Docker에서 hwdsl2/ipsec-vpn-server를 --network host 모드로 운영할 때, VPN 연결은 성공하지만 인터넷이나 LAN에 접근할 수 없는 문제를 겪었다. outBytes=0이 계속되는 상황이었다.
Table of contents
Open Table of contents
증상
- IKEv2 VPN 연결 자체는 성공 (클라이언트에 IP 할당됨)
- VPN 클라이언트에서 인터넷/LAN 접근 불가
ipsec status는 정상,ipsec whack --trafficstatus에서outBytes=0
# VPN 상태 확인
docker exec ipsec-vpn-server ipsec whack --trafficstatus
# 결과: outBytes=0 — 트래픽이 전달되지 않음
원인 분석
FORWARD 체인 추적
iptables 규칙을 하나씩 추적했다.
# FORWARD 체인 확인
iptables -L FORWARD -v -n
# 패킷 매칭은 되지만 최종 MASQUERADE까지 도달하지 않음
# POSTROUTING 확인
iptables -t nat -L POSTROUTING -v -n
# MASQUERADE 규칙은 존재하지만 카운터가 0
FORWARD 체인에서 패킷이 매칭은 되지만 어딘가에서 DROP되고 있었다.
핵심 원인: Docker의 nftables FORWARD 정책
Docker는 자체 네트워크 관리를 위해 nftables 기반 FORWARD 체인을 사용한다. --network host 모드에서 컨테이너의 iptables 규칙은 호스트와 양방향으로 공유되는데, Docker가 설정한 FORWARD 체인의 기본 정책이 drop이다.
# nftables 기반 iptables 확인
iptables-nft -L FORWARD -v -n
# policy DROP — Docker가 설정한 기본 정책
VPN 서버가 추가한 FORWARD ACCEPT 규칙은 iptables-legacy에 추가되지만, Docker는 iptables-nft를 사용한다. 두 테이블이 분리되어 있어서 VPN의 ACCEPT 규칙이 Docker의 DROP 정책을 우회하지 못한다.
해결
Docker의 DOCKER-USER 체인에 VPN 서브넷을 허용하는 규칙을 추가해야 한다. DOCKER-USER는 Docker가 사용자 정의 규칙을 위해 제공하는 체인으로, Docker 재시작 시에도 유지된다.
# VPN 서브넷 정의
L2TP_NET="192.168.42.0/24"
XAUTH_NET="192.168.43.0/24"
# DOCKER-USER 체인에 VPN 트래픽 허용
if iptables-nft -L DOCKER-USER -n >/dev/null 2>&1; then
iptables-nft -I DOCKER-USER 1 -s "$XAUTH_NET" -j ACCEPT
iptables-nft -I DOCKER-USER 2 -d "$XAUTH_NET" -j ACCEPT
iptables-nft -I DOCKER-USER 3 -s "$L2TP_NET" -j ACCEPT
iptables-nft -I DOCKER-USER 4 -d "$L2TP_NET" -j ACCEPT
fi
이 규칙을 VPN 서버의 커스텀 entrypoint 스크립트(run.sh)에 추가하여, 컨테이너 시작 시 자동으로 적용되도록 했다.
추가 MASQUERADE 규칙
외부 인터넷 접근을 위해 POSTROUTING에 MASQUERADE 규칙도 필요하다. LAN 접근은 NAT 없이 직접 라우팅한다.
# 외부 접근: MASQUERADE
iptables -t nat -A POSTROUTING -s "$XAUTH_NET" -o eth0 -j MASQUERADE
iptables -t nat -A POSTROUTING -s "$L2TP_NET" -o eth0 -j MASQUERADE
# LAN 접근: NAT 없이 직접 라우팅 (RETURN)
iptables -t nat -I POSTROUTING 1 -s "$XAUTH_NET" -d 10.0.0.0/24 -j RETURN
iptables -t nat -I POSTROUTING 2 -s "$L2TP_NET" -d 10.0.0.0/24 -j RETURN
검증
# VPN 연결 후 트래픽 확인
docker exec ipsec-vpn-server ipsec whack --trafficstatus
# outBytes > 0 확인
# 클라이언트에서 인터넷 접근
ping 8.8.8.8 # 외부 DNS
ping 10.0.0.1 # LAN 게이트웨이
핵심 정리
| 계층 | 문제 | 해결 |
|---|---|---|
| FORWARD | Docker nftables policy DROP | DOCKER-USER 체인에 VPN 서브넷 ACCEPT |
| POSTROUTING | MASQUERADE 미도달 | iptables NAT 규칙 추가 |
| LAN 접근 | 불필요한 NAT | RETURN 규칙으로 직접 라우팅 |
Docker host 모드에서 VPN을 운영할 때는 Docker의 nftables 방화벽과 VPN의 iptables 규칙이 다른 테이블에서 동작한다는 점을 반드시 인지해야 한다. DOCKER-USER 체인이 이 문제의 공식적인 해결 지점이다.
참고 자료
- Docker Packet Filtering and Firewalls — Docker 공식 iptables/nftables FORWARD 체인 문서
- hwdsl2/docker-ipsec-vpn-server — IPsec VPN 서버 Docker 이미지