집 서버 HTTPS를 내부 전용으로 전환하기: AdGuard DNS, WireGuard, 공개 DNS 레코드 정리
· homelab, docker, adguard, wireguard, dns, cloudflare
배경
- 서버 구성: 호스트(Ubuntu, LAN IP
<서버 LAN IP>)에 Docker로 NPM(80/81/443), AdGuard Home, Nextcloud(8081), cloudflared, cloudflare‑ddns가 동작하고 있었다. - HA는 같은 호스트의 KVM VM(
<HA VM IP>:8123)이며, 호스트에는 HA가 없었다. - 외부 접속은 두 경로가 섞여 있었다.
ha.hyuklee.net은 cloudflared 터널로 HA에 연결돼 있었고, 일부 서비스는 공개 DNS 레코드가 집 공인 IP를 가리키고 있었다. - 공유기(ipTIME AX5400BCM‑6E)의 80/443 포트포워딩은 열지 않기로 했다. 그래서 Let’s Encrypt는 DNS 챌린지 방식을 사용했다. (인증서 발급 부분은 별도 메모로 다룬다.)
- 목표는 집 Wi‑Fi, WireGuard, Tailscale 어디서든 같은 주소로 접속하고, 외부에서는 VPN 없이 열리지 않게 하는 것이었다.
- 막혔던 점: AdGuard를 설정했더니 인터넷이 느리거나 timeout이 발생해 사용을 중지한 상태였다.
결론부터
- 이름 해석: AdGuard Home의 DNS 리라이트로
hyuklee.net을<서버 LAN IP>로 보낸다. NPM이 이 IP로 들어온 요청을 각 서비스로 넘긴다. - 기기별 DNS: 공유기 DHCP의 DNS를
<서버 LAN IP>(기본)와168.126.63.1(보조)로 설정한다. WireGuard 클라이언트 설정의[Interface]에DNS = <서버 LAN IP>, 168.126.63.1을 넣는다. - 외부 공개 제거: Cloudflare 공개 A 레코드(집 IP 노출)를 삭제하고, HA 터널의 공개 호스트네임(경로)을 삭제했다. 이후 공개 DNS 조회 결과는
NXDOMAIN이다. - 외부 접속: WireGuard로만 접속한다.
버린 선택지와 이유
- Tailscale Split DNS: 처음에는 필수라고 생각했지만, WireGuard만으로 접속이 되어서 필요하지 않았다. Tailscale은
192.168.0.0/24서브넷 라우트만 광고한 상태로 두었다. - certbot을 Cloudflare Workers에 두기: Workers는 certbot 같은 프로세스를 돌릴 수 없어서 불가능하다고 판단했다. NPM이 DNS 챌린지로 직접 갱신하는 구성을 유지했다.
- cloudflare‑ddns 유지: 포트포워딩을 쓰지 않으니 DDNS로 공인 IP를 갱신할 이유가 없었다. 컨테이너를 내리고 폴더도 삭제했다.
- 포트포워딩으로 외부 공개: 처음부터 제외한 방식이다.
1. 현재 상태 확인
NPM 프록시 호스트를 DB에서 확인했다. 확인 시점에 ha 항목이 두 개 있었다.
| id | 도메인 | 대상 | 상태 |
|---|---|---|---|
| 2 | ha | <서버 LAN IP>:8123 |
활성, 대상 HA 없음 |
| 9 | ha | <HA VM IP>:8123 |
비활성 |
- id 2는 호스트에 HA가 없는데도 활성화돼 있었다. 나중에 UI에서 삭제했고, DB에는
is_deleted=1로 남았다. UI에 안 보이는 것은 이 soft delete 때문이다. DB가 깨진 것은 아니었다. nc,ai,files등 나머지 항목은 대부분 비활성이었다.
2. AdGuard Home 복구
증상: AdGuard 대시보드에 차단 건수는 뜨지만, 실제 인터넷이 느리거나 timeout이 발생한다.
원인 확인
$ docker inspect adguardhome --format '{{json .NetworkSettings.Networks}}'
{}
- 컨테이너에 네트워크가 연결돼 있지 않았다. 포트 매핑도
ports={}였다. - 로그에는 업스트림 DNS(DoH)에 연결하지 못하는
network is unreachable오류가 반복 기록돼 있었다. - 53번 포트는 호스트의 libvirt dnsmasq가
127.0.0.1:53,192.168.122.1:53에서 사용 중이었다. 그래서0.0.0.0:53으로 띄우면 충돌한다.
조치: compose의 포트를 서버 LAN IP에만 바인딩하고 재생성했다.
ports:
- "<서버 LAN IP>:53:53/tcp"
- "<서버 LAN IP>:53:53/udp"
docker compose up -d --force-recreate
- 결과:
dig @<서버 LAN IP> google.com이 응답했다.doubleclick.net은0.0.0.0으로 차단됐다. - 웹 UI는
:8080에 열린다.
3. AdGuard 리라이트
- Filters → DNS rewrites에
hyuklee.net→<서버 LAN IP>를 추가했다. - 확인:
dig @<서버 LAN IP> nc.hyuklee.net이<서버 LAN IP>를 응답했다. 쿼리 로그에도재작성됨으로 기록됐다. - 처음에는 와일드카드(
*.hyuklee.net)가 필요하다고 생각했지만, 실제로는hyuklee.net한 줄로nc가 리라이트됐다. 서브도메인 매칭 규칙은 이 테스트 외에 검증하지 않았다.
4. 공개 DNS 레코드 정리
Cloudflare 목록을 조회하면서 두 종류를 구분했다.
- DNS 전용(회색 구름):
nc,rss,whisper가 집 공인 IP(<공인 IP>)를 직접 가리켰다. 외부에서 공인 IP로 바로 닿는 상태였다. - 프록시(주황 구름):
ai,files,adguard,dashboard,ftp,www,*등은 Cloudflare IP로 응답했다. 집 IP는 숨겨져 있지만 레코드 내용은 집 IP였다.
정리 내용
- A 레코드 삭제:
adguard,ai,dashboard,ftp,www,*,ejincare,nc,rss,whisper ejincareCNAME(→ iPTIME DDNS 이름)도 삭제했다.cockpitCNAME(→ 같은 DDNS 이름) 처리: 호스트에서 Cockpit(9090)이 꺼져 있었다. 삭제 여부는 대화에서 최종 확인하지 못했다. (미확인)- 유지: CAA 레코드(Cloudflare가 자동 생성), Google Search Console용 TXT
cloudflare‑ddns 중단: * 와일드카드를 프록시 상태로 집 IP에 갱신하던 컨테이너였다. docker compose down으로 내렸고, 폴더도 삭제했다.
5. HA 터널 경로 삭제
- Cloudflare 대시보드 → 보호 및 연결 → 네트워크 → 터널 → 경로에서
ha.hyuklee.net경로를 삭제했다. - 경로를 지우니 DNS 레코드도 함께 자동 삭제됐다.
- 확인: 공개 DNS(1.1.1.1, 8.8.8.8, 통신사 DNS)에서
ha.hyuklee.net조회 결과는NXDOMAIN이었다. - cloudflared 컨테이너 자체는 변경하지 않았다. 다른 경로 사용 여부는 미확인이다.
6. 공유기 DHCP DNS와 WireGuard
공유기: DHCP DNS를 <서버 LAN IP>(기본)와 168.126.63.1(보조)로 설정했다. 원래는 자동으로 168.126.63.1~2가 내려가고 있었다. 원격 관리 포트(WAN)는 꺼져 있는 것을 확인했다.
WireGuard 클라이언트 설정
[Interface]
PrivateKey = <비공개 키>
Address = 10.0.172.<n>/24
DNS = <서버 LAN IP>, 168.126.63.1
[Peer]
...
AllowedIPs = 0.0.0.0/0
Endpoint = <ipTIME DDNS>:<포트>
Address와 Peer 쪽의 주소는 바꾸지 않았다. 피어 주소를 LAN 대역으로 바꾸는 것은 틀린 방향이었다.- 처음에는 다른 설정 파일을 수정했다. 폰에서 쓰는 프로파일을 찾는 데 시간이 걸렸다.
- 수정 후 AdGuard 로그에 VPN 클라이언트 주소(
10.0.172.x)는 없었고, 공유기 주소(192.168.0.1)로 찍힌 질의가 나타났다. ipTIME이 WireGuard 트래픽을 공유기 주소로 바꿔 LAN에 전달하는 것으로 보인다. - 결과: 폰 WireGuard 연결 상태에서
https://nc.hyuklee.net이 열렸다.
7. 데스크탑에서 Cloudflare 오류
- 데스크탑에서
https://ha.hyuklee.net을 열었더니 Cloudflare **Error 1016 (Origin DNS error)**가 표시됐다. nslookup의Server:줄에dns.google(8.8.8.8)이 나왔다. 이더넷 DNS가 수동으로 8.8.8.8로 설정돼 있었다.- 그래서 AdGuard를 거치지 않았고, 공개 DNS 응답으로 Cloudflare 프록시 IP를 받았다.
- 조치: 이더넷 DNS를 자동으로 바꿨다. DHCP로
<서버 LAN IP>를 받은 뒤 HA가 열렸다. - 처음에는 DNS 캐시 때문이라고 추정했다. 캐시 가능성은 확인하지 못했고, 최종 원인은 수동 DNS 설정이었다.
8. 아이패드: AdGuard VPN 앱
- 아이패드에서
nc.hyuklee.net과 HA 앱이 모두 열리지 않았다. 집 AdGuard 로그에도 아이패드(<아이패드 IP>) 질의가 없었다. - 원인: 유료 AdGuard 앱의 요청 시 연결(On‑demand) 이 켜져 있었다. VPN이 켜지면 iOS가 DNS 질의를 그 앱의 터널로 보내서 와이파이의 DNS 설정이 무시된다.
- 조치: 앱을 끄자 사파리와 HA 앱이 열렸다.
- 앱 설정의 사용자 지정 DNS 옵션은 찾지 못했다. (미확인)
- 집에서는 앱을 끈 상태로 쓰기로 정리했다.
9. 접속 확인 결과
| 경로 | 결과 |
|---|---|
| 폰, WireGuard 연결 | nc.hyuklee.net 열림 |
| 아이패드, 집 Wi‑Fi(앱 끔) | 사파리, HA 앱 열림 |
| 데스크탑, 이더넷(DNS 자동) | ha.hyuklee.net 열림 (수동 DNS 해제 후) |
| Fold7, 외부망(VPN 없음) | 접속 안 됨 (의도한 동작) |
| Fold7, WireGuard | 접속됨 |
| Fold7, 내부망 | 접속됨 |
- 외부 공개 DNS에는
nc,ha레코드가 남아 있지 않았다. - 프록시 호스트 설정:
ha(id 9)는<HA VM IP>:8123으로 WebSocket 허용.nc(id 4)는<서버 LAN IP>:8081. - HA 앱 URL: 내부/외부 모두
https://ha.hyuklee.net으로 설정했다. 외부에서는 WireGuard가 연결돼 있어야 열린다.
헷갈렸던 점들
-
AdGuard가 인터넷을 느리게 만듦
- 증상: 차단 대시보드는 뜨는데 timeout이 발생한다.
- 원인: 컨테이너에 네트워크가 연결되지 않았고, 53번 포트는 libvirt dnsmasq와 충돌했다.
- 해결: 서버 LAN IP에만 53번을 바인딩하고
--force-recreate로 재생성했다.
-
아이패드가 AdGuard에 질의하지 않음
- 증상: 집 Wi‑Fi인데 AdGuard 로그에 기록이 없었다.
- 원인: 앱의 VPN(요청 시 연결)이 DNS를 가로챘다.
- 해결: 앱을 끄자 정상 동작했다.
-
데스크탑 Cloudflare 1016 오류
- 증상: 집 내부에서 HA가 Cloudflare 오류 페이지로 뜬다.
- 원인: 이더넷 DNS가 수동
8.8.8.8이었다. - 해결: 자동으로 바꾸자 AdGuard 경로로 들어갔다.
-
WireGuard 설정을 잘못된 파일에서 수정
- 증상: 폰에서
nc.hyuklee.net이 공인 IP 경로로 가서 공유기 페이지가 떴다. - 원인: 폰이 쓰는 프로파일이 아닌 다른 설정 파일을 수정했다.
- 해결: 실제 프로파일의
DNS줄을 수정했다.
- 증상: 폰에서
-
Tailscale이 필수라고 생각함
- 증상: 설정을 준비하다 보니 WireGuard와 Tailscale 중 무엇이 필요한지 혼동됐다.
- 원인: 두 경로가 DNS를 쓰는 방식이 같아서 헷갈렸다.
- 결론: WireGuard에 DNS를 넣는 것만으로 충분했다. Tailscale Split DNS는 선택 사항이다.
-
공유기 페이지가 공인 IP에서 열림
- 증상: 외부에서
nc주소로 접속했을 때 공유기 관리 페이지가 떴다. - 원인:
nc공개 레코드가 집 공인 IP를 가리키고 있었다. 포트포워딩 때문은 아니었다. - 해결: 공개 레코드를 삭제했다. 원격 관리 포트가 꺼져 있는 것도 확인했다.
- 증상: 외부에서
-
HA 설정 이름과 실제 항목이 달랐음
- 증상: 처음에는
ha가 HTTP 챌린지 인증서를 쓰는 것으로 알았다. - 원인: DB를 보니 DNS 챌린지 인증서를 쓰고 있었다. 프록시 항목도 두 개였다.
- 해결: DB를 직접 확인한 뒤 정리했다.
- 증상: 처음에는
정리
- 집 안과 WireGuard에서 같은 주소를 쓰려면 DNS를 AdGuard(
<서버 LAN IP>)로 맞춘다. 공유기 DHCP, WireGuardDNS줄, 기기의 DNS 설정을 모두 자동 또는 AdGuard로 둔다. - 외부 공개는 공개 DNS 레코드(집 IP를 가리키는 것)와 Cloudflare 터널 공개 경로를 삭제해서 끊는다. 공개 DNS 조회로 확인한다.
- 기기 DNS를 수동으로
8.8.8.8등으로 지정하면 AdGuard를 우회해 Cloudflare 오류가 난다. 자동으로 두는 것을 기본값으로 한다. - 아이패드처럼 VPN 앱이 DNS를 가로채는 경우, 집에서는 앱을 끈다.
- 미확인 항목:
cockpitCNAME 삭제 여부, cloudflared 터널의 다른 사용처, HAconfiguration.yaml의external_url설정, AdGuard 리라이트의 서브도메인 매칭 규칙.