Published on

nginx 설정방법: 기본 구조부터 프록시·HTTPS까지

Authors
  • avatar
    Name
    Indo Yoon
    Twitter

nginx 설정방법의 핵심은 설정 파일의 계층 구조를 먼저 이해하는 것입니다. 최상위 설정에서 이벤트 처리와 http 블록을 열고, 그 안에 server와 location을 배치하면 정적 파일 서비스부터 리버스 프록시까지 대부분의 요구 사항을 해결할 수 있어요. 아래 내용은 nginx 공식 문서에서 확인한 범위를 기준으로 파일 위치, 문법 규칙, 프록시와 HTTPS 적용 순서를 정리한 것입니다.

한눈에 보기

nginx는 하나의 텍스트 설정 파일에 담긴 지시어(directive) 목록으로 동작합니다. 각 지시어는 세미콜론으로 끝나고, 블록 지시어는 중괄호로 범위를 만듭니다. 이 두 가지 규칙만 지켜도 문법 오류의 상당 부분을 줄일 수 있어요.

설정은 위에서 아래로 읽히지만, 실제 적용 범위는 블록의 중첩 관계로 결정됩니다. 상위 블록에서 선언한 값은 하위 블록으로 상속되고, 하위 블록에서 다시 선언하면 그 범위에서만 덮어써요. 그래서 http 블록에 공통 값을 두고 server나 location에서 필요한 부분만 바꾸는 방식이 유지보수에 유리합니다.

설정 파일은 배포판 패키지로 설치했는지, 소스에서 직접 빌드했는지에 따라 위치가 달라집니다. 배포판 패키지는 보통 /etc/nginx/nginx.conf를 진입점으로 두고, conf.d나 sites-enabled 같은 디렉터리를 include로 끌어다 쓰는 구성을 사용해요. 어느 쪽이든 nginx -t로 실제로 읽는 파일 경로와 문법 검사 결과를 확인할 수 있습니다.

설정 파일 구조 비교

블록역할자주 쓰는 지시어주의할 점
main프로세스 전역 동작 정의user, worker_processes, error_log, pid파일 최상단에 한 번만 위치
events연결 처리 방식 정의worker_connectionshttp 블록보다 먼저 선언
httpHTTP 서버 공통 설정include, keepalive_timeout, gzip, log_formatMIME 타입과 로그 형식을 여기서 지정
server가상 호스트 단위listen, server_name, root, return도메인마다 하나씩 두는 구성이 일반적
locationURI 경로별 분기proxy_pass, try_files, alias, rewrite매칭 우선순위를 반드시 확인
upstream백엔드 서버 묶음 정의server, keepalivehttp 블록 안에 선언

표에서 보듯 설정은 "전역 → 연결 → 프로토콜 → 가상 호스트 → 경로"로 좁혀지는 구조입니다. 어디에 어떤 지시어를 넣어야 하는지 헷갈릴 때는 이 계층을 기준으로 되짚어 보면 됩니다.

단계별 설정 방법

설정 파일 위치와 include 구조 확인

먼저 nginx가 어떤 파일을 읽는지 확인합니다. nginx -t를 실행하면 설정 파일 경로와 문법 검사 결과가 함께 출력돼요. 배포판 패키지를 쓴다면 /etc/nginx/nginx.conf가 진입점이고, 그 안의 include 지시어가 추가 파일을 불러옵니다. 소스에서 빌드했다면 기본 경로가 다를 수 있으므로 nginx -V로 컴파일 당시 지정된 경로를 확인하는 편이 안전합니다.

기본 문법 익히기

지시어는 이름 값; 형태로 쓰고 반드시 세미콜론으로 끝냅니다. 블록은 이름 { ... } 형태이며, 블록 안에 다시 블록을 넣을 수 있어요. 주석은 #으로 시작합니다. 문자열에 공백이나 특수문자가 들어가면 따옴표로 감싸고, 정규식은 ~ 또는 ~*를 붙여 표현합니다. 문법 오류가 나면 nginx -t가 문제가 되는 줄 번호를 알려주므로, 수정 후에는 항상 다시 검사하는 습관이 좋습니다.

server 블록 작성

가상 호스트 하나를 server 블록 하나로 생각하면 이해가 빠릅니다. listen으로 받을 포트를, server_name으로 도메인을 지정하고, root로 문서 루트를 잡습니다.

server {
    listen 80;
    server_name example.com;

    root /var/www/example;
    index index.html index.htm;

    access_log /var/log/nginx/example.access.log;
    error_log  /var/log/nginx/example.error.log;
}

server_name은 공백으로 구분해 여러 이름을 나열할 수 있고, 가장 앞에 오는 이름이 기본 이름 역할을 합니다. 도메인이 여러 개라면 server 블록을 나누고, 공통 설정은 http 블록에 두어 중복을 줄이세요.

location 블록으로 경로 분기

location은 요청 URI를 기준으로 처리를 나눕니다. 정적 파일은 try_files로 파일 존재 여부를 확인하고, 없으면 백엔드나 오류 페이지로 넘기는 패턴이 일반적입니다.

location / {
    try_files $uri $uri/ /index.html;
}

location /assets/ {
    expires 7d;
    add_header Cache-Control "public";
}

매칭 방식에는 정확 일치(=), 우선 접두사(^~), 정규식(~, ~*), 일반 접두사가 있고 적용 순서가 정해져 있습니다. 의도한 location이 선택되지 않는다면 이 우선순위를 먼저 확인해 보세요.

리버스 프록시 연결

애플리케이션 서버 앞단에 nginx를 두는 구성에서는 proxy_pass를 사용합니다. 백엔드 주소를 직접 적어도 되고, upstream 블록으로 묶어 이름을 붙여도 됩니다.

upstream app_backend {
    server 127.0.0.1:8080;
    keepalive 32;
}

server {
    listen 80;
    server_name api.example.com;

    location / {
        proxy_pass http://app_backend;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

프록시를 붙일 때 빠뜨리기 쉬운 것이 전달 헤더입니다. Host, X-Real-IP, X-Forwarded-For, X-Forwarded-Proto를 넘겨야 백엔드에서 원래 요청 정보를 알 수 있어요. 백엔드가 리다이렉트 주소를 만들거나 클라이언트 IP를 로깅한다면 이 헤더가 없을 때 결과가 달라집니다.

HTTPS 적용

인증서를 발급받았다면 server 블록을 하나 더 두고 TLS 관련 지시어를 설정합니다. 인증서 경로와 키 경로를 지정하고, 사용할 프로토콜과 암호군은 공식 문서의 권장 예시를 참고해 최신 상태로 유지하세요.

server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate     /etc/nginx/ssl/example.crt;
    ssl_certificate_key /etc/nginx/ssl/example.key;

    root /var/www/example;
    index index.html;
}

HTTP로 들어온 요청은 HTTPS로 넘기는 것이 일반적입니다. 별도 server 블록에서 return 301 https://$host$request_uri;처럼 영구 리다이렉트를 걸어 두면 주소가 하나로 정리돼요.

문법 검사와 무중단 반영

설정을 저장한 뒤에는 반드시 nginx -t로 검사합니다. 통과하면 nginx -s reload로 새 설정을 반영하는데, 이 명령은 기존 연결을 유지한 채 워커 프로세스를 교체하는 방식으로 동작합니다. 문법이 틀린 상태에서 재시작하면 서비스가 중단될 수 있으므로 검사와 반영은 항상 한 쌍으로 처리하세요.

상황별 선택

정적 파일만 제공한다면 server 블록에 root와 try_files만으로 충분합니다. 반면 화면 라우팅을 프런트엔드가 담당하는 구조에서는 try_files $uri $uri/ /index.html;로 모든 경로를 진입 파일로 돌려야 새로고침 시 404가 나지 않아요.

애플리케이션 서버가 따로 있다면 리버스 프록시 구성을 선택합니다. 이때 정적 자원은 nginx가 직접 처리하고 동적 요청만 백엔드로 넘기면 구성이 단순해집니다. 서버가 여러 대라면 upstream에 나열하고 분배 방식을 지정하세요.

도메인이 여러 개라면 server 블록을 도메인별로 나누고 공통 설정은 http 블록이나 별도 파일로 분리합니다. 이때 기본 server를 하나 지정해 두면 알 수 없는 Host로 들어온 요청을 일관되게 처리할 수 있습니다.

주의할 점

가장 흔한 실수는 세미콜론 누락과 중괄호 짝 불일치입니다. nginx -t가 대부분 잡아주지만, 검사 없이 재시작하면 장애로 이어질 수 있어요.

root와 alias의 차이도 자주 발목을 잡습니다. root는 URI를 경로 뒤에 붙이고, alias는 URI를 지정한 경로로 치환합니다. location 경로와 함께 쓸 때 결과가 달라지므로 두 지시어를 섞어 쓰지 않도록 주의하세요.

proxy_pass 뒤의 슬래시 유무도 결과를 바꿉니다. URI가 포함된 형태로 지정하면 매칭된 접두사가 제거되고, 슬래시 없이 호스트만 지정하면 원래 URI가 그대로 전달됩니다. 백엔드에서 경로를 어떻게 받는지 확인한 뒤 결정해야 합니다.

설정 파일 권한과 로그 경로도 점검 대상입니다. 워커 프로세스가 읽을 수 없는 경로를 지정하면 파일은 정상인데 응답이 실패할 수 있고, 이때는 error 로그에 원인이 남습니다.

자주 묻는 질문

nginx 설정 파일은 어디에 있나요?

배포판 패키지로 설치했다면 /etc/nginx/nginx.conf가 기본 진입점이고, 그 안의 include가 conf.d나 sites-enabled 디렉터리를 불러오는 구성이 일반적입니다. 소스에서 직접 빌드했다면 경로가 다를 수 있으므로 nginx -t와 nginx -V로 실제 경로를 확인하는 것이 정확합니다.

설정을 바꾼 뒤에는 재시작해야 하나요?

대부분의 경우 재시작 대신 nginx -s reload로 충분합니다. 기존 연결을 유지하면서 새 설정을 반영하기 때문에 무중단에 가깝게 교체됩니다. 다만 바이너리 자체를 교체했거나 리슨 소켓 구성이 크게 바뀐 경우에는 재시작이 필요할 수 있어요.

proxy_pass 뒤에 슬래시를 붙이는 것과 안 붙이는 차이는 무엇인가요?

URI를 포함해 proxy_pass http://backend/;처럼 슬래시로 끝내면 location과 매칭된 접두사가 제거된 경로가 백엔드로 전달됩니다. 반대로 호스트만 지정하면 원래 요청 URI가 그대로 전달돼요. 백엔드 라우팅이 어느 쪽을 기대하는지 확인하고 하나로 통일하는 것이 안전합니다.

server_name에 도메인을 여러 개 적어도 되나요?

가능합니다. 공백으로 구분해 나열하면 같은 server 블록이 여러 이름에 응답합니다. 다만 가장 앞에 오는 이름이 기본 이름이 되므로, 대표 도메인을 맨 앞에 두는 편이 예측하기 쉽습니다.

백엔드 연결 실패로 오류가 날 때는 어디를 봐야 하나요?

먼저 error 로그에서 업스트림 관련 메시지를 확인합니다. 그다음 proxy_pass에 적은 주소와 포트가 실제로 열려 있는지, 방화벽이나 SELinux 같은 정책이 막고 있지 않은지 점검하세요. 헤더 전달이 빠져 백엔드가 요청을 거부하는 경우도 있으므로 전달 헤더 설정도 함께 확인하는 것이 좋습니다.

출처

설정 파일은 한 번 정리해 두면 이후 배포가 훨씬 편해지므로, 프록시 구성과 함께 무중단 배포나 로그 수집 같은 운영 주제도 같이 살펴보시길 권합니다. 관련 운영 글은 devbull 사이트의 배포·운영 카테고리에서 이어서 확인할 수 있어요.