Repository navigation
Wiki_BE_Nginx
본 문서는 백엔드 개발에 투입되는 신입 개발자를 위해 작성되었습니다.
Nginx의 핵심 개념, 설정 방법, 자주 쓰는 명령어를 실무 중심으로 정리합니다.
- Nginx란?
- 설치 및 기본 명령어
- 디렉토리 및 파일 구조
- 설정 파일 문법 기초
- 정적 파일 서빙
- 리버스 프록시 설정
- 로드 밸런싱
- HTTPS 설정 (SSL/TLS)
- 로그 확인 및 디버깅
- 실무 설정 예시 모음
Nginx(엔진엑스) 는 고성능 웹 서버이자 리버스 프록시 서버입니다. 백엔드 서버 앞단에 위치하여 다음 역할을 수행합니다.
인터넷 (클라이언트)
│
▼
┌──────────┐
│ Nginx │ ← 웹 서버 / 리버스 프록시 / 로드 밸런서
└──────────┘
│
┌─────┴──────┐
▼ ▼
[서버 1] [서버 2] ← 실제 백엔드 애플리케이션
(FastAPI) (Flask)
Nginx가 하는 일:
| 역할 | 설명 |
|---|---|
| 웹 서버 | HTML, CSS, JS, 이미지 등 정적 파일 직접 서빙 |
| 리버스 프록시 | 클라이언트 요청을 백엔드 서버로 전달 |
| 로드 밸런서 | 여러 백엔드 서버에 트래픽 분산 |
| SSL 터미네이션 | HTTPS 처리를 Nginx가 담당, Web Application Server는 HTTP만 처리 |
| 캐시 서버 | 응답을 캐싱하여 백엔드 부하 감소 |
# 패키지 목록 업데이트
sudo apt update
# Nginx 설치
sudo apt install -y nginx
# 설치 확인
nginx -v
# 출력 예시: nginx version: nginx/1.24.0실제 서버에서는 systemctl 로 Nginx를 관리합니다.
# Nginx 시작
sudo systemctl start nginx
# Nginx 중지
sudo systemctl stop nginx
# Nginx 재시작 (설정 변경 후 완전 재시작 - 짧은 다운타임 발생)
sudo systemctl restart nginx
# Nginx 리로드 (설정 변경 후 무중단 적용 - 실무에서 주로 사용)
sudo systemctl reload nginx
# 서버 부팅 시 Nginx 자동 시작 등록
sudo systemctl enable nginx
# 자동 시작 해제
sudo systemctl disable nginx
# 현재 상태 확인
sudo systemctl status nginxrestart vs reload 차이:
| 명령어 | 동작 | 다운타임 |
|---|---|---|
restart |
프로세스 완전 종료 후 재시작 | 있음 (짧은 순간) |
reload |
설정만 다시 읽음, 프로세스 유지 | 없음 ✅ |
실무 팁: 설정 변경 후에는 반드시
reload를 사용하십시오.restart는 서비스가 잠깐 중단됩니다.
# 설정 파일 문법 검사 (적용 전 반드시 실행)
sudo nginx -t
# 설정 파일 문법 검사 + 상세 출력
sudo nginx -T
# 설정 리로드 (systemctl reload와 동일)
sudo nginx -s reload
# Nginx 정상 종료 (현재 처리 중인 요청 완료 후 종료)
sudo nginx -s quit
# Nginx 즉시 강제 종료
sudo nginx -s stop
# 특정 설정 파일 지정하여 실행
sudo nginx -c /etc/nginx/nginx.conf
⚠️ 주의: 설정 파일 수정 후nginx -t로 반드시 문법을 검사한 뒤 적용하십시오.
문법 오류가 있는 상태로reload하면 Nginx가 중단될 수 있습니다.
# 올바른 설정 변경 절차
sudo vi /etc/nginx/sites-available/myapp.conf # 1. 설정 수정
sudo nginx -t # 2. 문법 검사
sudo systemctl reload nginx # 3. 문제 없으면 적용/etc/nginx/
├── nginx.conf ← 메인 설정 파일
├── sites-available/ ← 사용 가능한 사이트 설정 보관
│ ├── default
│ └── myapp.conf
├── sites-enabled/ ← 실제 활성화된 사이트 설정 (심볼릭 링크)
│ └── myapp.conf -> ../sites-available/myapp.conf
├── conf.d/ ← 추가 설정 파일 (자동 로드)
│ └── gzip.conf
├── snippets/ ← 재사용 가능한 설정 조각
│ └── ssl-params.conf
└── mime.types ← 파일 확장자 ↔ MIME 타입 매핑
주요 로그 파일:
/var/log/nginx/
├── access.log ← 모든 요청 기록
└── error.log ← 오류 기록
기본 정적 파일 경로:
/var/www/html/ ← Nginx 기본 웹 루트 디렉토리
└── index.nginx-debian.html
Nginx는 sites-available에 설정을 작성하고, sites-enabled에 심볼릭 링크를 걸어 활성화합니다.
# 사이트 활성화 (심볼릭 링크 생성)
sudo ln -s /etc/nginx/sites-available/myapp.conf /etc/nginx/sites-enabled/
# 사이트 비활성화 (심볼릭 링크 제거)
sudo rm /etc/nginx/sites-enabled/myapp.conf
# 변경 사항 적용
sudo nginx -t && sudo systemctl reload nginxNginx 설정은 블록(Block) 과 지시어(Directive) 로 구성됩니다.
# 전역 블록 (nginx.conf 최상단)
worker_processes auto;
# events 블록
events {
worker_connections 1024;
}
# http 블록
http {
# server 블록 (가상 호스트)
server {
listen 80;
server_name example.com;
# location 블록 (URL 경로별 처리)
location / {
root /var/www/html;
index index.html;
}
}
}http
└── server ← 도메인/포트 단위 설정
└── location ← URL 경로 단위 설정
| 지시어 | 설명 | 예시 |
|---|---|---|
listen |
수신 포트 | listen 80; |
server_name |
처리할 도메인 | server_name example.com; |
root |
정적 파일 루트 경로 | root /var/www/html; |
index |
기본 인덱스 파일 | index index.html; |
proxy_pass |
프록시 대상 서버 | proxy_pass http://localhost:8080; |
return |
리다이렉트 또는 응답 반환 | return 301 https://$host$request_uri; |
include |
다른 설정 파일 포함 | include /etc/nginx/conf.d/*.conf; |
URL 경로를 매칭하는 방법에는 우선순위가 있습니다.
# 1순위: = (완전 일치)
location = /favicon.ico { ... }
# 2순위: ^~ (접두어 일치, 정규식 탐색 중단)
location ^~ /images/ { ... }
# 3순위: ~ (정규식, 대소문자 구분)
location ~ \.php$ { ... }
# 4순위: ~* (정규식, 대소문자 무시)
location ~* \.(jpg|jpeg|png|gif)$ { ... }
# 5순위: / (접두어 일치, 기본값)
location / { ... }실무에서 자주 쓰는 패턴:
server {
listen 80;
server_name example.com;
# 정적 파일은 Nginx가 직접 처리
location ~* \.(html|css|js|png|jpg|gif|ico|svg|woff2)$ {
root /var/www/html;
expires 30d; # 브라우저 캐시 30일
}
# API 요청은 백엔드로 전달
location /api/ {
proxy_pass http://localhost:8080;
}
# 그 외 모든 요청
location / {
root /var/www/html;
try_files $uri $uri/ /index.html; # SPA 대응
}
}Nginx 설정에서 자주 사용하는 내장 변수입니다.
| 변수 | 의미 |
|---|---|
$host |
요청의 Host 헤더 값 |
$request_uri |
요청 URI (쿼리스트링 포함) |
$uri |
요청 URI (쿼리스트링 제외) |
$remote_addr |
클라이언트 IP 주소 |
$args |
쿼리스트링 |
$scheme |
프로토콜 (http 또는 https) |
$server_port |
서버 포트 번호 |
$upstream_addr |
프록시 대상 서버 주소 |
가장 기본적인 Nginx 사용 사례입니다.
server {
listen 80;
server_name example.com www.example.com;
root /var/www/myapp;
index index.html index.htm;
location / {
try_files $uri $uri/ =404;
# $uri : 해당 파일 시도
# $uri/ : 디렉토리 시도
# =404 : 없으면 404 반환
}
# 정적 파일 캐시 설정
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf)$ {
expires 1y; # 1년 캐시
add_header Cache-Control "public";
}
}파일 권한 설정:
# Nginx가 파일을 읽을 수 있도록 권한 설정
sudo chown -R www-data:www-data /var/www/myapp
sudo chmod -R 755 /var/www/myapp백엔드 서버(Spring Boot, Node.js, Django 등)로 요청을 전달하는 설정입니다.
server {
listen 80;
server_name api.example.com;
location / {
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;
# 타임아웃 설정
proxy_connect_timeout 60s; # 백엔드 연결 대기 시간
proxy_read_timeout 60s; # 백엔드 응답 대기 시간
proxy_send_timeout 60s; # 백엔드로 전송 대기 시간
}
}헤더 설명:
| 헤더 | 역할 |
|---|---|
X-Real-IP |
실제 클라이언트 IP를 백엔드에 전달 |
X-Forwarded-For |
프록시 체인 전체 IP 목록 전달 |
X-Forwarded-Proto |
원본 프로토콜(http/https) 전달 |
Host |
원본 도메인 전달 |
실무 팁: 백엔드 애플리케이션에서 클라이언트 IP를 가져올 때
request.getRemoteAddr()대신X-Real-IP또는X-Forwarded-For헤더를 사용해야 합니다. Nginx를 거치면RemoteAddr은 Nginx의 IP가 됩니다.
여러 백엔드 서버로 트래픽을 분산합니다.
http {
# upstream 블록: 백엔드 서버 그룹 정의
upstream backend_servers {
server 192.168.1.101:8080;
server 192.168.1.102:8080;
server 192.168.1.103:8080;
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://backend_servers; # upstream 그룹으로 전달
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}upstream backend_servers {
# 1. Round Robin (기본값): 순서대로 분산
server 192.168.1.101:8080;
server 192.168.1.102:8080;
# 2. Least Connections: 연결 수가 가장 적은 서버에 분산
# least_conn;
# server 192.168.1.101:8080;
# server 192.168.1.102:8080;
# 3. IP Hash: 같은 클라이언트 IP는 항상 같은 서버로 (세션 유지)
# ip_hash;
# server 192.168.1.101:8080;
# server 192.168.1.102:8080;
# 4. Weight: 가중치로 분산 비율 조정 (3:1 비율)
# server 192.168.1.101:8080 weight=3;
# server 192.168.1.102:8080 weight=1;
}upstream backend_servers {
server 192.168.1.101:8080;
server 192.168.1.102:8080 backup; # 다른 서버 모두 다운 시에만 사용
server 192.168.1.103:8080 down; # 임시 비활성화
server 192.168.1.104:8080 max_fails=3 fail_timeout=30s;
# max_fails : 실패 횟수 초과 시 비정상 처리
# fail_timeout : 비정상 처리 유지 시간
}# Certbot 설치
sudo apt install -y certbot python3-certbot-nginx
# 인증서 발급 및 Nginx 자동 설정
sudo certbot --nginx -d example.com -d www.example.com
# 인증서 갱신 테스트 (90일마다 자동 갱신됨)
sudo certbot renew --dry-run
# 인증서 목록 확인
sudo certbot certificates# HTTP → HTTPS 리다이렉트
server {
listen 80;
server_name example.com www.example.com;
# 모든 HTTP 요청을 HTTPS로 리다이렉트
return 301 https://$host$request_uri;
}
# HTTPS 서버
server {
listen 443 ssl;
server_name example.com www.example.com;
# SSL 인증서 경로 (Certbot이 자동 생성)
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# 권장 SSL 설정
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
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;
}
}# 접근 로그 실시간 출력
sudo tail -f /var/log/nginx/access.log
# 에러 로그 실시간 출력
sudo tail -f /var/log/nginx/error.log
# 마지막 100줄 출력
sudo tail -n 100 /var/log/nginx/error.log
# 특정 단어 포함 로그 필터링
sudo grep "500" /var/log/nginx/access.log
sudo grep "error" /var/log/nginx/error.log기본 access.log 포맷:
192.168.1.1 - - [01/Jan/2024:12:00:00 +0900] "GET /api/users HTTP/1.1" 200 512 "-" "Mozilla/5.0"
│ │ │ │ │
클라이언트 IP 시간 메서드+경로 상태코드 응답크기
http {
# 커스텀 로그 포맷 정의
log_format custom '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'rt=$request_time uct=$upstream_connect_time '
'urt=$upstream_response_time';
# 특정 서버에 적용
server {
access_log /var/log/nginx/myapp_access.log custom;
error_log /var/log/nginx/myapp_error.log warn;
# 로그 레벨: debug | info | notice | warn | error | crit
}
}# 1. 설정 파일 문법 검사
sudo nginx -t
# 2. Nginx 상태 확인
sudo systemctl status nginx
# 3. 포트 사용 현황 확인 (80, 443 포트 리스닝 여부)
sudo ss -tlnp | grep nginx
# 또는
sudo netstat -tlnp | grep nginx
# 4. 에러 로그 확인
sudo tail -n 50 /var/log/nginx/error.log
# 5. 프로세스 확인
ps aux | grep nginx
# 6. 방화벽 확인 (포트가 열려있는지)
sudo ufw status
sudo ufw allow 80/tcp
sudo ufw allow 443/tcpserver {
listen 80;
server_name api.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name api.example.com;
ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;
# 최대 업로드 파일 크기
client_max_body_size 10M;
location / {
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;
proxy_connect_timeout 60s;
proxy_read_timeout 60s;
}
}server {
listen 80;
server_name example.com;
root /var/www/frontend/dist;
index index.html;
# SPA: 모든 경로를 index.html로 fallback
location / {
try_files $uri $uri/ /index.html;
}
# 정적 파일 캐시
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# API 요청은 백엔드로 전달
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;
}
}전송 데이터를 압축하여 응답 속도를 향상시킵니다.
http {
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6; # 압축 레벨 (1~9, 높을수록 압축률↑ CPU↑)
gzip_min_length 1000; # 1KB 이상인 경우만 압축
gzip_types
text/plain
text/css
text/javascript
application/javascript
application/json
application/xml
image/svg+xml;
}API 남용, DDoS 방어에 사용합니다.
http {
# IP당 초당 10개 요청으로 제한
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
server {
location /api/ {
limit_req zone=api_limit burst=20 nodelay;
# burst : 순간 허용 초과 요청 수
# nodelay : 버스트 요청을 지연 없이 즉시 처리
proxy_pass http://localhost:8080;
}
}
}server {
location /api/ {
# CORS 헤더
add_header 'Access-Control-Allow-Origin' 'https://example.com' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type' always;
# Preflight 요청 처리
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Max-Age' 86400;
add_header 'Content-Length' 0;
return 204;
}
proxy_pass http://localhost:8080;
}
}server {
location /ws/ {
proxy_pass http://localhost:8080;
# WebSocket 업그레이드 설정
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 3600s; # WebSocket은 오래 유지되므로 타임아웃 증가
}
}# 상태 확인
sudo systemctl status nginx
# 설정 문법 검사
sudo nginx -t
# 무중단 설정 적용 (실무 표준)
sudo nginx -t && sudo systemctl reload nginx
# 재시작
sudo systemctl restart nginx
# 로그 실시간 확인
sudo tail -f /var/log/nginx/access.log
sudo tail -f /var/log/nginx/error.log
# 사이트 활성화
sudo ln -s /etc/nginx/sites-available/myapp.conf /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
# 사이트 비활성화
sudo rm /etc/nginx/sites-enabled/myapp.conf
sudo nginx -t && sudo systemctl reload nginx# 1. 설정 파일 수정
sudo vi /etc/nginx/sites-available/myapp.conf
# 2. 문법 검사
sudo nginx -t
# 3. 정상이면 적용
sudo systemctl reload nginx
# 4. 로그 확인
sudo tail -f /var/log/nginx/error.log| 경로 | 설명 |
|---|---|
/etc/nginx/nginx.conf |
메인 설정 파일 |
/etc/nginx/sites-available/ |
사이트 설정 보관 |
/etc/nginx/sites-enabled/ |
활성화된 사이트 (심볼릭 링크) |
/var/log/nginx/access.log |
접근 로그 |
/var/log/nginx/error.log |
에러 로그 |
/var/www/html/ |
기본 웹 루트 |
본 문서의 내용은 Nginx를 처음 다루는 개발자를 위한 최소한의 실무 기초입니다.
심화 학습은 [Nginx 공식 문서](https://nginx.org/en/docs/)를 참고하십시오.
- 궁금한 점은 Discussions 탭이나 담당자에게 문의하세요.
- 담당자: 홍길동 (dev-hong@example.com)
© 2024 Project-Team-Name. All rights reserved. Licensed under the MIT License. 기여해주신 모든 분들께 진심으로 감사드립니다. 위는 푸터 템플릿으로 넣어논겁니다.