nginx 설정정리(2)

최준병·2026년 3월 30일

Nginx 서버 설정 완전 정리

Nginx는 고성능 웹 서버이자 리버스 프록시 서버로, 가볍고 빠른 처리 성능으로 널리 사용된다.
이 문서는 실무에서 자주 접하는 핵심 설정들을 정리한다.


목차

  1. 기본 구조
  2. worker 설정
  3. http 블록 핵심 설정
  4. server 블록
  5. location 설정
  6. proxy_pass 설정
  7. HTTPS / SSL 설정
  8. 로드 밸런싱
  9. 정적 파일 서빙
  10. 캐시 설정
  11. 로그 설정
  12. 보안 설정
  13. gzip 압축
  14. 타임아웃 설정

1. 기본 구조

Nginx 설정 파일(nginx.conf)은 블록(block) 단위로 구성된다.

main (전역)
├── events { }         # 연결 처리 방식
└── http { }           # HTTP 관련 설정
    ├── upstream { }   # 로드 밸런싱 대상 서버 그룹
    └── server { }     # 가상 호스트 설정
        └── location { } # 요청 경로별 처리
# nginx.conf 기본 구조

worker_processes auto;

events {
    worker_connections 1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    server {
        listen 80;
        server_name example.com;

        location / {
            root /var/www/html;
            index index.html;
        }
    }
}

2. worker 설정

Nginx는 멀티 프로세스 모델로 동작한다.
master process 1개가 worker process 여러 개를 관리한다.

# CPU 코어 수에 맞게 자동 설정 (권장)
worker_processes auto;

events {
    # worker 하나가 동시에 처리할 수 있는 최대 연결 수
    worker_connections 1024;

    # 여러 연결을 한 번에 수락 (성능 향상)
    multi_accept on;

    # Linux 에서 가장 효율적인 이벤트 처리 방식
    use epoll;
}

💡 최대 동시 처리 가능 연결 수 = worker_processes × worker_connections


3. http 블록 핵심 설정

http {
    # MIME 타입 정의 파일 포함
    include mime.types;
    default_type application/octet-stream;

    # sendfile: OS 커널이 직접 파일 전송 (성능 향상)
    sendfile on;

    # 패킷을 모아서 한 번에 전송 (sendfile on 일때 효과적)
    tcp_nopush on;

    # 작은 패킷도 즉시 전송 (지연 감소)
    tcp_nodelay on;

    # Keep-Alive 연결 유지 시간 (초)
    keepalive_timeout 65;
}

4. server 블록

하나의 Nginx에서 여러 도메인(가상 호스트) 을 운영할 수 있다.

# HTTP 서버
server {
    listen 80;
    server_name example.com www.example.com;

    # ...
}

# 다른 도메인
server {
    listen 80;
    server_name another.com;

    # ...
}

HTTP → HTTPS 리다이렉트

server {
    listen 80;
    server_name example.com;

    return 301 https://$host$request_uri;
}

5. location 설정

매칭 방식 및 우선순위

우선순위기호방식설명
1=Exact Match경로 정확히 일치
2^~Prefix Match (우선)prefix 일치 시 정규식 검사 중단
3~ / ~*Regex Match정규식 일치 (~* 는 대소문자 무시)
4(없음)Prefix Match일반 전방 일치
# ① 정확 일치 (최우선)
location = /health {
    return 200 'OK';
}

# ② prefix 우선 일치 (정규식보다 우선)
location ^~ /static/ {
    root /var/www;
}

# ③ 정규식 일치 (대소문자 구분)
location ~ ^/api/v\d+/ {
    proxy_pass http://localhost:8080;
}

# ③ 정규식 일치 (대소문자 무시)
location ~* \.(jpg|jpeg|png|gif)$ {
    expires 30d;
}

# ④ 일반 prefix 일치
location /app/ {
    proxy_pass http://localhost:3000/;
}

/path vs /path/ 주의사항

location /detector//detector (trailing slash 없음) 요청을 매칭하지 않는다.
두 경우를 모두 처리하려면 아래처럼 설정한다.

location = /detector {
    return 301 /detector/;
}

location /detector/ {
    proxy_pass http://localhost:8080/;
}

6. proxy_pass 설정

trailing slash(/) 의 의미

proxy_pass 끝에 / 가 붙는지 여부에 따라, location prefix를 백엔드로 전달할지 말지가 결정된다.

설정클라이언트 요청백엔드로 전달되는 경로
proxy_pass http://localhost:8080;/detector/api/detector/api (prefix 유지)
proxy_pass http://localhost:8080/;/detector/api/api (prefix 제거)
# prefix 유지: /detector/api → localhost:8080/detector/api
location /detector/ {
    proxy_pass http://localhost:8080;
}

# prefix 제거: /detector/api → localhost:8080/api
location /detector/ {
    proxy_pass http://localhost:8080/;
}

정규식 location에서의 proxy_pass

정규식 location에서는 proxy_pass에 URI(trailing slash 포함)를 명시하면 nginx가 설정 로드 시 에러를 발생시킨다.

# ❌ 설정 에러 발생
location ~ ^/detector/\d+ {
    proxy_pass http://localhost:8080/;
}

# ✅ URI 없이만 사용 가능
location ~ ^/detector/\d+ {
    proxy_pass http://localhost:8080;
}

prefix를 제거하고 싶다면 rewrite 를 사용한다.

location ~ ^/detector/(.*)$ {
    rewrite ^/detector/(.*)$ /$1 break;
    proxy_pass http://localhost:8080;
    # /detector/api/test → localhost:8080/api/test
}

프록시 헤더 설정

리버스 프록시 시 클라이언트 정보를 백엔드로 전달하기 위해 헤더를 설정한다.

location /api/ {
    proxy_pass http://localhost:8080/;

    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클라이언트 실제 IP
X-Forwarded-For프록시를 거친 IP 체인
X-Forwarded-Proto원본 요청 프로토콜 (http/https)

7. HTTPS / SSL 설정

server {
    listen 443 ssl;
    server_name example.com;

    # 인증서 경로
    ssl_certificate     /etc/nginx/ssl/example.com.crt;
    ssl_certificate_key /etc/nginx/ssl/example.com.key;

    # 권장 프로토콜 (구버전 TLS 제외)
    ssl_protocols TLSv1.2 TLSv1.3;

    # 권장 암호화 알고리즘
    ssl_ciphers HIGH:!aNULL:!MD5;

    # 서버 암호화 알고리즘 우선 사용
    ssl_prefer_server_ciphers on;

    # SSL 세션 캐시 (성능 향상)
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;

    location / {
        proxy_pass http://localhost:3000;
    }
}

💡 Let's Encrypt + Certbot 을 사용하면 무료 SSL 인증서를 자동으로 발급/갱신할 수 있다.


8. 로드 밸런싱

여러 백엔드 서버에 트래픽을 분산한다.

upstream backend {
    # 기본: Round Robin (순서대로 분산)
    server 127.0.0.1:8001;
    server 127.0.0.1:8002;
    server 127.0.0.1:8003;
}

server {
    location /api/ {
        proxy_pass http://backend/;
    }
}

로드 밸런싱 방식

upstream backend {
    # least_conn: 연결 수가 가장 적은 서버로 분산
    least_conn;

    server 127.0.0.1:8001;
    server 127.0.0.1:8002;
}
upstream backend {
    # ip_hash: 같은 클라이언트 IP는 항상 같은 서버로 (세션 유지)
    ip_hash;

    server 127.0.0.1:8001;
    server 127.0.0.1:8002;
}
upstream backend {
    # weight: 가중치 설정 (8001이 트래픽 3배 더 받음)
    server 127.0.0.1:8001 weight=3;
    server 127.0.0.1:8002 weight=1;
}

서버 상태 옵션

upstream backend {
    server 127.0.0.1:8001;
    server 127.0.0.1:8002 backup;   # 나머지 서버 장애시에만 사용
    server 127.0.0.1:8003 down;     # 사용 안 함 (점검용)
}

9. 정적 파일 서빙

server {
    listen 80;
    server_name example.com;

    # 루트 디렉토리 지정
    root /var/www/html;

    # 기본 인덱스 파일
    index index.html index.htm;

    location / {
        # 파일 → 디렉토리 → 404 순으로 시도
        try_files $uri $uri/ =404;
    }

    # SPA(React, Vue 등) 라우팅 처리
    location / {
        try_files $uri $uri/ /index.html;
    }
}

특정 확장자 캐싱

location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff2)$ {
    expires 30d;
    add_header Cache-Control "public, no-transform";
}

10. 캐시 설정

프록시 캐시

백엔드 응답을 Nginx가 캐싱하여 백엔드 부하를 줄인다.

http {
    # 캐시 저장 경로 및 옵션 정의
    proxy_cache_path /var/cache/nginx
                     levels=1:2
                     keys_zone=my_cache:10m
                     max_size=1g
                     inactive=60m;

    server {
        location /api/ {
            proxy_pass http://localhost:8080/;
            proxy_cache my_cache;
            proxy_cache_valid 200 10m;   # 200 응답은 10분 캐시
            proxy_cache_valid 404 1m;    # 404 응답은 1분 캐시

            # 캐시 상태를 응답 헤더에 표시 (HIT/MISS/BYPASS)
            add_header X-Cache-Status $upstream_cache_status;
        }
    }
}

11. 로그 설정

http {
    # 로그 포맷 정의
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent"';

    # 접근 로그
    access_log /var/log/nginx/access.log main;

    # 에러 로그 (레벨: debug, info, notice, warn, error, crit)
    error_log /var/log/nginx/error.log warn;

    server {
        # 특정 서버만 로그 비활성화
        access_log off;
    }
}

12. 보안 설정

http {
    # Nginx 버전 정보 숨기기
    server_tokens off;

    server {
        # 클릭재킹 방지
        add_header X-Frame-Options "SAMEORIGIN";

        # XSS 필터 활성화
        add_header X-XSS-Protection "1; mode=block";

        # MIME 타입 스니핑 방지
        add_header X-Content-Type-Options "nosniff";

        # HTTPS 강제 (HSTS)
        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

        # 특정 HTTP 메서드만 허용
        if ($request_method !~ ^(GET|HEAD|POST|PUT|DELETE)$) {
            return 405;
        }
    }
}

요청 크기 제한

http {
    # 클라이언트 요청 body 최대 크기 (파일 업로드 등)
    client_max_body_size 10m;
}

IP 접근 제한

location /admin/ {
    allow 192.168.1.0/24;   # 특정 대역만 허용
    allow 127.0.0.1;
    deny all;               # 나머지 차단
}

13. gzip 압축

응답 데이터를 압축하여 전송 속도를 높인다.

http {
    gzip on;

    # 압축 레벨 (1~9, 높을수록 압축률 높고 CPU 사용량 증가)
    gzip_comp_level 6;

    # 최소 압축 대상 크기 (너무 작은 파일은 압축 불필요)
    gzip_min_length 1000;

    # 압축 대상 MIME 타입
    gzip_types
        text/plain
        text/css
        text/javascript
        application/json
        application/javascript
        application/xml
        image/svg+xml;

    # 프록시 캐시와 함께 사용 시 필요
    gzip_vary on;
}

14. 타임아웃 설정

http {
    # 클라이언트로부터 요청 헤더를 읽는 타임아웃
    client_header_timeout 10s;

    # 클라이언트로부터 요청 body를 읽는 타임아웃
    client_body_timeout 10s;

    # 클라이언트에게 응답을 전송하는 타임아웃
    send_timeout 10s;

    # 프록시 서버 연결 타임아웃
    proxy_connect_timeout 5s;

    # 프록시 서버로부터 응답을 받는 타임아웃
    proxy_read_timeout 60s;

    # 프록시 서버로 요청을 전송하는 타임아웃
    proxy_send_timeout 60s;
}

요약

설정 항목핵심 포인트
workerworker_processes auto + worker_connections 로 동시 처리량 결정
location우선순위: = > ^~ > ~ > prefix
proxy_passtrailing / 유무로 prefix 제거 여부 결정
정규식 locationproxy_pass에 URI 불가 → rewrite 활용
SSLTLSv1.2 이상 사용, Let's Encrypt 권장
로드 밸런싱Round Robin / least_conn / ip_hash / weight
보안server_tokens off, 보안 헤더, IP 제한
성능gzip, sendfile, proxy_cache, keepalive 활용
profile
나의 기록

0개의 댓글