Debian에서 Node 앱이 외부 API(예: api.stripe.com)나 DB 호스트를 호출할 때 갑자기 ENOTFOUND, EAI_AGAIN, 타임아웃이 늘었다면, 의외로 “DNS 설정 실수”가 원인인 경우가 많습니다. 특히 /etc/resolv.conf가 예상과 다르게 바뀌었거나, systemd-resolved/NetworkManager/클라우드 에이전트가 서로 덮어쓰는 상황이 흔합니다.

DNS 연결 오류를 상징하는 서버와 끊어진 체인

아래는 가장 흔한 실수부터 순서대로 좁혀가는 점검/해결 흐름입니다.

1) 증상 정리: DNS 문제인지 먼저 구분하기

DNS 이슈는 “네트워크가 완전히 죽음”이 아니라, 특정 도메인만 또는 간헐적으로 실패하는 형태로 나타나는 경우가 많습니다. Node에서는 다음 로그가 단서가 됩니다.

  • getaddrinfo ENOTFOUND: 도메인 자체를 못 찾음(대개 DNS 서버/도메인 오타/검색 도메인 영향)
  • getaddrinfo EAI_AGAIN: 일시적 DNS 실패(타임아웃/UDP 막힘/리졸버 불안정/캐시 문제)
  • 같은 호스트에 대해 성공/실패가 번갈아 발생: 여러 DNS 서버 중 하나가 불량이거나, split-horizon/사설 DNS가 섞였을 가능성

빠르게 구분하려면 “IP로 붙으면 되는데 도메인으로만 실패”하는지 확인합니다. 예를 들어 외부 API가 IP로 접근 가능한 구조는 드물지만, 내부 서비스(사설 DB 등)는 IP로 테스트가 가능합니다.

2) 점검 순서(체크리스트): 가장 흔한 설정 실수부터

아래 체크리스트를 위에서부터 순서대로 진행하면, 불필요한 삽질을 줄일 수 있습니다.

  • /etc/resolv.conf가 실제로 어떤 파일(실파일/심볼릭 링크)인지 확인
  • nameserver가 올바른지(사내 DNS, 8.8.8.8/1.1.1.1 등 정책에 맞게) 확인
  • systemd-resolved 사용 여부 확인(127.0.0.53을 쓰는지)
  • VPN/클라우드 에이전트/NetworkManager가 DNS를 덮어쓰는지 확인
  • 도메인 오타/불필요한 search 설정으로 엉뚱한 질의가 추가되지 않는지 확인
  • 방화벽/보안그룹에서 UDP/TCP 53이 막히지 않았는지 확인
  • 캐시(nscd/dnsmasq/systemd-resolved)가 꼬였을 가능성 점검

서버 DNS 점검 체크리스트 흐름 도식

3) 1차 확인: resolv.conf와 systemd-resolved 상태 보기

먼저 현재 리졸버 구성이 무엇인지 “사실 확인”부터 합니다.

  • /etc/resolv.conf 내용 확인(현재 nameserver가 무엇인지)
  • /etc/resolv.conf가 심볼릭 링크인지 확인(예: systemd-resolved가 관리)
  • systemd-resolved를 쓴다면 “서버가 어떤 DNS 서버를 업스트림으로 쓰는지” 확인

자주 보는 패턴은 다음 둘입니다.

  • nameserver 127.0.0.53: 로컬 stub(systemd-resolved)로 보내고, 실제 업스트림 DNS는 별도 설정
  • 직접 IP가 박혀 있음(예: nameserver 10.x.x.x 또는 공용 DNS): 외부 환경에서 덮어쓰기 당했는지 의심

여기서 흔한 실수는, systemd-resolved 환경인데 운영자가 /etc/resolv.conf를 직접 편집했다가 이후 재부팅/네트워크 갱신 때 원복되며 장애가 “간헐적”으로 보이는 경우입니다.

4) 재현 테스트: dig/nslookup로 “어느 DNS에서” 실패하는지 분리

DNS 문제는 “어느 리졸버로 질의했는지”를 분리하면 원인 범위가 확 줄어듭니다. 핵심은 같은 도메인을 기본 리졸버특정 DNS 서버로 각각 질의해 비교하는 것입니다.

  • 기본 리졸버로 조회했을 때 응답이 느리거나 실패하는지
  • 특정 DNS(예: 사내 DNS, 1.1.1.1, 8.8.8.8)로 강제 조회하면 정상인지
  • 응답이 오더라도 결과가 다른지(split-horizon, 내부/외부 레코드 충돌)

또 하나 자주 놓치는 부분이 IPv6(AAAA)입니다. AAAA 응답이 애매하게 구성되어 있거나, IPv6 라우팅이 막혀 있는데도 Node가 IPv6로 먼저 시도하면서 체감 장애가 생길 수 있습니다(환경에 따라).

DNS 질의 흐름과 실패 지점 분리 도식

5) 해결 단계: 흔한 원인별로 안전하게 정리

아래는 “가장 흔한 설정 실수” 순서대로, 리스크가 낮은 것부터 정리한 해결 단계입니다.

  • 오타/잘못된 DNS 서버 IP: nameserver를 정책에 맞는 값으로 수정(사내 DNS 우선, 필요 시 보조 DNS 추가)
  • /etc/resolv.conf 덮어쓰기: systemd-resolved/NetworkManager 중 실제 관리 주체를 하나로 정리(수동 편집을 반복하지 않도록)
  • search 도메인 과다/오염: 불필요한 search를 제거(질의가 늘어 타임아웃이 증가하는 원인)
  • 방화벽/보안그룹 이슈: DNS 서버로의 UDP 53이 막히면 타임아웃 형태로 나타남. 정책상 TCP 53도 필요할 수 있음(응답이 큰 경우)
  • 캐시 꼬임: systemd-resolved 캐시 플러시 또는 관련 데몬 재시작으로 즉시 복구되는지 확인
  • IPv6 우선 시도 문제: 네트워크가 IPv6를 제대로 지원하지 않으면, OS/애플리케이션 레벨에서 우선순위 조정 검토

운영 팁으로는, “임시로 공용 DNS를 넣어 바로 복구”는 가능하지만, 사내 망/프라이빗 존을 쓰는 환경에서는 오히려 내부 도메인이 깨질 수 있습니다. 따라서 외부 도메인과 내부 도메인 둘 다 테스트하면서 바꾸는 게 안전합니다.

6) Node 관점 확인: 앱 설정/런타임이 DNS 실패를 키우는 경우

DNS가 완전히 정상이어도, Node 앱에서 다음 조건이 겹치면 장애가 과장되어 보일 수 있습니다.

  • 재시도 로직이 없거나, 재시도 간격이 너무 짧아 한꺼번에 폭주
  • DNS 실패(EAI_AGAIN)를 즉시 “치명적 오류”로 처리
  • 외부 API 호출이 동기적으로 몰려서, 실패 시 대량 타임아웃이 누적

가능하면 외부 호출에는 타임아웃지수 백오프 재시도를 두고, DNS가 잠깐 흔들려도 서비스 전체가 멈추지 않게 완충을 두는 편이 좋습니다. 다만 이건 “근본 원인 해결 후” 안정성을 보강하는 성격으로 접근하는 게 좋습니다.

마무리

Debian에서 DNS 장애는 대부분 “/etc/resolv.conf가 누가 관리하는지 모르는 상태”에서 시작합니다. 먼저 현재 구성을 확정하고(실제 nameserver, systemd-resolved 여부), dig/nslookup로 어느 단계에서 실패하는지 분리하면 빠르게 좁혀집니다.

체크리스트대로 한 번만 정리해두면, 다음에 같은 증상이 와도 원인 파악이 훨씬 빨라집니다.