Nginx 설정 완벽 가이드 - 설치부터 실전 운영까지
Nginx Configuration Complete Guide - From Installation to Production
서론: 왜 Nginx인가
Nginx(엔진엑스)는 전 세계 웹 사이트의 약 34%가 사용하는 웹서버로, Apache와 함께 양대 산맥을 이루고 있습니다. 2004년 러시아 개발자 Igor Sysoev가 C10K 문제(동시 접속 1만 커넥션 처리)를 해결하기 위해 설계한 Nginx는, 이벤트 기반(event-driven) 비동기 아키텍처를 채택하여 적은 메모리로 대량의 동시 접속을 처리할 수 있습니다.
실무에서 Nginx는 단순한 웹서버를 넘어, 리버스 프록시, 로드밸런서, API Gateway, 캐시 서버 등 다양한 역할을 수행합니다. 특히 컨테이너 환경과 마이크로서비스 아키텍처가 보편화되면서 Nginx의 중요성은 더욱 커지고 있습니다.
이 가이드에서는 Nginx의 설치부터 실전 운영에 필요한 모든 설정을 체계적으로 다룹니다. 초보자도 따라할 수 있는 기본 설정부터, 실무에서 반드시 알아야 할 고급 설정까지 실제 설정 파일 예제와 함께 상세히 설명합니다.
1. Nginx 설치
1.1 Ubuntu/Debian 계열 설치
# 패키지 목록 업데이트 후 설치
sudo apt update
sudo apt install nginx -y
# 버전 확인
nginx -v
# 서비스 시작 및 자동 시작 등록
sudo systemctl start nginx
sudo systemctl enable nginx
# 상태 확인
sudo systemctl status nginx
1.2 RHEL/CentOS/Rocky Linux 계열 설치
# EPEL 저장소 추가 (CentOS 7)
sudo yum install epel-release -y
sudo yum install nginx -y
# Rocky Linux 9 / RHEL 9
sudo dnf install nginx -y
# 서비스 시작 및 자동 시작 등록
sudo systemctl start nginx
sudo systemctl enable nginx
# 방화벽 허용
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
1.3 공식 Nginx 저장소에서 최신 버전 설치
배포판 기본 저장소의 Nginx는 버전이 오래된 경우가 많습니다. 최신 기능이 필요하다면 공식 저장소를 추가합니다:
# Ubuntu - Nginx 공식 저장소 추가
sudo apt install curl gnupg2 ca-certificates lsb-release -y
# 서명 키 추가
curl -fsSL https://nginx.org/keys/nginx_signing.key | sudo gpg --dearmor -o /usr/share/keyrings/nginx-archive-keyring.gpg
# 저장소 추가 (stable)
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] http://nginx.org/packages/ubuntu $(lsb_release -cs) nginx" | sudo tee /etc/apt/sources.list.d/nginx.list
# 설치
sudo apt update
sudo apt install nginx -y
mainline(최신 기능, 홀수 버전)과 stable(안정판, 짝수 버전) 두 가지 트랙이 있습니다. 운영 환경에서는 stable을 권장합니다.
1.4 설치 확인
# 브라우저에서 확인: http://서버IP
# 또는 커맨드라인으로 확인
curl -I http://localhost
# 설치 경로 확인
nginx -V # 컴파일 옵션과 모듈 확인
nginx -t # 설정 문법 검증
2. Nginx 디렉토리 구조와 설정 파일
2.1 핵심 디렉토리 구조
| 경로 | 설명 |
|---|---|
/etc/nginx/ |
메인 설정 디렉토리 |
/etc/nginx/nginx.conf |
메인 설정 파일 (모든 설정의 시작점) |
/etc/nginx/conf.d/ |
추가 설정 파일 (*.conf 자동 로드) |
/etc/nginx/sites-available/ |
사용 가능한 사이트 설정 (Ubuntu) |
/etc/nginx/sites-enabled/ |
활성화된 사이트 심볼릭 링크 (Ubuntu) |
/etc/nginx/mime.types |
MIME 타입 매핑 |
/var/log/nginx/access.log |
접속 로그 |
/var/log/nginx/error.log |
에러 로그 |
/var/www/html/ |
기본 웹 루트 디렉토리 |
/usr/share/nginx/html/ |
기본 웹 루트 (RHEL 계열) |
2.2 nginx.conf 기본 구조
Nginx 설정은 블록(block) 구조로 이루어져 있으며, 계층적으로 중첩됩니다:
# === 전역 컨텍스트 (Main Context) ===
user nginx; # 워커 프로세스 실행 사용자
worker_processes auto; # 워커 프로세스 수 (auto = CPU 코어 수)
error_log /var/log/nginx/error.log warn; # 에러 로그 경로 및 레벨
pid /run/nginx.pid; # PID 파일 경로
# === 이벤트 컨텍스트 ===
events {
worker_connections 1024; # 워커당 최대 동시 연결 수
use epoll; # 이벤트 처리 방식 (Linux)
multi_accept on; # 한 번에 여러 연결 수락
}
# === HTTP 컨텍스트 ===
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# 로그 형식 정의
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;
sendfile on; # 커널 레벨 파일 전송
tcp_nopush on; # sendfile과 함께 사용
tcp_nodelay on; # 소량 패킷 지연 방지
keepalive_timeout 65; # 연결 유지 시간
# gzip 압축
gzip on;
gzip_types text/plain text/css application/json application/javascript;
# 추가 설정 파일 로드
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*; # Ubuntu 방식
}
nginx -t로 문법을 검증하고, sudo systemctl reload nginx로 적용하세요. restart 대신 reload를 사용하면 서비스 중단 없이 설정을 반영할 수 있습니다.
3. Server Block (가상 호스트) 설정
Server Block은 Apache의 VirtualHost에 해당하며, 하나의 Nginx 서버에서 여러 도메인(사이트)을 운영할 수 있게 합니다.
3.1 기본 정적 웹사이트
# /etc/nginx/conf.d/example.com.conf
server {
listen 80; # IPv4 포트
listen [::]:80; # IPv6 포트
server_name example.com www.example.com;
root /var/www/example.com/html; # 문서 루트
index index.html index.htm; # 기본 인덱스 파일
# 기본 location
location / {
try_files $uri $uri/ =404; # 파일 → 디렉토리 → 404
}
# 에러 페이지 커스터마이징
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# 로그 설정 (사이트별 분리)
access_log /var/log/nginx/example.com.access.log;
error_log /var/log/nginx/example.com.error.log;
}
# 웹 루트 디렉토리 생성
sudo mkdir -p /var/www/example.com/html
sudo chown -R $USER:$USER /var/www/example.com/html
# 테스트 페이지 생성
echo "<h1>Welcome to example.com</h1>" > /var/www/example.com/html/index.html
# 설정 검증 및 적용
sudo nginx -t
sudo systemctl reload nginx
3.2 Ubuntu의 sites-available / sites-enabled 패턴
# 설정 파일 생성
sudo nano /etc/nginx/sites-available/example.com
# 심볼릭 링크로 활성화
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
# 기본 사이트 비활성화 (필요 시)
sudo rm /etc/nginx/sites-enabled/default
# 적용
sudo nginx -t
sudo systemctl reload nginx
3.3 여러 도메인 운영 (멀티 사이트)
# 사이트 A: /etc/nginx/conf.d/site-a.conf
server {
listen 80;
server_name site-a.com www.site-a.com;
root /var/www/site-a/html;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
# 사이트 B: /etc/nginx/conf.d/site-b.conf
server {
listen 80;
server_name site-b.com www.site-b.com;
root /var/www/site-b/html;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
# 기본 서버 (매칭 안 되는 요청 처리)
server {
listen 80 default_server;
server_name _;
return 444; # 연결 종료 (응답 없이)
}
4. Location 블록 - URL 매칭의 핵심
location 블록은 Nginx 설정에서 가장 자주 사용되고 가장 중요한 디렉티브입니다. URL 경로에 따라 서로 다른 처리를 할 수 있습니다.
4.1 매칭 방식과 우선순위
| 문법 | 매칭 방식 | 우선순위 |
|---|---|---|
= /path |
정확히 일치 (Exact Match) | 1순위 (최우선) |
^~ /path |
접두사 일치 (정규식 검색 안 함) | 2순위 |
~ /regex |
정규표현식 (대소문자 구분) | 3순위 |
~* /regex |
정규표현식 (대소문자 무시) | 3순위 |
/path |
접두사 일치 (가장 긴 매칭) | 4순위 (기본) |
4.2 실전 Location 예제
server {
listen 80;
server_name example.com;
root /var/www/example.com;
# 정확히 루트 경로만 매칭
location = / {
# 메인 페이지 전용 처리
try_files /index.html =404;
}
# /api/ 로 시작하는 경로 → 백엔드 프록시
location /api/ {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# 정적 파일 (이미지, CSS, JS)
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff2?)$ {
expires 30d; # 30일 캐시
add_header Cache-Control "public, immutable";
access_log off; # 정적 파일 로그 비활성화
}
# PHP 파일 처리
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# 숨김 파일 접근 차단 (.htaccess, .git 등)
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
# favicon.ico 404 로그 방지
location = /favicon.ico {
log_not_found off;
access_log off;
}
# robots.txt
location = /robots.txt {
log_not_found off;
access_log off;
}
}
=(정확) → ^~(접두사 우선) → ~/~*(정규식) → 일반 접두사. 정확한 이해가 없으면 예상치 못한 라우팅 문제가 발생할 수 있습니다.
5. 리버스 프록시 설정
리버스 프록시는 Nginx의 가장 강력한 기능 중 하나입니다. 클라이언트의 요청을 백엔드 서버(Node.js, Python, Java 등)로 전달하고 응답을 반환합니다.
5.1 기본 리버스 프록시
# Node.js 앱 프록시 (포트 3000)
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://127.0.0.1:3000;
# 필수 헤더 전달
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;
# 타임아웃 설정
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
# 버퍼 설정
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
}
}
5.2 WebSocket 프록시
# WebSocket 지원이 필요한 경우 (채팅, 실시간 앱)
server {
listen 80;
server_name ws.example.com;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
# WebSocket 업그레이드 헤더
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# WebSocket 연결 유지 시간
proxy_read_timeout 86400s; # 24시간
proxy_send_timeout 86400s;
}
}
5.3 경로별 다중 백엔드 프록시
# 마이크로서비스 라우팅
server {
listen 80;
server_name example.com;
# 프론트엔드 (React/Vue SPA)
location / {
root /var/www/frontend/dist;
try_files $uri $uri/ /index.html; # SPA 라우팅
}
# API 서버 (Node.js)
location /api/ {
proxy_pass http://127.0.0.1:3000/; # 마지막 / 중요!
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# 인증 서버 (Python)
location /auth/ {
proxy_pass http://127.0.0.1:5000/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# 파일 업로드 서버 (별도 크기 제한)
location /upload/ {
client_max_body_size 100M; # 업로드 최대 100MB
proxy_pass http://127.0.0.1:4000/;
proxy_set_header Host $host;
}
}
proxy_pass URL의 마지막 슬래시(/)에 주의하세요. proxy_pass http://backend/;는 location 경로를 제거하고 전달하며, proxy_pass http://backend;(슬래시 없음)는 location 경로를 포함하여 전달합니다.
6. 로드밸런싱
여러 백엔드 서버에 트래픽을 분산하여 고가용성과 성능을 확보합니다.
6.1 로드밸런싱 방식
# === Round Robin (기본) ===
# 순서대로 번갈아가며 요청 분배
upstream backend_rr {
server 192.168.1.10:8080;
server 192.168.1.11:8080;
server 192.168.1.12:8080;
}
# === Weighted Round Robin ===
# 서버 성능에 따라 가중치 부여
upstream backend_weighted {
server 192.168.1.10:8080 weight=5; # 5배 더 많은 요청
server 192.168.1.11:8080 weight=3;
server 192.168.1.12:8080 weight=1;
}
# === Least Connections ===
# 가장 연결이 적은 서버에 분배
upstream backend_lc {
least_conn;
server 192.168.1.10:8080;
server 192.168.1.11:8080;
server 192.168.1.12:8080;
}
# === IP Hash ===
# 같은 클라이언트 IP는 항상 같은 서버로 (세션 유지)
upstream backend_hash {
ip_hash;
server 192.168.1.10:8080;
server 192.168.1.11:8080;
server 192.168.1.12:8080;
}
# 로드밸런서 적용
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://backend_rr;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
6.2 헬스체크와 장애 대응
upstream backend {
server 192.168.1.10:8080 max_fails=3 fail_timeout=30s;
server 192.168.1.11:8080 max_fails=3 fail_timeout=30s;
server 192.168.1.12:8080 backup; # 백업 서버 (다른 서버 모두 실패 시 사용)
server 192.168.1.13:8080 down; # 수동으로 비활성화
# max_fails=3: 3번 실패하면 해당 서버를 비활성화
# fail_timeout=30s: 30초 후 다시 시도
# backup: 다른 모든 서버가 다운될 때만 사용
# down: 영구적으로 비활성화 (유지보수용)
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://backend;
proxy_next_upstream error timeout http_500 http_502 http_503;
proxy_next_upstream_tries 3; # 최대 3번 다른 서버 시도
proxy_next_upstream_timeout 10s; # 타임아웃
}
}
7. HTTPS / SSL 설정
7.1 Let's Encrypt 무료 인증서 발급
# Certbot 설치
sudo apt install certbot python3-certbot-nginx -y # Ubuntu
sudo dnf install certbot python3-certbot-nginx -y # Rocky/RHEL
# 인증서 발급 (Nginx 자동 설정)
sudo certbot --nginx -d example.com -d www.example.com
# 인증서 자동 갱신 테스트
sudo certbot renew --dry-run
# 자동 갱신 크론 확인
sudo systemctl status certbot.timer
7.2 SSL 수동 설정 (최적화 포함)
# /etc/nginx/conf.d/example.com.conf
server {
listen 80;
server_name example.com www.example.com;
# HTTP → HTTPS 리다이렉트
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com www.example.com;
# SSL 인증서 경로
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# SSL 프로토콜 (TLS 1.2 이상만 허용)
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
# SSL 세션 캐시 (핸드셰이크 성능 향상)
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
# OCSP Stapling (인증서 검증 속도 향상)
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
# 보안 헤더
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Frame-Options DENY always;
add_header X-Content-Type-Options nosniff always;
add_header X-XSS-Protection "1; mode=block" always;
root /var/www/example.com/html;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
8. 보안 설정
8.1 기본 보안 강화
# /etc/nginx/conf.d/security.conf (공통 보안 설정)
# Nginx 버전 정보 숨기기
server_tokens off;
# 요청 크기 제한 (기본 1MB)
client_max_body_size 10M;
# 요청 헤더/바디 타임아웃
client_header_timeout 10s;
client_body_timeout 10s;
send_timeout 10s;
# 버퍼 오버플로우 공격 방지
client_body_buffer_size 1K;
client_header_buffer_size 1k;
large_client_header_buffers 2 1k;
8.2 IP 기반 접근 제어
# 관리자 페이지 IP 제한
location /admin/ {
allow 10.0.0.0/8; # 내부 네트워크 허용
allow 192.168.1.100; # 특정 IP 허용
deny all; # 나머지 차단
proxy_pass http://127.0.0.1:8080;
}
# 특정 국가/IP 대역 차단
# geo 모듈 활용
geo $blocked_ip {
default 0;
1.2.3.0/24 1; # 차단할 IP 대역
5.6.7.0/24 1;
}
server {
if ($blocked_ip) {
return 403;
}
}
8.3 Rate Limiting (요청 제한)
# http 블록에서 zone 정의
http {
# IP당 초당 10개 요청으로 제한
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
# IP당 동시 연결 수 제한
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
}
# server 블록에서 적용
server {
# API에 Rate Limit 적용
location /api/ {
limit_req zone=api_limit burst=20 nodelay;
# burst=20: 순간 20개까지 허용
# nodelay: 초과분을 즉시 처리 (대기하지 않음)
limit_req_status 429; # 제한 초과 시 429 응답
proxy_pass http://backend;
}
# 로그인 페이지 (더 엄격한 제한)
location /login {
limit_req zone=api_limit burst=5;
limit_conn conn_limit 5; # 동시 5개 연결로 제한
proxy_pass http://backend;
}
}
8.4 봇/스크래퍼 차단
# 악성 User-Agent 차단
if ($http_user_agent ~* (scrapy|curl|wget|python-requests|httpclient|Go-http-client)) {
return 403;
}
# 빈 User-Agent 차단
if ($http_user_agent = "") {
return 403;
}
# 특정 리퍼러 차단 (핫링크 방지)
location ~* \.(jpg|jpeg|png|gif|webp)$ {
valid_referers none blocked server_names *.example.com;
if ($invalid_referer) {
return 403;
}
}
9. 성능 최적화
9.1 Gzip 압축
http {
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6; # 압축 레벨 (1-9, 6 권장)
gzip_min_length 256; # 256바이트 이상만 압축
gzip_types
text/plain
text/css
text/xml
text/javascript
application/json
application/javascript
application/xml
application/rss+xml
application/atom+xml
image/svg+xml
font/woff
font/woff2;
}
9.2 정적 파일 캐싱
# 정적 리소스 브라우저 캐싱
location ~* \.(jpg|jpeg|png|gif|ico|webp|avif)$ {
expires 365d;
add_header Cache-Control "public, immutable";
access_log off;
}
location ~* \.(css|js)$ {
expires 30d;
add_header Cache-Control "public";
access_log off;
}
location ~* \.(woff|woff2|ttf|otf|eot)$ {
expires 365d;
add_header Cache-Control "public, immutable";
access_log off;
add_header Access-Control-Allow-Origin "*"; # CORS (폰트)
}
location ~* \.(html|htm)$ {
expires 1h;
add_header Cache-Control "public, must-revalidate";
}
9.3 프록시 캐싱
http {
# 프록시 캐시 영역 정의
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m
max_size=1g inactive=60m use_temp_path=off;
server {
location / {
proxy_pass http://backend;
# 캐시 활성화
proxy_cache my_cache;
proxy_cache_valid 200 302 10m; # 200, 302 → 10분 캐시
proxy_cache_valid 404 1m; # 404 → 1분 캐시
# 캐시 상태 헤더 (디버깅용)
add_header X-Cache-Status $upstream_cache_status;
# 캐시 바이패스 조건
proxy_cache_bypass $http_cache_control;
proxy_no_cache $http_pragma;
}
}
}
9.4 Worker 프로세스 튜닝
# CPU 코어 수에 맞게 설정
worker_processes auto; # 자동 감지 (권장)
events {
worker_connections 4096; # 서버 규모에 따라 조정
use epoll; # Linux 최적 이벤트 모델
multi_accept on;
}
http {
# 파일 디스크립터 캐싱
open_file_cache max=10000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
}
# OS 레벨 튜닝 (커널 파라미터)
# /etc/sysctl.conf에 추가
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_tw_reuse = 1
# 워커 프로세스의 파일 디스크립터 제한
# /etc/security/limits.conf
# nginx soft nofile 65535
# nginx hard nofile 65535
# 또는 nginx.conf의 전역 컨텍스트에서:
worker_rlimit_nofile 65535;
10. 로그 설정과 모니터링
10.1 커스텀 로그 형식
http {
# 상세 로그 형식 (응답시간 포함)
log_format detailed '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'$request_time $upstream_response_time';
# JSON 형식 로그 (ELK/Loki 연동에 유용)
log_format json_log escape=json '{'
'"time":"$time_iso8601",'
'"remote_addr":"$remote_addr",'
'"request":"$request",'
'"status":$status,'
'"body_bytes_sent":$body_bytes_sent,'
'"request_time":$request_time,'
'"upstream_response_time":"$upstream_response_time",'
'"http_referer":"$http_referer",'
'"http_user_agent":"$http_user_agent"'
'}';
# 조건부 로그 (2xx 응답은 로그하지 않기)
map $status $loggable {
~^[23] 0;
default 1;
}
server {
access_log /var/log/nginx/access.log detailed;
# access_log /var/log/nginx/access.json json_log if=$loggable;
}
}
10.2 로그 로테이션
# /etc/logrotate.d/nginx
/var/log/nginx/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
create 0640 www-data adm
sharedscripts
postrotate
[ -f /var/run/nginx.pid ] && kill -USR1 $(cat /var/run/nginx.pid)
endscript
}
10.3 Nginx 상태 모니터링 (stub_status)
# 내부에서만 접근 가능한 상태 페이지
server {
listen 8080;
server_name localhost;
location /nginx_status {
stub_status on;
allow 127.0.0.1;
allow 10.0.0.0/8;
deny all;
}
}
# 출력 예시:
# Active connections: 291
# server accepts handled requests
# 16630948 16630948 31070465
# Reading: 6 Writing: 179 Waiting: 106
# 상태 확인
curl http://localhost:8080/nginx_status
# Prometheus 연동 시 nginx-prometheus-exporter 사용
# docker run -p 9113:9113 nginx/nginx-prometheus-exporter -nginx.scrape-uri=http://host:8080/nginx_status
11. 실전 운영 팁
11.1 자주 쓰는 명령어 모음
# 설정 문법 검증 (수정 후 반드시 실행!)
sudo nginx -t
# 서비스 중단 없이 설정 적용
sudo systemctl reload nginx
# 서비스 재시작 (중단됨)
sudo systemctl restart nginx
# 로그 실시간 모니터링
tail -f /var/log/nginx/access.log
tail -f /var/log/nginx/error.log
# 특정 상태코드만 필터
tail -f /var/log/nginx/access.log | grep --line-buffered '" 500 '
# 연결 상태 확인
ss -tlnp | grep nginx
# 현재 활성 연결 수
ss -s | head -5
# Nginx 마스터/워커 프로세스 확인
ps aux | grep nginx
# 설정 파일 경로 및 모듈 확인
nginx -V 2>&1 | tr ' ' '\n' | grep -E "^--"
11.2 무중단 설정 변경 절차
# 1. 설정 파일 수정
sudo nano /etc/nginx/conf.d/example.com.conf
# 2. 문법 검증 (필수!)
sudo nginx -t
# nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
# nginx: configuration file /etc/nginx/nginx.conf test is successful
# 3. reload로 적용 (다운타임 없음)
sudo systemctl reload nginx
# 만약 문법 오류가 있다면:
# nginx: [emerg] unknown directive "servr" in /etc/nginx/conf.d/example.com.conf:2
# nginx: configuration file /etc/nginx/nginx.conf test failed
# → reload하지 말고 오류를 수정!
11.3 흔한 실수와 해결법
| 증상 | 원인 | 해결 |
|---|---|---|
| 502 Bad Gateway | 백엔드 서버 다운 또는 소켓 오류 | 백엔드 프로세스 확인, proxy_pass 주소 확인 |
| 504 Gateway Timeout | 백엔드 응답 지연 | proxy_read_timeout 값 증가 |
| 413 Request Entity Too Large | 업로드 크기 초과 | client_max_body_size 값 증가 |
| 403 Forbidden | 파일 권한 또는 SELinux | 파일 소유자/권한 확인, SELinux 컨텍스트 확인 |
| 301 리다이렉트 루프 | HTTP↔HTTPS 설정 충돌 | server 블록 분리, $scheme 조건 확인 |
| 실시간 로그가 안 나옴 | access_log off; 또는 버퍼링 |
location 블록의 로그 설정 확인 |
12. 설정 파일 체크리스트
운영 서버에 Nginx를 배포하기 전에 다음 항목을 반드시 점검하세요:
- 기본 보안:
server_tokens off;설정 여부 - HTTPS: 모든 HTTP 트래픽이 HTTPS로 리다이렉트되는지
- SSL 프로토콜: TLS 1.2 이상만 허용하는지
- 보안 헤더: HSTS, X-Frame-Options, X-Content-Type-Options 설정
- 파일 접근:
.git,.env등 숨김 파일 차단 여부 - 업로드 제한:
client_max_body_size적절한 값 설정 - Rate Limiting: API, 로그인 등 민감한 경로에 제한 설정
- Gzip 압축: 텍스트 기반 응답에 압축 활성화
- 캐싱: 정적 파일에 적절한
expires설정 - 로그: 사이트별 로그 분리 및 로테이션 설정
- Default Server: 매칭되지 않는 요청 처리 (
return 444;) - 타임아웃:
proxy_read_timeout등 적절한 타임아웃 설정 - 백업: 설정 파일의 백업 및 버전 관리 (Git 추천)
결론: Nginx는 설정이 곧 실력이다
Nginx는 설치는 쉽지만 제대로 운영하려면 설정에 대한 깊은 이해가 필요합니다. 이 가이드에서 다룬 내용은 실무에서 가장 자주 마주치는 시나리오를 기반으로 구성했습니다.
핵심 포인트를 정리하면 다음과 같습니다:
- 기본기부터 탄탄히 -
nginx.conf의 블록 구조와 상속 관계를 이해하세요. - location 우선순위를 외워라 -
=→^~→~/~*→ 일반 접두사. 이것만 알아도 대부분의 라우팅 문제를 해결할 수 있습니다. - 변경 전 반드시
nginx -t- 설정 오류는 서비스 장애로 직결됩니다. 문법 검증은 선택이 아닌 필수입니다. - reload ≠ restart -
reload는 무중단 반영,restart는 서비스 중단이 발생합니다. - 보안은 처음부터 - HTTPS, 보안 헤더, Rate Limiting은 운영 시작 전에 설정하세요.
- 로그는 자산이다 - 커스텀 로그 형식을 설정하고, 정기적으로 분석하면 장애 예방과 성능 개선에 큰 도움이 됩니다.
이 가이드의 설정 예제를 자신의 환경에 맞게 수정하여 적용해 보세요. 실전 경험이 쌓일수록 Nginx 설정은 점점 자연스러워지고, 복잡한 아키텍처도 자신 있게 구성할 수 있게 될 것입니다.