서버가 몇 대만 늘어나도 IP 주소를 외워 접속하기가 번거로워져요. 내부 DNS를 두면 node1.lab.com처럼 이름으로 접속하고, 서버 주소가 바뀌었을 때 DNS 레코드 한곳에서 관리할 수 있습니다.
이 글은 Rocky Linux 9에 BIND를 설치해 lab.com의 이름과 IP를 관리하는 내부 DNS 서버를 구성합니다. 이름에서 IP를 찾는 정방향 조회, IP에서 이름을 찾는 역방향 조회, 클라이언트의 DNS 지정까지 연결합니다.
이 글의 목차
실습 환경과 도메인 사용 범위
| 항목 | 예제 값 | 용도 |
|---|---|---|
| 내부 네트워크 | 192.168.10.0/24 | DNS 조회를 허용할 대역 |
| DNS 서버 | ns1.lab.com / 192.168.10.10 | Rocky Linux 9, BIND |
| 시간 서버 | ntp.lab.com / 192.168.10.20 | 별도 chronyd 글과 연결 |
| 클라이언트 | node1.lab.com / 192.168.10.30 | 조회·접속을 시험할 호스트 |
| 별칭 | www.lab.com | node1.lab.com을 가리키는 CNAME |
위 주소는 실습용 가정입니다. 서버와 클라이언트 사이에 통신이 가능하고, DNS 서버의 고정 IP가 이미 설정되어 있어야 합니다. 고정 IP부터 준비한다면 Rocky Linux 9 고정 IP 설정 글을 먼저 참고하세요. 명령은 sudo 권한이 있는 계정에서 실행합니다.
lab.com은 예약된 예제 도메인이 아닙니다. 여기서는 요청한 이름을 격리된 실습망 안에서만 사용합니다. 운영망에는 자신이 관리하는 도메인의 하위 도메인을 사용하세요. 이 서버가 lab.com 존을 갖는 동안에는 공용 인터넷의 같은 이름을 내부 레코드로 가리며, 내부에 없는 lab.com 하위 이름을 자동으로 공용 DNS에 다시 묻지 않습니다. 예약된 예제 도메인은 IANA 안내에서 확인할 수 있습니다.
1. BIND 설치와 기존 설정 보관
BIND는 DNS 서버 소프트웨어이고, Rocky Linux에서 서비스 이름은 named입니다. 먼저 패키지를 설치하고 설정을 백업합니다. 기존 DNS 서버가 아니라 새 실습 서버를 기준으로 진행합니다.
sudo dnf install -y bind bind-utils
rpm -q bind bind-utils
sudo cp -a /etc/named.conf /etc/named.conf.before-lab
bind-utils에는 확인에 사용할 dig, nslookup 등이 들어 있습니다. 백업 파일이 이미 있다면 다른 이름을 사용해 이전 사본을 보존합니다. SELinux는 기본 enforcing 상태를 유지하고, named-chroot 대신 일반 named 서비스를 사용합니다. 구성 방식은 RHEL 9의 BIND 안내를 기준으로 합니다.
2. 수신 주소와 조회 허용 대역 지정
sudo vi /etc/named.conf로 파일을 엽니다. 기존 options보다 앞에 아래 ACL을 추가합니다. ACL은 접근을 허용할 주소들을 묶은 목록입니다.
acl "lab_clients" {
127.0.0.1;
192.168.10.0/24;
};
기존 options { ... }; 안에서 다음 항목을 찾아 수정하고, 없는 항목만 추가합니다. options 블록을 하나 더 만들거나 같은 항목을 중복으로 넣지 않습니다. 아래는 수정할 부분이며 파일 전체 내용이 아닙니다.
listen-on port 53 { 127.0.0.1; 192.168.10.10; };
listen-on-v6 port 53 { none; };
allow-query { lab_clients; };
recursion yes;
allow-recursion { lab_clients; };
allow-query-cache { lab_clients; };
allow-transfer { none; };
이 예제는 IPv4 내부망용입니다. listen-on은 서버가 실제로 가진 주소여야 합니다. 기본 파일의 directory "/var/named";, DNSSEC 검증 설정, 기본 존과 include는 그대로 둡니다. 재귀 조회는 서버가 다른 DNS에 질문해 답을 찾아오는 기능이며, 내부 대역에만 허용합니다. 존 전송은 다른 DNS 서버에 존 전체를 복제하는 기능으로, 보조 DNS를 구성하지 않는 이 실습에서는 차단합니다.
기본 재귀 조회로 외부 이름도 찾으려면 DNS 서버에서 인터넷의 DNS 서버로 TCP·UDP 53번 통신이 가능해야 합니다. 회사에서 지정한 상위 DNS만 허용한다면 그 실제 주소를 forwarders로 지정하고 필요에 따라 forward only;를 사용합니다. 외부 조회가 필요 없는 폐쇄망은 이 options에서 recursion no;로 바꾸어 내부 존만 제공해도 됩니다.
3. 정방향·역방향 존 등록
존(zone)은 이 DNS 서버가 관리하는 이름 영역입니다. 다음 내용으로 /etc/named.lab.zones를 만듭니다. 이 경로에 기존 파일이 있다면 먼저 보관하고 내용을 병합합니다.
sudo tee /etc/named.lab.zones > /dev/null <<'EOF'
zone "lab.com" IN {
type master;
file "lab.com.zone";
allow-update { none; };
};
zone "10.168.192.in-addr.arpa" IN {
type master;
file "192.168.10.rev";
allow-update { none; };
};
EOF
lab.com은 정방향 존입니다. 역방향 존의 10.168.192.in-addr.arpa는 192.168.10.0/24에서 앞의 세 옥텟을 거꾸로 적은 이름이에요. 이 예시는 /24 기준이며, 다른 크기의 대역을 단순히 같은 방법으로 자르면 안 됩니다.
/etc/named.conf 맨 아래의 전역 위치에 다음 한 줄을 한 번만 추가합니다. options 내부에 넣지 않습니다.
include "/etc/named.lab.zones";
file의 상대 경로는 기본 directory "/var/named";를 기준으로 해석합니다. 따라서 다음 단계의 파일은 /var/named/에 저장합니다.
4. lab.com 정방향 레코드 작성
/var/named/lab.com.zone에 아래 내용을 저장합니다.
sudo tee /var/named/lab.com.zone > /dev/null <<'EOF'
$TTL 3600
@ IN SOA ns1.lab.com. hostmaster.lab.com. (
2026102301 ; serial
3600 ; refresh
900 ; retry
604800 ; expire
300 ; negative cache TTL
)
IN NS ns1.lab.com.
@ IN A 192.168.10.30
ns1 IN A 192.168.10.10
ntp IN A 192.168.10.20
node1 IN A 192.168.10.30
www IN CNAME node1.lab.com.
EOF
A는 이름과 IPv4 주소를 연결하고, CNAME은 다른 이름을 가리키는 별칭입니다. NS는 이 존의 DNS 서버를 지정합니다. SOA는 존의 기준 정보이며, hostmaster.lab.com.은 관리자 메일 주소 hostmaster@lab.com을 표현한 예제 값입니다. 운영 시 실제 관리 주소로 바꿉니다.
ns1.lab.com.처럼 완전한 이름 뒤에는 점을 붙입니다. 점을 빼면 현재 존 이름이 다시 붙어 ns1.lab.com.lab.com.으로 해석될 수 있어요. @는 존 자체인 lab.com입니다. www 별칭을 만들었다고 웹 서버가 설치되는 것은 아닙니다.
serial의 2026102301은 초기 예시 값입니다. 이후 존 내용을 바꿀 때마다 기존 값보다 증가시킵니다. 날짜 형식을 쓸 경우 같은 날 두 번째 수정은 2026102302처럼 올립니다.
5. 역방향 레코드와 파일 권한 설정
이번에는 IP 주소의 마지막 옥텟과 호스트 이름을 연결합니다.
sudo tee /var/named/192.168.10.rev > /dev/null <<'EOF'
$TTL 3600
@ IN SOA ns1.lab.com. hostmaster.lab.com. (
2026102301
3600
900
604800
300
)
IN NS ns1.lab.com.
10 IN PTR ns1.lab.com.
20 IN PTR ntp.lab.com.
30 IN PTR node1.lab.com.
EOF
sudo chown root:named /etc/named.lab.zones \
/var/named/lab.com.zone /var/named/192.168.10.rev
sudo chmod 640 /etc/named.lab.zones \
/var/named/lab.com.zone /var/named/192.168.10.rev
sudo restorecon -v /etc/named.lab.zones \
/var/named/lab.com.zone /var/named/192.168.10.rev
PTR은 IP에서 이름을 찾는 레코드입니다. 30은 이 역방향 존에서 192.168.10.30을 뜻합니다. 이 서버는 파일을 읽기만 하므로 쓰기 권한을 넓힐 필요가 없습니다. restorecon은 표준 경로의 SELinux 문맥을 복구합니다. 권한 문제 때문에 SELinux를 끄거나 chmod 777을 적용하지 않습니다.
6. 문법 검사 후 방화벽과 서비스 적용
서비스를 시작하기 전에 두 존과 전체 설정을 검사합니다.
sudo named-checkzone lab.com /var/named/lab.com.zone
sudo named-checkzone 10.168.192.in-addr.arpa /var/named/192.168.10.rev
sudo named-checkconf -z /etc/named.conf
named-checkzone에서 OK가 나오는지 확인합니다. named-checkconf -z는 설정 문법과 주 존 파일의 로드를 함께 검사합니다. 오류가 있으면 파일 경로, 세미콜론, 괄호와 이름 끝의 점부터 수정합니다.
firewalld가 실행 중인 서버에서는 먼저 클라이언트 트래픽을 받는 인터페이스의 zone을 확인합니다.
sudo firewall-cmd --get-active-zones
다음은 해당 zone이 public인 경우입니다. 다른 zone이면 그 이름으로 바꿉니다. dns 서비스는 TCP와 UDP 53번을 함께 허용합니다. 일반 DNS 조회에도 TCP가 쓰일 수 있으므로 UDP만 열지 않습니다.
sudo firewall-cmd --permanent --zone=public --add-service=dns
sudo firewall-cmd --reload
sudo firewall-cmd --zone=public --query-service=dns
sudo systemctl enable --now named
sudo systemctl restart named
sudo systemctl status named --no-pager
sudo ss -lntup '( sport = :53 )'
query-service가 yes, 서비스가 active (running)인지 확인합니다. 수신 주소에 192.168.10.10:53이 있어야 합니다. firewalld 대신 다른 방화벽을 사용 중이면 그 정책에서 허용하며, DNS 접근은 앞서 지정한 BIND ACL로도 제한합니다.
7. 서버를 직접 지정해 조회 시험
먼저 DNS 서버 자체에서 실행합니다. 이어서 같은 명령을 클라이언트에서도 실행해 네트워크 경로까지 확인합니다. 클라이언트에도 bind-utils가 필요합니다.
dig @192.168.10.10 ns1.lab.com A
dig @192.168.10.10 node1.lab.com A +short
dig @192.168.10.10 www.lab.com CNAME +short
dig @192.168.10.10 -x 192.168.10.30 +short
dig @192.168.10.10 lab.com SOA +short
dig @192.168.10.10 node1.lab.com A +tcp +short
아래는 위 설정에서 기대하는 값입니다. 실제 로그를 옮긴 표가 아니라, 자신의 결과와 비교할 기준입니다.
| 확인 대상 | 기대 값 |
|---|---|
ns1.lab.com A | 상태 NOERROR, 응답 IP 192.168.10.10, 권한 응답 플래그 aa |
node1.lab.com A | 192.168.10.30 |
www.lab.com CNAME | node1.lab.com. |
192.168.10.30 PTR | node1.lab.com. |
lab.com SOA | ns1.lab.com.과 설정한 serial 포함 |
| TCP 조회 | 192.168.10.30 |
인터넷 재귀 조회까지 사용하는 환경이라면 dig @192.168.10.10 rockylinux.org A도 확인합니다. 내부 이름은 되는데 외부 이름만 실패하면 내부 존을 다시 만들기보다 상위 DNS·인터넷 경로와 서버 시각, DNSSEC 검증 로그를 확인하는 편이 빠릅니다.
8. 클라이언트의 기본 DNS로 지정
직접 지정한 dig @...가 성공한 뒤에 클라이언트 설정을 바꿉니다. Rocky Linux 9의 NetworkManager 연결 이름은 아래 명령으로 확인합니다.
nmcli -t -f NAME,DEVICE connection show --active
다음 예시는 연결 이름이 ens160인 경우입니다. 첫 줄의 값은 위에서 확인한 실제 연결 이름으로 바꿉니다. 변경 전 DNS·DHCP 무시 설정을 기록해 두고, 여러 NIC가 있다면 DNS를 제공할 연결을 정확히 선택합니다.
LAB_CONNECTION='ens160'
nmcli -f ipv4.dns,ipv4.dns-search,ipv4.ignore-auto-dns,ipv6.ignore-auto-dns \
connection show "$LAB_CONNECTION"
sudo nmcli connection modify "$LAB_CONNECTION" \
ipv4.dns "192.168.10.10" \
ipv4.dns-search "lab.com" \
ipv4.ignore-auto-dns yes \
ipv6.ignore-auto-dns yes
sudo nmcli device reapply ens160
마지막 ens160은 장치 이름이며 연결 이름과 다를 수 있습니다. 실제 장치 이름으로 바꾸세요. reapply로 적용되지 않는 항목은 콘솔 접속이 가능한 상태에서 nmcli connection up "$LAB_CONNECTION"으로 재활성화합니다. SSH 연결이 끊길 수 있으므로 원격 접속만 가능한 상태에서는 재활성화를 서두르지 않습니다.
nmcli device show ens160
cat /etc/resolv.conf
dig node1.lab.com A
getent hosts node1.lab.com
getent hosts node1
dig의 SERVER가 내부 DNS인지 확인합니다. getent는 /etc/hosts 등도 반영하므로, 예전에 같은 이름을 등록했다면 구분해서 봅니다. 검색 도메인 lab.com은 짧은 이름 node1을 찾을 때 사용합니다. IPv6 자동 DNS도 무시하도록 한 이유는 다른 DNS가 내부 이름 질의에 섞이지 않게 하기 위해서입니다. 다른 활성 연결이나 VPN의 DNS가 있다면 함께 확인합니다.
내부 존을 모르는 공용 DNS를 보조 주소로 함께 넣으면 내부 이름 조회가 불규칙하게 실패할 수 있습니다. 이중화가 필요하면 같은 내부 존을 제공하는 두 번째 DNS를 준비합니다. /etc/resolv.conf만 직접 고치면 NetworkManager가 다시 쓸 수 있으므로 연결 프로필에서 관리합니다.
레코드 변경과 오류 확인
레코드를 수정한 뒤에는 해당 존의 serial을 올리고 검사부터 다시 수행합니다. 서비스가 실행 중일 때 다음 명령으로 구성을 다시 읽힙니다.
sudo named-checkconf -z /etc/named.conf
sudo rndc reload
sudo journalctl -u named -n 60 --no-pager
TTL이 남아 있는 클라이언트나 중간 DNS는 이전 값을 유지할 수 있습니다. 이때 서버를 직접 지정해 조회한 결과와 일반 조회 결과를 비교하세요.
| 증상 | 먼저 확인할 곳 |
|---|---|
connection timed out | 서버 IP·경로, 수신 주소, 방화벽 zone, TCP·UDP 53번 |
REFUSED | 요청한 클라이언트 IP가 lab_clients에 포함되는지 |
SERVFAIL | 존 로드 오류와 로그, 외부 조회라면 DNSSEC·상위 경로·서버 시각 |
NXDOMAIN | 조회한 이름의 레코드 존재 여부와 존 이름, 이름 끝의 점 |
@서버IP로는 성공하고 일반 조회는 실패 | 클라이언트 DNS, 다른 NIC·VPN, /etc/hosts와 캐시 |
이제 node1.lab.com과 역방향 조회가 일치하면 내부 이름 관리를 시작할 수 있어요. 다음으로 ntp.lab.com을 실제 시간 서버로 구성하려면 chronyd 로컬 시간 서버 구성 글을 이어서 참고하면 됩니다.
확인 범위: 2026년 10월 23일 공식 문서를 확인했습니다. Rocky Linux 9 컨테이너에서 예제의 존 문법과 정방향·역방향·CNAME·TCP 조회를 검증했습니다. firewalld·NetworkManager·systemd 및 SELinux enforcing 상태의 전체 VM 적용은 별도 확인이 필요합니다. 대표 이미지는 일반 서버 랙 참고 사진이며 이 실습 환경을 촬영한 사진이 아닙니다.



