WireGuard DNS 연결 실패 원인과 해결 방법 3가지
WireGuard 터널은 연결되었으나 DNS 이름 해석이 안 되거나 쿼리가 유출되는 문제를 해결합니다. 리졸버 응답 없음, 설정 덮어쓰기, 라우팅 오류 등 세 가지 주요 실패 모드를 진단하고 각 상황에 맞는 정확한 수정 방법을 안내합니다.
WireGuard 터널이 활성화되는 즉시 DNS가 작동하지 않는 이유
WireGuard를 통한 DNS는 세 가지 방식으로 실패하며, 각각 해결 방법이 다릅니다. 이름 해석이 전혀 되지 않거나, 이름은 해석되지만 쿼리가 터널 외부로 나가거나, 클라이언트의 리졸버 관리자가 인터페이스 시작 후 몇 초 만에 설정을 덮어쓰는 경우입니다. 터널 자체가 문제인 경우는 거의 없습니다. 문제는 클라이언트에게 어떤 리졸버를 사용할지 지시하는 한 줄의 설정과, 해당 리졸버로 향하는 패킷의 경로를 결정하는 라우팅입니다.
WireGuard는 IP 패킷을 전달할 뿐 DNS(도메인 이름 시스템, example.com와 같은 이름을 IP 주소로 변환하는 서비스)에 대해서는 알지 못합니다. 클라이언트 [Interface] 블록의 DNS = 줄은 WireGuard 설정이 아닙니다. 이 설정은 인터페이스를 활성화하는 셸 래퍼인 wg-quick이 읽으며, wg-quick은 터널이 활성화된 동안 클라이언트의 리졸버 설정을 편집하고 wg-quick down 시점에 이를 복구합니다. 따라서 아래의 모든 문제는 라우팅 문제이거나 wg-quick 문제이며, 암호화 문제는 아닙니다. 터널 자체가 아직 구축되지 않았다면 직접 호스팅하는 WireGuard VPN을 먼저 설정한 뒤 이 페이지로 돌아오십시오.
DNS 설정을 건드리기 전에 터널이 정상인지 확인하십시오.
sudo wg show
ping -c 3 10.8.0.1
ping -c 3 1.1.1.1wg show 명령을 실행하면 최근 latest handshake를 가진 피어가 표시되어야 하며, 양방향 핑이 모두 응답해야 합니다. 만약 ping 1.1.1.1에서 타임아웃이 발생한다면 이는 DNS 문제가 아니라 포워딩 또는 NAT(네트워크 주소 변환) 문제입니다. 이 경우 리졸버 설정을 아무리 변경해도 해결되지 않습니다. 핑은 응답하지만 실제 트래픽이 시작될 때 처리량이 급감한다면 이는 별개의 결함이며, 느린 WireGuard는 거의 항상 MTU 문제로 귀결됩니다. 이 페이지의 모든 예제는 10.8.0.0/24를 터널 서브넷으로, 10.8.0.1를 서버의 터널 주소로 사용합니다. 본인의 환경에 맞게 수정하십시오.
첫 번째 실패: 리졸버가 응답하지 않아 아무것도 해석되지 않음
증상은 명확합니다. ping 1.1.1.1은 정상 작동하며, curl https://example.com은 다음을 반환합니다.
curl: (6) Could not resolve host: example.com클라이언트에서 터널 리졸버로 직접 질의하십시오. dig은 Ubuntu 및 Debian의 dnsutils 패키지에 포함되어 있습니다.
dig +short @1.1.1.1 example.com
dig +short @10.8.0.1 example.com첫 번째 명령은 주소를 반환하며, 이는 패킷이 터널을 통해 인터넷에 도달함을 증명합니다. 두 번째 명령은 아무것도 반환하지 않고 ;; communication timed out; no servers could be reached을 출력합니다. 이것이 진단의 전부입니다. 클라이언트가 10.8.0.1을 가리키고 있으나, 10.8.0.1가 UDP 53번 포트에서 응답하지 않는 상태입니다.
이 현상은 두 가지 원인으로 발생합니다. 서버에서 리졸버가 실행 중이지 않거나, 서버 방화벽이 쿼리가 도착하기 전에 차단하는 경우입니다. 서버에서 두 가지 모두 확인하십시오.
sudo ss -ulnp | grep ':53'
sudo nft list ruleset정상적으로 실행되어 바인딩된 리졸버는 10.8.0.1:53 또는 0.0.0.0:53가 포함된 줄을 보여줍니다. Ubuntu에서 흔히 발생하는 의외의 상황은 127.0.0.53:53입니다. 이는 systemd-resolved 스텁 리스너로, 루프백 주소에 바인딩되어 외부 기기에서는 의도적으로 접근할 수 없습니다. VPN 클라이언트가 이 스텁 리졸버만 가진 서버를 가리키면 정확히 이 타임아웃이 발생합니다.
해결책은 터널 주소에서 수신 대기하는 리졸버를 구성하고, 피어(peer)가 해당 리졸버에 접근할 수 있도록 방화벽 규칙을 하나 추가하는 것입니다.
sudo apt update && sudo apt install -y unbound
printf 'server:\n interface: 10.8.0.1\n access-control: 10.8.0.0/24 allow\n' \
| sudo tee /etc/unbound/unbound.conf.d/wireguard.conf
sudo systemctl restart unbound
sudo ss -ulnp | grep '10.8.0.1:53'그런 다음 터널 트래픽에 대해서만 포트를 개방하십시오. nftables를 사용하는 경우, /etc/nftables.conf의 input 체인에 다음 두 줄을 추가하고 sudo systemctl reload nftables로 다시 로드하십시오.
udp dport 53 iifname "wg0" accept
tcp dport 53 iifname "wg0" acceptufw를 사용하는 경우, sudo ufw allow in on wg0 to any port 53로 동일한 작업을 수행할 수 있습니다. 53번 포트를 공용 인터넷에 절대 개방하지 마십시오. 개방된 재귀적 리졸버는 며칠 내로 스캐너에 탐지되어 서비스 거부 공격(DoS) 증폭에 악용되며, 서비스 제공업체는 귀하보다 먼저 해당 트래픽을 감지할 것입니다.
클라이언트에서 dig +short @10.8.0.1 example.com을 다시 실행하십시오. 출력에 주소가 나타난다면 리졸버 경로가 정상 작동하는 것이며, 이제 클라이언트가 해당 경로를 사용하도록 설정하기만 하면 됩니다. 클라이언트 [Interface] 블록에 해당 줄을 추가하고 sudo wg-quick down wg0 && sudo wg-quick up wg0로 인터페이스를 재시작하십시오.
[Interface]
PrivateKey = <client private key>
Address = 10.8.0.2/32
DNS = 10.8.0.1실패 사례 2: 스플릿 터널이 리졸버를 라우팅하지 않아 발생하는 DNS 유출
이 문제는 모든 것이 정상적으로 작동하는 것처럼 보이기 때문에 더 위험합니다. 도메인 이름은 해석되고 페이지는 로드되지만, DNS 쿼리는 신뢰할 수 없는 로컬 네트워크를 통해 평문으로 전송됩니다.
이 현상은 두 가지 설정에서 발생합니다. 첫 번째는 AllowedIPs = 0.0.0.0/0, ::/0을 사용하면서 DNS = 항목이 없는 클라이언트입니다. wg-quick는 자체 라우팅 테이블에 기본 경로를 설치하고 suppress_prefixlength 0 규칙을 추가하는데, 이는 프린터와 같은 로컬 장치에 계속 접근할 수 있도록 더 구체적인 로컬 경로를 의도적으로 유지하기 위함입니다. 이때 클라이언트가 DHCP로 학습한 리졸버(일반적으로 192.168.1.1의 라우터)가 해당 로컬 경로 중 하나와 일치하게 됩니다. 결과적으로 데이터 트래픽은 터널을 통과하지만, 로컬 네트워크는 사용자가 조회하는 모든 도메인 이름 목록을 그대로 수신하게 됩니다.
두 번째는 DNS = 9.9.9.9를 사용한 스플릿 터널 AllowedIPs = 10.8.0.0/24입니다. 9.9.9.9이 AllowedIPs 내부에 포함되어 있지 않기 때문에, 클라이언트는 터널을 통해 해당 리졸버로 가는 경로를 알지 못합니다. 따라서 첫 번째 사례와 마찬가지로 쿼리가 로컬 링크를 통해 외부로 유출됩니다.
어떤 리졸버가 실제로 응답하는지 확인하십시오. whoami.akamai.net는 쿼리를 보낸 재귀적 리졸버의 IP 주소를 응답으로 돌려주는 공개 테스트 도메인입니다. 이 응답을 서버의 공인 IP 주소와 비교할 수 있습니다.
resolvectl status
dig +short whoami.akamai.net
sudo tcpdump -ni any -c 10 port 53resolvectl status은 링크별로 하나의 블록을 출력합니다. 이더넷이나 무선 링크 블록에 여전히 Current DNS Server: 192.168.1.1가 표시되는데 wg0 블록에는 아무것도 없다면, 그것이 바로 유출입니다. dig +short whoami.akamai.net이 서버의 주소가 아닌 가정용 광대역 주소를 반환한다면 원격지에서도 유출이 확인된 것입니다. tcpdump 라인은 논란을 종식하는 증거입니다. 정상적인 상태라면 모든 53번 포트 패킷이 wg0을 통과해야 하며, 유출이 발생하면 wlan0나 enp3s0을 통과하게 됩니다.
이 문제를 해결하려면 두 가지 조치가 모두 필요합니다. DNS을 터널 내부의 주소로 설정하고, 해당 주소가 반드시 AllowedIPs 범위 내에 있는지 확인하십시오.
[Interface]
Address = 10.8.0.2/32
DNS = 10.8.0.1
[Peer]
PublicKey = <server public key>
Endpoint = vpn.example.com:51820
AllowedIPs = 10.8.0.0/24, 10.20.0.0/1610.8.0.1은 10.8.0.0/24 내부에 위치하므로 쿼리가 암호화되어 서버로 전송됩니다. 스플릿 터널 환경에서 굳이 공개 리졸버를 사용해야 한다면, 호스트 경로로 추가하십시오: AllowedIPs = 10.8.0.0/24, 9.9.9.9/32. 이렇게 하면 패킷이 터널링되지만, 로컬 네트워크는 이전 세션 기록을 통해 사용자가 해당 제공업체를 선택했음을 여전히 알 수 있습니다. 직접 운영하는 리졸버를 사용하면 이러한 문제를 원천적으로 피할 수 있습니다.
Resolver 할당은 직접 구성한 WireGuard와 조정형 메시 네트워크 사이에서 나타나는 차이 중 하나이며, 이는 WireGuard와 Tailscale 비교에서 다루는 절충점의 일부다. 직접 호스팅하는 Headscale 제어 서버를 사용하면 키 자료를 제3자에게 넘기지 않고도 이러한 조정을 구현할 수 있다. 마지막 표현이 걱정된다면, Tailscale은 트래픽을 암호화하는 키를 보유하지 않는다는 점에 유의해야 한다. 더 중요한 질문은 조정 서버가 침해되거나 ID 계정이 탈취되었을 때 공격자가 네트워크에 어떤 권한을 추가할 수 있는가다.
세 번째 실패: Linux 클라이언트에서 resolvconf와 systemd-resolved의 충돌
macOS, Windows, iOS, Android 클라이언트는 공식 앱을 통해 DNS =을 적용하므로 별다른 문제가 발생하지 않습니다. Linux의 경우, 여러 리졸버 관리자 중 어떤 것을 사용하는지 추측해야 하는 셸 스크립트를 통해 설정이 적용됩니다.
첫 번째 실패는 명확하게 드러납니다. sudo wg-quick up wg0이 다음 메시지와 함께 중단됩니다.
resolvconf: command not foundwg-quick은 resolvconf를 호출하는데, 해당 바이너리가 설치되어 있지 않기 때문입니다. systemd-resolved와 통신하는 구현체를 설치한 다음 인터페이스를 다시 활성화하십시오.
sudo apt install -y openresolv
sudo systemctl restart systemd-resolved
sudo wg-quick down wg0 && sudo wg-quick up wg0
resolvectl status wg0두 번째 실패는 조용히 발생하며, 해결하는 데 많은 시간이 소요됩니다. 인터페이스가 활성화되고 resolvectl status wg0이 DNS Servers: 10.8.0.1을 올바르게 표시하더라도, 조회는 여전히 이전 리졸버로 전달됩니다. systemd-resolved는 링크별로 별도의 리졸버 목록을 유지하며 쿼리마다 링크를 선택합니다. 특정 링크가 이름에 대한 기본 경로(default route)로 지정되지 않으면, 무선 링크가 검색 도메인을 가지고 있고 사용자의 링크는 그렇지 않기 때문에 무선 링크의 리졸버를 계속 사용하게 됩니다.
리졸버를 설정하고 동시에 기본 경로를 지정하십시오. %i는 인터페이스 이름으로 확장되므로, 이 블록은 어떤 인터페이스에서든 수정 없이 작동합니다.
[Interface]
Address = 10.8.0.2/32
PostUp = resolvectl dns %i 10.8.0.1; resolvectl domain %i ~.
PostDown = resolvectl revert %iPostUp를 이런 방식으로 사용할 때는 DNS = 라인을 삭제하십시오. 그렇지 않으면 두 메커니즘이 리졸버 상태를 기록하게 되며, 그중 하나만 나중에 정리 작업을 수행하기 때문입니다. ~. 인자가 중요한 부분입니다. 이 인자는 wg0을 모든 이름에 대한 라우팅 도메인으로 표시하므로, systemd-resolved가 쿼리마다 링크를 선택하는 대신 모든 쿼리를 해당 도메인으로 보냅니다. 이를 확인하십시오.
resolvectl status wg0정상적인 출력에는 DNS Servers: 10.8.0.1과 Default Route: yes이 포함되어야 합니다. 만약 Default Route가 no을 가리킨다면, resolvectl domain 부분이 실행되지 않은 것이며 다시 링크 선택 단계로 돌아간 상태입니다.
한 가지 사례를 더 언급할 필요가 있습니다. /etc/resolv.conf가 /run/systemd/resolve/stub-resolv.conf에 대한 심볼릭 링크가 아닌 실제 파일이라면, NetworkManager나 컨테이너 런타임 등 다른 무언가가 해당 파일을 소유하고 있는 것입니다. 다른 문제를 디버깅하기 전에 ls -l /etc/resolv.conf를 실행하십시오. 네트워크가 변경될 때마다 해당 파일을 덮어쓰는 도구가 있다면, 가장 곤란한 순간에 사용자의 작업을 무효화할 것이기 때문입니다.
업그레이드: 터널을 통한 자체 필터링 리졸버 구성
쿼리가 터널을 통해 안정적으로 전송되면, 원격지의 리졸버가 제어 지점이 됩니다. 해당 위치에서 AdGuard Home을 실행하면 클라이언트 소프트웨어나 기기별 설정 없이도 연결된 모든 기기에 차단 목록 필터링과 쿼리 로그 기능을 제공할 수 있습니다. 2026년 7월 기준으로 확인된 공식 설치 스크립트는 한 줄로 실행됩니다.
curl -s -S -L https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/master/scripts/install.sh | sh -s -- -v설정 마법사는 최초 실행 시 3000번 포트에서 대기합니다. 해당 포트를 외부에 공개하는 대신 터널을 통해 http://10.8.0.1:3000로 접속하십시오. 마법사에서 DNS 대기 주소와 관리자 대기 주소를 모두 10.8.0.1으로 설정합니다. 만약 첫 번째 실패 사례에서 사용한 unbound이 여전히 같은 주소를 점유하고 있다면, sudo systemctl disable --now unbound 명령으로 먼저 중지하십시오. 두 프로세스가 하나의 주소에서 UDP 53번 포트를 동시에 바인딩할 수 없으며, 두 번째 프로세스는 listen udp 10.8.0.1:53: bind: address already in use 오류와 함께 종료되기 때문입니다.
클라이언트 설정이 이미 DNS = 10.8.0.1으로 되어 있다면 별도의 변경은 필요하지 않습니다. 이제 쿼리 로그에는 모든 피어의 조회 기록이 표시됩니다. 이는 단순히 이득만 있는 것이 아니라 개인정보 보호에 관한 실질적인 결정입니다. 즉, 인터넷 서비스 제공업체에 대한 신뢰를 본인에게로 옮겨오는 것이며, 해당 서버의 보안 패치를 직접 관리해야 할 책임도 따릅니다. 인터넷에 노출된 서버는 기본적인 보안 조치가 선행되어야 하며, 새 VPS에서의 초기 10분 가이드에서 이를 다룹니다.
FAQ
WireGuard 터널은 연결되는데 도메인 이름이 해석되지 않는 이유는 무엇입니까?
터널은 패킷을 전달할 뿐 이름 해석을 처리하지 않습니다. 터널은 정상인데 조회가 실패한다면 지정한 리졸버가 응답하지 않는 것입니다. 클라이언트에서 dig +short @10.8.0.1 example.com 명령으로 테스트하십시오. communication timed out 응답이 돌아온다면 해당 터널 주소에서 리졸버가 대기 중이지 않은 것입니다. 이는 보통 systemd-resolved 스텁이 127.0.0.53에만 바인딩되어 있거나, 서버 방화벽이 wg0로 들어오는 UDP 53번 포트를 차단하기 때문입니다. 먼저 리스너를 수정하고, wg0에 대해서만 포트를 개방하십시오.
WireGuard를 통해 DNS가 유출되는지 어떻게 확인합니까?
클라이언트에서 sudo tcpdump -ni any -c 10 port 53을 실행하고 브라우징하는 동안 인터페이스 열을 확인하십시오. 모든 패킷은 wg0을 통해 나가야 합니다. 무선이나 이더넷 인터페이스에 패킷이 나타난다면 쿼리가 평문으로 유출되는 것입니다. dig +short whoami.akamai.net을 사용하면 교차 검증이 가능합니다. 이 도구는 쿼리를 보낸 재귀적 리졸버의 공인 IP 주소를 반환하므로, 서버 주소가 아닌 다른 주소가 응답한다면 유출이 발생한 것입니다.
스플릿 터널을 사용할 때 DNS = 줄이 필요한가요?
네, 필요합니다. 리졸버 주소 또한 AllowedIPs 내부에 포함되어야 합니다. 그렇지 않으면 클라이언트에 해당 주소로 가는 경로가 없기 때문입니다. AllowedIPs = 10.8.0.0/24을 사용하면 10.8.0.1에 위치한 리졸버가 포함되어 쿼리가 암호화됩니다. 9.9.9.9과 같은 공용 리졸버는 포함되지 않으므로, DNS 줄이 올바르게 설정된 것처럼 보여도 쿼리는 로컬 링크를 통해 외부로 나갑니다.
resolvectl은 올바른 서버를 보여주는데 왜 조회는 다른 곳으로 가나요?
systemd-resolved는 링크마다 리졸버 목록을 유지하며 쿼리마다 링크를 선택합니다. 따라서 wg0에 올바른 항목이 있어도 다른 링크가 이름 해석의 기본 경로를 점유하고 있다면 무시됩니다. 클라이언트 [Interface] 블록에 PostUp = resolvectl dns %i 10.8.0.1; resolvectl domain %i ~.을 추가하고 DNS = 줄을 제거하십시오. 그러면 resolvectl status wg0에서 Default Route: yes이 보고되어야 합니다.
여러 클라이언트가 고장 났을 때 무엇부터 수정해야 합니까?
Linux 클라이언트 하나를 먼저 수정하십시오. 작동 원리를 확인할 수 있는 유일한 플랫폼이기 때문입니다. resolvectl status과 tcpdump를 통해 어떤 리졸버가 응답했는지, 어떤 인터페이스가 패킷을 전달했는지 알 수 있습니다. 모바일 및 데스크톱 앱은 내부 동작을 보여주지 않은 채 동일한 DNS 및 AllowedIPs 값을 적용합니다. 따라서 Linux 클라이언트에서 설정을 검증한 뒤 해당 값을 복사하는 것이 좋습니다.