- OpenVPN을 WireGuard로 바꾸는 기본 절차는 단순하지만, 실제 운영에서는 NAT 우회와 IPv6 공개 주소 할당 같은 추가 구성이 필요해짐
- 기본 VPN은 서버와 클라이언트의 키쌍,
10.100.0.0/16 같은 VPN 대역, wg0의 iptables NAT 규칙, 클라이언트별 AllowedIPs로 구성됨
- WireGuard는 UPnP 서버를 포함하지 않는 단순한 커널 모듈이므로, BitTorrent처럼 NAT에 민감한 애플리케이션은 서버에
miniupnpd를 붙여 포트 포워딩을 처리해야 함
- IPv6에서는 호스팅 제공자가 준
/48 또는 서버의 /56 범위 안에서 VPN 클라이언트에 공개 라우팅 가능한 IPv6 주소를 직접 줄 수 있음
- 클라이언트가
2001:aaaa:bbbb:1000:cafe::2/128 같은 공개 IPv6를 받으면 인터넷에서 직접 포트에 접근할 수 있어, UPnP 기반 주소 감지나 포트 포워딩이 필요 없어짐
WireGuard 기본 VPN 구성
- 목표는 호스팅 제공자 서버를 VPN 서버로 쓰고, 기존 OpenVPN 구성을 WireGuard로 대체하는 것임
- 기본 구성 흐름은 서버와 클라이언트의 키쌍을 만든 뒤 VPN 대역을 정하는 방식임
- 서버용 개인키/공개키 키쌍 생성
- 각 클라이언트용 키쌍 생성
- VPN 네트워크 선택
- 예시 VPN 대역:
10.100.0.0/16
- 서버 IP:
10.100.0.1
- 클라이언트 IP:
10.100.0.2, 10.100.0.3 등
- 서버 설정은
wg0 인터페이스에 주소, 개인키, 리슨 포트, NAT/포워딩용 iptables 규칙을 넣음
[Interface]
Address = 10.100.0.1/24
PrivateKey = (redacted)
ListenPort = 51820
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o ens0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o ens0 -j MASQUERADE
[Peer]
PublicKey = (redacted)
AllowedIPs = 10.100.0.2/32
[Peer]
PublicKey = (redacted)
AllowedIPs = 10.100.0.3/32
- 서버는
wg up /etc/wireguard/wg0.conf로 시작함
- 클라이언트 설정에는 서버 공개키, 엔드포인트, 전체 트래픽 라우팅용
AllowedIPs = 0.0.0.0/0, ::/0이 들어감
[Interface]
PrivateKey = (redacted)
[Peer]
PublicKey = (redacted)
Endpoint = my-server.example.com:51820
AllowedIPs = 0.0.0.0/0, ::/0
- 선택적으로 VPN용 네트워크 네임스페이스를 만들면, 기본 인터넷 연결은 직접 유지하면서 특정 애플리케이션만 VPN 네임스페이스 안에서 실행할 수 있음
NAT와 UPnP가 필요한 이유
- BitTorrent 클라이언트 같은 일부 애플리케이션은 NAT 뒤에서 동작이 불안정할 수 있음
- WireGuard 여부와 관계없이 VPN은 NAT처럼 동작하며, UPnP는 이 문제를 우회하는 흔한 방법임
- UPnP가 해결하는 문제는 크게 두 가지임
- 컴퓨터가 외부 시스템에서 보이는 공인 주소를 모를 수 있음
- VPN 뒤에서는 공인 주소가 ISP가 할당한 주소가 아니라 VPN 서버 주소임
- VPN 소프트웨어는 그 주소를 알지만, 시스템의 다른 부분은 일반적으로 알지 못함
- P2P 소프트웨어가 이 주소를 모르면 다른 피어에게 전달할 수 없음
- 포트를 열어도 연결은 클라이언트가 아니라 VPN 서버 IP의 해당 포트로 들어옴
- 예시는 TCP
8043
- 실제로 클라이언트에 도달하려면 VPN 서버의 포트 포워딩 규칙이 필요함
- UPnP는 이 포트 포워딩을 설정하는 수단이 됨
- 단순 WireGuard 구성에서는
miniupnpc의 external-ip 도구가 UPnP 장치를 찾지 못함
$ external-ip
No IGD UPnP Device found on the network !
WireGuard에 miniupnpd 붙이기
- WireGuard는 단순한 커널 모듈이며 UPnP 서버를 포함하지 않음
- 서버에
miniupnpd를 설치하고, WireGuard 설정의 PostUp/PostDown에서 서비스를 시작·중지하도록 구성함
PostUp = systemctl start miniupnpd
PostDown = systemctl stop miniupnpd
- 핵심 설정 파일은
/etc/miniupnpd/miniupnpd.conf임
- 필요한 주요 설정은 다음과 같음
ext_ifname=ens0
- 서버의 인터넷-facing 인터페이스임
- 실제 환경에서는
ens0이 아닐 수 있음
listening_ip=wg0
- 서버의 WireGuard 네트워크 인터페이스임
uuid=06df7440-dbac-404c-9c07-0b0dbfca609e
uuidgen으로 생성할 수 있음
- 모든 동작이 private, non-routable 네트워크 안에서 일어나므로 예시 UUID를 써도 문제없다고 봄
allow 1024-65535 10.100.0.0/16 1024-65535
- WireGuard 네트워크
10.100.0.0/16에 대해 허용 범위를 지정함
UPnP 동작 확인
external-ip는 서버 IP를 반환하고, upnpc는 서버의 TCP 8043을 내부 10.100.0.2:8043으로 리다이렉트함
$ external-ip
(redacted, but it correctly returned my server IP)
$ upnpc -n 10.100.0.2 8043 8043 tcp 300
external (redacted:server-ip):8043 TCP is redirected to internal 10.100.0.2:8043 (duration=300)
$ socat TCP-LISTEN:8043 STDIO
- 다른 머신에서 서버 IP의 TCP
8043으로 접속하면 두 socat 인스턴스가 VPN을 거쳐 통신할 수 있음
$ socat TCP:(redacted:server-ip):8043 STDIO
IPv6에서는 NAT 없이 구성 가능
- NAT 문제를 UPnP로 우회하는 것보다 더 나은 방식은 NAT 자체를 없애는 것이며, IPv6에서는 이 구성이 가능함
- WireGuard 기반 VPN의 IPv6 튜토리얼은 IPv4 구성을 그대로 옮기는 경우가 있음
- IPv4의
10.100.0.0/16 같은 private, non-routable 네트워크를 IPv6의 fd00:dead:beef::/48 같은 대역으로 바꿈
- 서버와 클라이언트에 이 네트워크 안의 주소를 할당함
ip6tables masquerade 액션을 추가함
- 여기서는 그 대신 공개 라우팅 가능한 IPv6를 클라이언트에 직접 할당함
- 예시 환경에서는 호스팅 제공자가 계정에
/48 네트워크 2001:aaaa:bbbb::/48를 할당했고, 서버에는 /56인 2001:aaaa:bbbb:1000::1/56이 있음
- VPN 네트워크에는
/80 서브네트워크 2001:aaaa:bbbb:1000:cafe::/80을 할당함
[Interface]
Address = 2001:aaaa:bbbb:1000:cafe::1/80
[Peer]
AllowedIPs = 2001:aaaa:bbbb:1000:cafe::2/128
[Peer]
AllowedIPs = 2001:aaaa:bbbb:1000:cafe::3/128
- 클라이언트 쪽에는 해당 공개 IPv6 주소를 직접 지정함
[Interface]
Address = 2001:aaaa:bbbb:1000:cafe::2/128
- 서버에서
ip -6 route get 2001:aaaa:bbbb:1000:cafe::2가 WireGuard 인터페이스 wg0를 반환해야 함
- 그렇지 않으면 라우팅에서
wg0에 더 낮은 metric을 줘야 함
- 클라이언트는 IPv6에서 직접 포트를 리슨할 수 있음
$ socat TCP6-LISTEN:8043
- 인터넷의 다른 위치에서 클라이언트 IPv6 주소로 직접 접속 가능함
$ socat TCP6:[2001:aaaa:bbbb:1000:cafe::2]:8043
- 기본 라우트 장치의 IP 주소가
2001:aaaa:bbbb:1000:cafe::2가 되므로, IPv4에서 private 주소였던 VPN 인터페이스 IP가 IPv6에서는 공개 IP가 됨
- 이 구성에서는 UPnP로 공개 IPv6를 감지하거나 포트 포워딩을 설정할 필요가 없음