Nginx란? Nginx (엔진엑스)는 2004년 러시아 개발자 Igor Sysoev가 만든 고성능 웹 서버이자 리버스 프록시 서버입니다. 처음에는 Rambler.ru라는 러시아 포털 사이트의 C10K 문제(동시에 10,000개의 연결을 처리하는 문제)를 해결하기 위해 개발되었으며, 현재는 전 세계 웹사이트의 30% 이상에서 사용되고 있습니다.
Apache가 오랫동안 웹 서버 시장을 지배했지만, Nginx는 높은 동시 접속 처리 능력과 낮은 메모리 사용량으로 빠르게 시장 점유율을 확대했습니다. Netflix, Airbnb, GitHub, WordPress.com 등 트래픽이 많은 대형 사이트들이 Nginx를 사용하고 있습니다.
주요 특징 1. 높은 성능과 확장성 Nginx는 비동기 이벤트 기반(Event-Driven) 아키텍처 를 채택하여 적은 수의 워커 프로세스로 수만 개의 동시 연결을 처리할 수 있습니다. Apache의 프로세스/스레드 기반 모델과 달리, 각 연결마다 새로운 프로세스나 스레드를 생성하지 않아 메모리 효율이 뛰어납니다.
2. 낮은 리소스 사용 동일한 트래픽을 처리할 때 Apache 대비 메모리 사용량이 현저히 낮습니다. 이는 클라우드 환경에서 비용 절감으로 직결되며, 제한된 리소스를 가진 서버에서도 우수한 성능을 발휘합니다.
3. 확장성과 모듈화 다양한 모듈을 통해 기능을 확장할 수 있습니다. 기본 제공되는 코어 모듈 외에도 서드파티 모듈을 컴파일하여 사용할 수 있으며, Nginx Plus(상용 버전)에서는 더욱 강력한 기능을 제공합니다.
4. 무중단 운영 설정 파일을 수정한 후 nginx -s reload 명령으로 서비스 중단 없이 새로운 설정을 적용할 수 있습니다. 또한 바이너리 업그레이드도 무중단으로 가능하여 24/7 운영이 필요한 환경에 적합합니다.
5. 다양한 역할 수행
웹 서버 : 정적 파일(HTML, CSS, JavaScript, 이미지)을 매우 빠르게 제공
리버스 프록시 : 백엔드 애플리케이션 서버 앞단에서 요청을 중계
로드 밸런서 : 여러 백엔드 서버로 트래픽을 분산
HTTP 캐시 : 응답을 캐싱하여 백엔드 부하 감소
API Gateway : 마이크로서비스 아키텍처에서 진입점 역할
Nginx vs Apache 비교 웹 서버를 선택할 때 가장 많이 비교되는 두 솔루션이 Nginx와 Apache입니다. 각각의 장단점을 이해하면 프로젝트에 적합한 웹 서버를 선택하는 데 도움이 됩니다.
항목
Nginx
Apache
아키텍처
이벤트 기반 (비동기)
프로세스/스레드 기반 (동기)
동시 접속 처리
우수
보통
메모리 사용량
낮음
높음
정적 콘텐츠 제공
매우 빠름
보통
동적 콘텐츠 처리
프록시 필요
자체 처리 가능
설정 파일
간결함
복잡함 (.htaccess 지원)
모듈 시스템
정적 컴파일
동적 로딩
언제 Nginx를 선택해야 할까?
고트래픽 웹사이트 : 동시 접속자가 많은 경우 (수천~수만 명)
정적 파일 서빙 : 이미지, CSS, JavaScript 등 정적 자원 제공이 주된 목적
리버스 프록시 : Node.js, Python, Java 등의 애플리케이션 서버 앞단
로드 밸런싱 : 여러 백엔드 서버로 트래픽 분산 필요
클라우드 환경 : 리소스 효율이 중요하고 비용 절감 필요
언제 Apache를 선택해야 할까?
레거시 애플리케이션 : .htaccess 기반 설정에 의존하는 경우
PHP 애플리케이션 : mod_php를 통한 PHP 직접 처리가 필요한 경우
다양한 모듈 활용 : 동적 모듈 로딩으로 유연한 기능 확장이 필요
공유 호스팅 : 디렉토리별 권한 제어와 사용자별 설정이 중요
완전한 호환성 : 오래된 웹 애플리케이션과의 호환성 우선
실무에서의 선택 많은 현대적인 웹 아키텍처에서는 Nginx를 프론트엔드 리버스 프록시 로, Apache나 다른 애플리케이션 서버를 백엔드 로 함께 사용합니다. 이런 구성으로 Nginx의 빠른 정적 파일 서빙과 효율적인 연결 처리, Apache의 동적 콘텐츠 처리 능력을 모두 활용할 수 있습니다.
Nginx 설치 Ubuntu/Debian sudo apt update sudo apt install nginx sudo systemctl start nginx sudo systemctl enable nginx sudo systemctl status nginx
CentOS/RHEL sudo yum install epel-release sudo yum install nginx sudo systemctl start nginx sudo systemctl enable nginx
macOS (Homebrew) brew install nginx brew services start nginx
Docker docker run -d -p 80:80 --name nginx nginx:latest
Nginx 기본 구조 디렉토리 구조 /etc/nginx/ ├── nginx.conf # 메인 설정 파일 ├── sites-available/ # 사용 가능한 사이트 설정 ├── sites-enabled/ # 활성화된 사이트 설정 (심볼릭 링크) ├── conf.d/ # 추가 설정 파일 ├── snippets/ # 재사용 가능한 설정 조각 └── modules-enabled/ # 활성화된 모듈 /var/log/nginx/ # 로그 디렉토리 ├── access.log # 접근 로그 └── error.log # 에러 로그 /var/www/html/ # 기본 웹 루트 디렉토리
nginx.conf 기본 구조 user www-data;worker_processes auto;pid /run/nginx.pid;events { worker_connections 1024 ; use epoll ; } 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 " "$http_x_forwarded_for "' ; access_log /var/log/nginx/access.log main; error_log /var/log/nginx/error .log; sendfile on ; tcp_nopush on ; tcp_nodelay on ; keepalive_timeout 65 ; types_hash_max_size 2048 ; gzip on ; gzip_vary on ; gzip_proxied any; gzip_comp_level 6 ; gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss; include /etc/nginx/conf.d/*.conf ; include /etc/nginx/sites-enabled/*; }
핵심 설정 가이드 1. 기본 웹 서버 설정 server { listen 80 ; listen [::]:80 ; server_name example.com www.example.com; root /var/www/example.com; index index.html index.htm; access_log /var/log/nginx/example.com.access.log; error_log /var/log/nginx/example.com.error .log; location / { try_files $uri $uri / =404 ; } }
2. HTTPS/SSL 설정 server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name example.com; ssl_certificate /etc/nginx/ssl/example.com.crt; ssl_certificate_key /etc/nginx/ssl/example.com.key; ssl_protocols TLSv1.2 TLSv1.3 ; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on ; ssl_session_cache shared:SSL:10m ; ssl_session_timeout 10m ; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; root /var/www/example.com; index index.html; } server { listen 80 ; server_name example.com; return 301 https://$server_name $request_uri ; }
3. 리버스 프록시 설정 server { listen 80 ; server_name api.example.com; location / { proxy_pass http://localhost: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 ; } }
4. 로드 밸런싱 설정 upstream backend { least_conn; server backend1.example.com:8080 weight=3 ; server backend2.example.com:8080 weight=2 ; server backend3.example.com:8080 backup; } server { listen 80 ; server_name example.com; location / { proxy_pass http://backend; proxy_next_upstream error timeout invalid_header http_500; 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 { server srv1.example.com; server srv2.example.com; } upstream backend { server srv1.example.com weight=3 ; server srv2.example.com weight=1 ; } upstream backend { least_conn; server srv1.example.com; server srv2.example.com; } upstream backend { ip_hash; server srv1.example.com; server srv2.example.com; } upstream backend { random; server srv1.example.com; server srv2.example.com; }
5. 정적 파일 서빙 최적화 server { listen 80 ; server_name static.example.com; root /var/www/static; location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ { expires 1y ; add_header Cache-Control "public, immutable" ; access_log off ; } location ~* \.(css|js|json|xml)$ { gzip_static on ; expires 1y ; add_header Cache-Control "public" ; } }
6. 캐싱 설정 proxy_cache_path /var/cache/nginx levels=1 :2 keys_zone=my_cache:10m max_size=1g inactive=60m use_temp_path=off ; server { listen 80 ; server_name example.com; location / { proxy_pass http://backend; proxy_cache my_cache; proxy_cache_key "$scheme $request_method $host $request_uri " ; proxy_cache_valid 200 60m ; proxy_cache_valid 404 10m ; proxy_cache_bypass $cookie_nocache $arg_nocache ; add_header X-Cache-Status $upstream_cache_status ; } }
7. WebSocket 프록시 map $http_upgrade $connection_upgrade { default upgrade; '' close; } server { listen 80 ; server_name ws.example.com; location /ws { proxy_pass http://backend; proxy_http_version 1 .1 ; proxy_set_header Upgrade $http_upgrade ; proxy_set_header Connection $connection_upgrade ; proxy_set_header Host $host ; proxy_read_timeout 3600s ; proxy_send_timeout 3600s ; } }
8. Rate Limiting (요청 제한) limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;server { listen 80 ; server_name example.com; location /api/ { limit_req zone=mylimit burst=20 nodelay; limit_req_status 429 ; proxy_pass http://backend; } }
9. 보안 헤더 설정 server { listen 443 ssl http2; server_name example.com; add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; add_header X-XSS-Protection "1; mode=block" always; add_header Referrer-Policy "no-referrer-when-downgrade" always; add_header Content-Security-Policy "default-src 'self' https: data: 'unsafe-inline' 'unsafe-eval';" always; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; location / { root /var/www/example.com; index index.html; } }
10. 리다이렉트 및 Rewrite server { listen 80 ; server_name example.com; location /old-page { return 301 /new-page; } location / { return 301 https://newdomain.com$request_uri ; } location /users/ { rewrite ^/users/(.*)$ /user-profile?id=$1 last ; } if ($host != 'example.com' ) { return 301 https://example.com$request_uri ; } }
SPA (Single Page Application) 설정 React/Vue/Angular 배포 server { listen 80 ; server_name app.example.com; root /var/www/app/dist; index index.html; location / { try_files $uri $uri / /index.html; } location /api { proxy_pass http://localhost:3000; proxy_set_header Host $host ; proxy_set_header X-Real-IP $remote_addr ; } location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { expires 1y ; add_header Cache-Control "public, immutable" ; } }
마이크로서비스 라우팅 server { listen 80 ; server_name api.example.com; location /auth { proxy_pass http://auth-service:8001; proxy_set_header Host $host ; proxy_set_header X-Real-IP $remote_addr ; } location /users { proxy_pass http://user-service:8002; proxy_set_header Host $host ; proxy_set_header X-Real-IP $remote_addr ; } location /orders { proxy_pass http://order-service:8003; proxy_set_header Host $host ; proxy_set_header X-Real-IP $remote_addr ; } location /payments { proxy_pass http://payment-service:8004; proxy_set_header Host $host ; proxy_set_header X-Real-IP $remote_addr ; } }
성능 최적화 1. Worker 프로세스 최적화 worker_processes auto;worker_cpu_affinity auto;worker_rlimit_nofile 65535 ;events { worker_connections 4096 ; multi_accept on ; use epoll ; }
2. 버퍼 및 타임아웃 최적화 http { client_body_buffer_size 128k ; client_max_body_size 100M ; client_header_buffer_size 1k ; large_client_header_buffers 4 16k ; client_body_timeout 12 ; client_header_timeout 12 ; keepalive_timeout 15 ; send_timeout 10 ; sendfile on ; tcp_nopush on ; tcp_nodelay on ; }
3. 압축 최적화 http { gzip on ; gzip_vary on ; gzip_proxied any; gzip_comp_level 6 ; gzip_min_length 1000 ; gzip_disable "msie6" ; gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss application/rss+xml font/truetype font/opentype application/vnd.ms-fontobject image/svg+xml; }
모니터링 및 로깅 1. 액세스 로그 커스터마이징 http { log_format detailed '$remote_addr - $remote_user [$time_local ] ' '"$request " $status $body_bytes_sent ' '"$http_referer " "$http_user_agent " ' 'rt=$request_time uct="$upstream_connect_time " ' 'uht="$upstream_header_time " urt="$upstream_response_time "' ; log_format json 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 "' '}' ; access_log /var/log/nginx/access.log detailed; }
2. Status 페이지 활성화 server { listen 8080 ; server_name localhost; location /nginx_status { stub_status on ; access_log off ; allow 127.0.0.1 ; deny all; } }
Docker와 Nginx Dockerfile 예제 FROM nginx:alpineCOPY nginx.conf /etc/nginx/nginx.conf COPY conf.d/ /etc/nginx/conf.d/ COPY dist/ /usr/share/nginx/html/ EXPOSE 80 443 CMD ["nginx" , "-g" , "daemon off;" ]
docker-compose.yml 예제 version: '3.8' services: nginx: image: nginx:alpine ports: - "80:80" - "443:443" volumes: - ./nginx.conf:/etc/nginx/nginx.conf:ro - ./conf.d:/etc/nginx/conf.d:ro - ./ssl:/etc/nginx/ssl:ro - ./html:/usr/share/nginx/html:ro - ./logs:/var/log/nginx networks: - app-network restart: unless-stopped app: image: myapp:latest networks: - app-network networks: app-network: driver: bridge
Nginx 관리 명령어 기본 명령어 nginx -t nginx -s reload nginx -s stop nginx -s quit systemctl restart nginx nginx -v nginx -V nginx -t 2>&1 | grep "configuration file"
로그 관리 nginx -s reopen tail -f /var/log/nginx/access.logtail -f /var/log/nginx/error.loggrep "error" /var/log/nginx/error.log grep "192.168.1.100" /var/log/nginx/access.log
트러블슈팅 1. 502 Bad Gateway 원인 :
백엔드 서버가 다운되었거나 응답하지 않음
방화벽이 연결을 차단
SELinux가 프록시 연결을 차단 (CentOS/RHEL)
해결 :
curl http://localhost:3000 setsebool -P httpd_can_network_connect 1 iptables -L -n
2. 413 Request Entity Too Large 원인 : 업로드 파일 크기 제한 초과
해결 :
http { client_max_body_size 100M ; }
3. 504 Gateway Timeout 원인 : 백엔드 서버 응답 시간 초과
해결 :
location / { proxy_connect_timeout 600s ; proxy_send_timeout 600s ; proxy_read_timeout 600s ; }
4. 너무 많은 리다이렉트 원인 : 무한 리다이렉트 루프
해결 :
if ($http_x_forwarded_proto = "https" ) { set $https_redirect 0 ; } if ($https_redirect = 1 ) { return 301 https://$server_name $request_uri ; }
보안 베스트 프랙티스 1. 기본 보안 설정 http { server_tokens off ; if ($request_method !~ ^(GET|POST|PUT|DELETE|HEAD)$) { return 405 ; } location ~ /\. { deny all; access_log off ; log_not_found off ; } location ~ ~$ { deny all; } }
2. DDoS 방어 limit_conn_zone $binary_remote_addr zone=conn_limit:10m ;limit_req_zone $binary_remote_addr zone=req_limit:10m rate=10r/s;server { limit_conn conn_limit 10 ; limit_req zone=req_limit burst=20 nodelay; }
3. IP 화이트리스트/블랙리스트 location /admin { allow 192.168.1.0 /24 ; allow 10.0.0.1 ; deny all; } if ($geoip_country_code ~ (CN|RU)) { return 403 ; }
4. Basic Auth 설정 sudo apt install apache2-utils sudo htpasswd -c /etc/nginx/.htpasswd username
location /admin { auth_basic "Restricted Area" ; auth_basic_user_file /etc/nginx/.htpasswd; }
Let’s Encrypt SSL 인증서 Certbot 사용 sudo apt install certbot python3-certbot-nginx sudo certbot --nginx -d example.com -d www.example.com sudo certbot renew --dry-run 0 3 * * * certbot renew --quiet
참고 자료