DNS 서버 · 6 min read · Oct 02, 2025
Docker를 사용하여 Debian 10에서 동적 DNS 서버 배포하는 방법

동적 DNS는 도메인 이름을 동적(임시, 자주 변경되는) IP 주소에 매핑하는 네트워크 서비스입니다. 이는 정적 IP 주소가 없는 컴퓨터에 접근하는 데 사용되며, SOHO(소규모 사무실/홈 오피스) 네트워크와 같은 환경에서 자주 사용되며, NAT 방화벽 뒤에 있는 시스템에 접근하기 위해 포트 포워딩과 함께 사용됩니다. 이 문서에서는 Debian 10 시스템의 Docker 컨테이너에서 동적 DNS 서버를 완전히 설정하는 방법을 안내합니다. 여기에는 필요한 DNS 레코드 설정, 관리 API를 Nginx HTTPS 리버스 프록시 뒤에 배치하는 것, 클라이언트 측 DNS 레코드 업데이트 자동화가 포함됩니다.
요구 사항
- 단일 Debian 10 서버, 선택적으로 IPv6 연결 가능. (192.0.2.2 및 2001:0db8::0db9는 서버의 IPv4 및 IPv6에 대한 자리 표시자로 사용됩니다.)
- 루트 사용자 또는 sudo 권한이 있는 사용자에 대한 접근.
- 호스트에서 tcp/53 및 udp/53 포트가 사용 가능해야 합니다.
- 등록된 도메인 이름과 해당 네임서버/존 파일에 대한 접근. 다음 섹션에 설명된 대로 이 도메인에 대한 DNS 레코드를 생성합니다.
- $EDITOR 환경 변수가 설정되어 있어야 합니다.
- 선택적으로, 자동 DNS 레코드 업데이트를 설정할 Linux/Unix 클라이언트 시스템.
DNS 레코드 생성
동적 DNS 서버가 작동하려면 최소 2개의 DNS 레코드를 생성해야 합니다. 먼저, ns1.your_domain과 같은 서브도메인을 선택하여 서버의 IPv4 주소를 가리키도록 합니다. 둘째, ddns.your_domain과 같은 서브도메인을 선택하여 ns1.your_domain에 위임합니다.
동적 DNS 서버는 ddns.your_domain 아래의 모든 레코드를 처리합니다. 세 번째 레코드인 AAAA 유형은 선택 사항입니다. 해당 레코드는 다음과 같습니다:
ns1.your_domain A 192.0.2.2ddns.your_domain NS ns1.your_domainns1.your_domain AAAA 2001:0db8::0db9 (선택 사항)
이 레코드는 도메인 등록 기관의 제어판에서 생성해야 합니다. 이러한 레코드가 전파되는 데 최대 24시간이 걸릴 수 있지만 일반적으로 몇 분이 걸립니다.
설치
루트 사용자를 사용하지 않는 경우, 이 가이드에 표시된 대부분의 명령이 상승된 권한을 요구하므로 임시 루트 셸을 시작하는 것이 좋습니다. 루트 셸을 시작하려면 다음 명령 중 하나를 사용하십시오:
sudo su - rootsudo -s1단계: 종속성 업데이트 및 설치
시스템을 먼저 업데이트하는 것이 항상 좋은 방법입니다:
apt updateapt upgrade -yreboot재부팅 후, 이 설정에 필요한 소프트웨어 패키지를 설치합니다:
- certbot은 SSL/TLS 인증서를 얻는 데 사용됩니다.
- make는 DDNS 서버가 실행될 도커 이미지를 빌드하는 데 필요합니다.
- apt-transport-https, ca-certificates, curl, gnupg2 및 software-properties-common은 Docker 저장소 및 해당 GPG 키를 설치하는 데 필요합니다.
- dnsutils는 테스트에 사용될 dig를 제공합니다.
apt install -y certbot make apt-transport-https curl ca-certificates software-properties-common gnupg2 dnsutils2단계: Docker CE 설치
Docker의 GPG 키를 추가합니다:
curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add -Docker 저장소를 설치합니다:
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian buster stable"Debian의 저장소 캐시를 업데이트한 후 Docker 및 해당 종속성을 설치합니다:
apt updateapt install -y docker-ce docker-ce-cli containerd.io설치가 완료되면 Docker 서비스가 활성화되고 실행 중인지 확인합니다:
systemctl enable --now docker.service3단계: docker-ddns 다운로드 및 빌드
우리의 동적 DNS 서버는 Bind를 DNS 서버로 사용하고 Go로 작성된 관리 API를 사용하는 도커 컨테이너에 의해 구동됩니다. 먼저, Github 리포지토리를 클론하고 다음 명령으로 컨테이너 이미지를 빌드합니다:
git clone https://github.com/dprandzioch/docker-ddns.gitcd docker-ddnsmake image프로세스가 완료될 때까지 기다리며, 시간이 걸릴 수 있습니다. 그런 다음 텍스트 편집기로 envfile 파일을 엽니다:
$EDITOR envfile다음 내용을 입력합니다:
SHARED_SECRET=your_secret
ZONE=ddns.your_domain
RECORD_TTL=60공유 비밀은 관리 API와 인증하는 데 사용될 비밀번호입니다. ZONE은 서버가 책임질 DNS 존을 나타내며, 레코드 TTL은 DNS 레코드가 캐시될 수 있는 시간을 지정합니다. 자주 변경되는 동적 IP의 경우 60초의 TTL을 권장합니다.
필요한 경우, 다음 명령을 사용하여 비밀을 위한 무작위 40자 문자열을 생성할 수 있습니다:
cat /dev/urandom | tr -dc "a-zA-Z0-9" | fold -w 40 | head -1이제 컨테이너를 생성할 수 있습니다:
docker create -it -p 127.0.0.1:8080:8080 -p 53:53 -p 53:53/udp --env-file envfile -v /mnt/ddns-data:/var/cache/bind --name ddns-server davd/docker-ddns이 명령은 이전에 빌드한 이미지에서 ddns-server라는 이름의 컨테이너를 생성하고, 호스트에서 컨테이너로 8080/tcp, 53/tcp 및 53/udp 포트를 매핑합니다. 또한 호스트의 /mnt/ddns-data 디렉토리를 컨테이너의 파일 시스템의 /var/cache/bind에 마운트합니다. 이는 컨테이너 재생성 간에 DNS 데이터를 지속하기 위해 사용됩니다.
다음 명령으로 컨테이너가 생성되었는지 확인합니다:
docker container ls -a단일 항목이 ddns-server라는 이름으로 출력되어야 합니다.
4단계: Systemd 서비스 (선택 사항)
이 단계는 관리가 더 간단하지만 엄격히 필요하지는 않습니다. systemd 서비스를 사용하지 않기로 선택하면 컨테이너를 수동으로 관리하거나 다른 관리 솔루션을 사용해야 합니다. 더 크고 복잡한 컨테이너 배포의 경우 Kubernetes 또는 Docker Swarm과 같은 오케스트레이션 솔루션을 사용하는 것이 좋습니다. 이 경우, 단일 컨테이너만 실행하므로 systemd 서비스가 적합합니다.
이 컨테이너를 시스템 서비스로 관리할 수 있도록 systemd 유닛으로 래핑합니다. 텍스트 편집기로 /etc/systemd/system/ddns-server-ct.service 파일을 생성합니다:
$EDITOR /etc/systemd/system/ddns-server-ct.service다음 내용을 추가합니다:
[Unit]
Description=DDNS Server Docker Container
After=docker.service
Requires=docker.service
Requires=network.target
[Service]
Type=oneshot
TimeoutStartSec=240
Restart=no
RemainAfterExit=yes
ExecStart=/usr/bin/docker start ddns-server
ExecStop=/usr/bin/docker stop ddns-server
[Install]
WantedBy=multi-user.target저장하고 종료한 후, 이 유닛 파일에 대한 올바른 권한을 설정합니다:
chmod 664 /etc/systemd/system/ddns-server-ct.service다음 명령으로 새 서비스 파일을 로드합니다:
systemctl daemon-reload이제 systemctl을 사용하여 다른 시스템 서비스처럼 이 컨테이너를 시작하고 중지할 수 있어야 합니다.
DDNS 서버가 시스템 부팅 시 자동으로 시작되도록 하려면 다음을 실행합니다:
systemctl enable ddns-server-ct.service5단계: 서버 테스트
설정을 진행하기 전에 관리 API를 로컬에서 테스트합니다. 컨테이너를 시작합니다:
systemctl start ddns-server-ct.service새 레코드를 생성하기 위해 API에 GET 요청을 보냅니다:
참고: API는 현재 로컬(즉, localhost)에서만 접근할 수 있습니다.
curl "http://127.0.0.1:8080/update?secret=your_secret&domain=test1&addr=1.1.1.1"Curl은 다음 응답을 반환해야 합니다:
{"Success":true,"Message":"Updated A record for test1 to IP address 1.1.1.1","Domain":"test1","Domains":["test1"],"Address":"1.1.1.1","AddrType":"A"}참고: 도메인 test1은 test1.ddns.your_domain을 나타냅니다. 서버가 ddns.your_domain 존을 처리하고 있기 때문입니다.
레코드가 실제로 생성되었는지 확인하고 DNS 해상도를 테스트하기 위해 DNS 조회를 수행합니다:
dig +short -t A test1.ddns.your_domain @127.0.0.1출력은 1.1.1.1이어야 합니다.
6단계: 리버스 프록시
API가 HTTP를 통해 작동하므로, 네트워크를 통해 요청을 보낼 때 인증 비밀이 스니핑될 수 있습니다. 공격자는 이 비밀을 사용하여 DNS 레코드를 조작할 수 있습니다. Nginx를 사용하여 리버스 프록시를 설정하고 HTTPS를 사용하여 보안합니다. 먼저, certbot을 사용하여 Let’s Encrypt에서 SSL 인증서를 얻습니다:
certbot certonly --standalone --agree-tos -m [email protected] -d ns1.your_domain도메인의 소유권이 확인되고 인증서가 발급됩니다. 다음으로 Nginx를 설치하고 활성화되어 실행 중인지 확인합니다:
apt install -y nginx systemctl enable --now nginx.service그런 다음 기본 서버 블록 파일을 비활성화합니다. 이는 필요하지 않습니다:
unlink /etc/nginx/sites-enabled/default이제 리버스 프록시를 위한 새 구성 파일을 생성합니다. 예를 들어:
$EDITOR /etc/nginx/sites-available/ddns-api-proxy.conf다음 내용을 붙여넣고 IP 주소와 도메인 이름을 자신의 것으로 교체합니다:
server {
listen 192.0.2.2:8080;
server_name ns1.your_domain;
ssl on;
ssl_certificate /etc/letsencrypt/live/ns1.your_domain/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/ns1.your_domain/privkey.pem;
location /update {
proxy_pass http://127.0.0.1:8080;
}
location / {
return 404;
}
access_log /var/log/nginx/ddns-api-access.log;
error_log /var/log/nginx/ddns-api-error.log;
}선택 사항: API를 IPv6를 통해 접근 가능하게 하려면 기존 listen 지시문 뒤에 다음 줄을 추가합니다:
listen [2001:0db8::0db9]:8080;이 구성을 활성화하고 Nginx를 다시 로드하여 변경 사항을 적용합니다:
ln -s /etc/nginx/sites-available/ddns-api-proxy.conf /etc/nginx/sites-enabled/systemctl reload nginx.service이제 API는 인터넷을 통해 접근 가능하며, HTTPS 연결만 허용합니다. 테스트하려면 다음 명령을 실행합니다:
curl "https://ns1.your_domain:8080/update?secret=your_secret&domain=test2&addr=1.1.1.2"다음과 같은 응답이 반환되어야 합니다:
{"Success":true,"Message":"Updated A record for test2 to IP address 1.1.1.2","Domain":"test2","Domains":["test2"],"Address":"1.1.1.2","AddrType":"A"}7단계: 클라이언트 구성
Pfsense와 같은 사용자 지정 동적 DNS 공급자를 지원하는 모든 라우터에서 자동 레코드 업데이트를 설정할 수 있습니다. 사무실이나 홈 네트워크의 대부분의 다른 장치에서도 설정할 수 있습니다. 레코드를 업데이트하거나 생성하려면 다음 엔드포인트에 GET 요청을 보내야 합니다:
https://ns1.your_domain:8080/update?secret=your_secret&domain=your_subdomain&addr=your_ip_address단일 요청으로 여러 서브도메인의 레코드를 업데이트할 수도 있습니다. 예를 들어, IP 주소 198.51.100.100으로 sub1.ddns.your_domain 및 sub2.ddns.your_domain의 레코드를 생성/업데이트하려면 다음 URL에 GET 요청을 보내야 합니다:
https://ns1.your_domain:8080/update?secret=your_secret&domain=sub1,sub2&addr=198.51.100.100addr 매개변수는 AAAA DNS 레코드를 생성/업데이트하기 위해 IPv6 주소를 포함할 수도 있습니다. 예를 들어:
https://ns1.your_domain:8080/update?secret=your_secret&domain=cheese&addr=2001:0db8:aaaa::Linux 클라이언트에서 이러한 업데이트를 자동화하려면 다음 bash 스크립트를 /opt/ddns-update.sh로 저장합니다:
#!/bin/bash
while [ -z $CURRENTIP ]
do
CURRENTIP=`dig -r +short myip.opendns.com @resolver1.opendns.com 2>/dev/null`
sleep 1
done
curl -s "https://ns1.your_domain:8080/update?secret=your_secret&domain=your_subdomain&addr=${CURRENTIP}"이 스크립트는 클라이언트의 공용 IP 주소를 가져오고 이를 변수에 저장하는 dig 명령을 감싼 while 루프를 사용합니다. 루프는 공용 IP가 올바르게 가져와지도록 보장합니다. 그런 다음 cURL을 사용하여 이 새로 가져온 IP로 DNS 레코드를 업데이트하기 위해 API 요청을 보냅니다. your_secret 및 your_subdomain의 값을 교체해야 합니다.
다음으로 이 스크립트를 실행 가능하게 만듭니다:
chmod +x /opt/ddns-update.sh그런 다음 crontab 편집기를 엽니다:
crontab -ecrontab의 끝에 다음 줄을 추가합니다:
*/2 * * * * /opt/ddns-update.sh저장하고 종료합니다. 이제 이 스크립트는 매 2분마다 실행되어 클라이언트의 최신 공용 IP 주소로 동적 DNS 레코드를 최신 상태로 유지합니다.
추가 읽기
- 동적 DNS 위키백과 기사
- Github의 docker-ddns
새 게시물을 받은 편지함에서 받기
스팸은 없습니다. 언제든지 구독 해지 가능합니다.