Nginx 설정 테스트: 주요 명령어로 안정적인 배포 보장하기

nginx -t, nginx -T 및 안전한 리로드 습관을 사용하여 트래픽에 영향을 미치기 전에 Nginx 설정 오류를 잡아내세요.

Nginx 설정 테스트: 주요 명령어로 안정적인 배포 보장하기

Nginx 설정 테스트는 사소해 보이지만, 잘못된 리로드로부터 당신을 구해주는 습관 중 하나입니다. 세미콜론 하나가 빠지거나, 잘못된 include 경로, 또는 없는 모듈의 지시어가 Nginx가 새 설정을 적용하지 못하게 할 수 있습니다. 프로덕션 리버스 프록시에서는 작은 실수가 아닙니다.

핵심 명령어는 간단합니다:

sudo nginx -t

매 리로드 전에 실행하세요. 서버 블록을 수정한 후에도 실행하세요. 팀이 Nginx 설정을 Git에 저장한다면 CI에서도 실행하세요. 이 명령어는 설정을 파싱하고 구문이 유효한지 보고합니다. 라우팅 로직이 올바른지, TLS 인증서가 모든 호스트 이름에 유효한지, 또는 업스트림 앱이 정상인지는 증명하지 않습니다. Nginx가 설정을 적용하기 전에 감지할 수 있는 오류 유형을 잡아냅니다.

nginx -t가 확인하는 것

nginx -t는 Nginx에게 설정을 테스트하라고 지시합니다. 메인 설정 파일을 읽고, include 지시어를 따라가며, 지시어와 블록을 파싱하고, 많은 파일/경로 문제를 확인합니다. 성공적인 실행은 보통 다음과 같습니다:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

실패한 실행은 파일과 줄 번호를 가리킵니다:

nginx: [emerg] unexpected "}" in /etc/nginx/conf.d/api.conf:18
nginx: configuration file /etc/nginx/nginx.conf test failed

줄 번호는 파서가 문제를 발견한 위치이지, 항상 실수를 한 곳은 아닙니다. Nginx가 18번 줄에 예상치 못한 }가 있다고 하면, 그 위의 줄에서 세미콜론 누락이나 닫히지 않은 블록을 확인하세요.

설정 파일, 인증서 파일, 또는 포함된 스니펫이 root만 읽을 수 있는 경우 sudo를 사용하세요:

sudo nginx -t

올바른 권한이 없으면 구문이 정상이어도 테스트가 실패할 수 있습니다.

include로 설정을 보기 어려울 때 nginx -T 사용하기

많은 Nginx 설정은 /etc/nginx/nginx.conf, conf.d/*.conf, sites-enabled/*, 그리고 공유 스니펫에 걸쳐 분할됩니다. 이는 유지보수에 좋지만 디버깅을 혼란스럽게 만들 수 있습니다.

nginx -T는 설정을 테스트하고 전체 파싱된 설정을 stdout으로 출력합니다:

sudo nginx -T

이는 다음과 같은 질문에 답해야 할 때 유용합니다:

  • 이 서버 블록을 실제로 정의하는 파일은 무엇인가?
  • include 패턴이 백업 파일을 가져왔는가?
  • 이 지시어가 http, server, 또는 location 범위에서 설정되고 있는가?
  • 중복된 server_name 블록 중 어떤 것이 우선하는가?

nginx -T 출력을 공유할 때 주의하세요. 인증서 경로, 내부 호스트 이름, 업스트림 이름, 헤더, 또는 민감한 컨텍스트의 주석이 포함될 수 있습니다. 티켓에 사용할 때는 게시하기 전에 수정하세요.

-c로 기본이 아닌 설정 파일 테스트하기

스테이징 경로에서 설정을 작성 중이라면 -c를 사용하세요:

sudo nginx -t -c /home/deploy/nginx-staging/nginx.conf

이는 Nginx에게 테스트할 메인 설정 파일을 알려줍니다. 해당 설정 내의 상대 경로는 접두사 설정에 따라 다르게 동작할 수 있으므로, 가능하면 스테이징 테스트를 프로덕션 레이아웃에 가깝게 유지하세요.

컴파일 타임 경로와 모듈도 다음으로 검사할 수 있습니다:

nginx -V

출력은 많은 시스템에서 stderr로 가는데, 출력을 리디렉션할 때 사람들을 놀라게 합니다. Nginx 버전과 빌드 옵션(모듈 지원 및 기본 경로 포함)을 보여줍니다. 이는 설정이 http_v2, realip, stub_status, 또는 스트림 프록시와 같은 모듈의 지시어를 사용할 때 중요합니다.

리로드, 무턱대고 재시작하지 마세요

테스트가 통과하면 Nginx를 리로드하세요:

sudo systemctl reload nginx

리로드는 마스터 프로세스에게 새 설정을 읽고, 기존 작업자가 현재 요청을 완료하는 동안 새 작업자를 시작하도록 요청합니다. 이는 설정 변경의 일반적인 경로입니다.

재시작은 서비스를 중지하고 시작합니다:

sudo systemctl restart nginx

패키지 변경이나 서비스 상태 문제 후와 같이 실제로 필요할 때만 재시작을 사용하세요. 일반적인 설정 편집에는 리로드가 덜 방해가 됩니다.

일부 systemd 유닛 파일은 리로드의 일부로 설정 테스트를 실행합니다. 이것만으로 안전망을 삼지 마세요. 직접 nginx -t를 먼저 실행하여 실행 중인 서비스를 건드리기 전에 실패를 확인하세요.

기본 Nginx 시그널 명령어도 일반적입니다:

sudo nginx -s reload

systemd로 관리되는 서버에서는 보통 systemctl reload nginx를 선호합니다. 서비스 상태와 로그를 동일한 관리 계층에 유지하기 때문입니다.

안전한 편집 워크플로우

일반적인 서버 블록 변경에는 이 리듬을 사용하세요:

sudo cp /etc/nginx/conf.d/api.conf /etc/nginx/conf.d/api.conf.bak.$(date +%Y%m%d%H%M%S)
sudoedit /etc/nginx/conf.d/api.conf
sudo nginx -t
sudo systemctl reload nginx
sudo systemctl status nginx --no-pager

설정이 Git에 있다면, 무작위 백업 파일을 영원히 보관하는 대신 변경 사항을 커밋하세요. 위의 백업 명령어는 소규모 관리되지 않는 서버에 유용하지만, 버전 관리를 대체하지는 않습니다.

리로드 후 실제 경로를 테스트하세요:

curl -I https://example.com/api/health
curl -I -H 'Host: example.com' http://127.0.0.1/

nginx -t는 설정이 파싱된다고 알려줍니다. curl은 사이트가 의도한 대로 동작하는지 알려줍니다.

일반적인 실패 메시지와 그 의미

세미콜론 누락은 종종 다음과 같이 보입니다:

nginx: [emerg] invalid number of arguments in "proxy_set_header" directive in /etc/nginx/conf.d/app.conf:22

해당 줄과 그 이전 줄의 지시어를 확인하세요. Nginx 지시어는 보통 ;로 끝나고, 블록은 { ... }로 끝납니다.

잘못된 include 경로는 다음과 같습니다:

nginx: [emerg] open() "/etc/nginx/snippets/security-headers.conf" failed (2: No such file or directory)

파일 경로가 잘못되었거나, 스니펫이 배포되지 않았거나, include 패턴이 환경별로 다릅니다.

권한 문제는 다음과 같을 수 있습니다:

nginx: [emerg] cannot load certificate "/etc/letsencrypt/live/example.com/fullchain.pem": BIO_new_file() failed

파일이 없거나, 심볼릭 링크가 깨졌거나, 테스트를 실행하는 사용자가 읽을 수 없습니다. 인증서 갱신 및 배포 스크립트에서 자주 발생하는 문제입니다.

알 수 없는 지시어는 세 가지 중 하나를 의미합니다: 오타, 잘못된 컨텍스트, 또는 누락된 모듈.

nginx: [emerg] unknown directive "proxy_cache_purge"

지시어 이름이 잘못되었을 수 있습니다. 다른 모듈에 속할 수 있습니다. 프로덕션 Nginx 빌드에 스테이징에 있던 타사 모듈이 포함되지 않았을 수 있습니다. 설정이 이식 가능하다고 가정하기 전에 nginx -V를 확인하세요.

중복되거나 충돌하는 서버 이름은 하드 실패보다는 경고로 나타날 수 있습니다:

nginx: [warn] conflicting server name "example.com" on 0.0.0.0:80, ignored

마지막 줄이 테스트 성공을 알린다고 해서 경고를 무시하지 마세요. 경고는 Nginx가 생각하는 서버 블록을 사용하지 않을 수 있음을 의미할 수 있습니다.

CI에서 테스트하기

Nginx 설정이 저장소에 있다면 배포 전에 테스트하세요. 간단한 컨테이너 기반 검사는 설정을 Nginx 이미지에 마운트하고 다음을 실행할 수 있습니다:

nginx -t -c /etc/nginx/nginx.conf

어려운 부분은 프로덕션 경로를 일치시키는 것입니다. 설정이 /etc/letsencrypt를 참조하면 로컬 테스트에는 플레이스홀더 파일이나 테스트별 설정이 필요합니다. 업스트림 호스트 이름을 참조하면 구문 테스트에는 업스트림이 살아 있을 필요가 없지만, 포함된 파일과 인증서 파일은 존재해야 합니다.

여러 사이트를 가진 팀의 경우, nginx -T를 실행하고 정리된 출력을 아티팩트로 저장하는 사전 배포 단계를 추가하세요. 리로드가 이상하게 동작할 때, 마지막으로 성공한 배포의 렌더링된 설정과 현재 설정을 비교할 수 있습니다.

설정 테스트가 잡을 수 없는 것

nginx -t는 새 location 블록이 다른 정규식 위치에 의해 가려졌다고 알려주지 않습니다. 업스트림 앱이 500을 반환한다고 알려주지 않습니다. 리다이렉트 체인이 합리적인지 또는 캐시 규칙이 안전한지 증명하지 않습니다.

이를 위해 동작 검사를 추가하세요:

curl -I https://example.com/
curl -I https://example.com/old-path
curl -sS https://example.com/api/health

TLS 변경의 경우 클라이언트 관점에서 인증서를 확인하세요:

openssl s_client -connect example.com:443 -servername example.com </dev/null

리버스 프록시 변경의 경우 리로드 중 및 후에 로그를 확인하세요:

sudo tail -f /var/log/nginx/error.log /var/log/nginx/access.log

Nginx 설정 테스트는 완전한 배포 전략은 아니지만, 모든 전략이 포함해야 하는 관문입니다. 구문에는 nginx -t, 렌더링된 설정 디버깅에는 nginx -T, 빌드 세부 정보에는 nginx -V, 일반 변경에는 systemctl reload nginx를 사용하세요. 그런 다음 실제 요청으로 동작을 확인하세요.