Nginx 핵심 기능 분석 및 Tcpdump/Wireshark를 활용한 패킷 캡처 실습

1. Nginx 개요 및 HTTP 프로토콜

1.1 Nginx 특성

Nginx는 고성능 경량 웹 서버 및 리버스 프록시 소프트웨어로, 다음과 같은 장점을 제공합니다:

  • 높은 안정성과 낮은 리소스 소비
  • HTTP 동시 연결 처리 능력 우수 (단일 물리 서버에서 30,000~50,000개 동시 요청 처리 가능)

단점으로는 동적 콘텐츠 처리 성능이 상대적으로 떨어지며, Apache에 비해 rewrite 기능이 제한적입니다.

1.2 HTTP 프로토콜 발전

버전특징
HTTP/0.9텍스트 전용 단순 프로토콜, 콘텐츠 협상 불가
HTTP/1.0요청/응답마다 연결 생성 및 종료, 트랜잭션 중심
HTTP/1.1지속 연결(Persistent Connection) 지원, 파이프라이닝
HTTP/2바이너리 프레이밍, 헤더 압축(HPACK), 서버 푸시

1.3 프록시 방식 비교

포워드 프록시(Forward Proxy): 클라이언트와 대상 서버 사이에 위치하여 클라이언트를 대신해 요청을 전달합니다. 클라이언트는 프록시 설정이 필요하고, 실제 서버 IP는 숨겨집니다.

리버스 프록시(Reverse Proxy): 클이언트 입장에서는 목표 서버처럼 동작합니다. 클라이언트 설정 없이 프록시 서버를 통해 내부 서버에 접근하며, 실제 서버 정보가 클라이언트에 노출되지 않습니다.

2. 설치 및 기본 설정

2.1 소스 컴파일 설치 스크립트

#!/bin/bash
set -e

# 방화벽 초기화 및 의존성 설치
iptables -F
yum install -y epel-release
yum clean all && yum makecache
yum install -y pcre-devel zlib-devel gcc gcc-c++ make wget openssl-devel

# 전용 계정 생성
id -u webuser &>/dev/null || useradd -M -s /sbin/nologin webuser

# 소스 다운로드 및 압축 해제
NGINX_VER="1.24.0"
wget "https://nginx.org/download/nginx-${NGINX_VER}.tar.gz" -P /tmp
tar -zxf "/tmp/nginx-${NGINX_VER}.tar.gz" -C /opt

cd "/opt/nginx-${NGINX_VER}"

# 컴파일 설정
./configure \
  --prefix=/apps/nginx \
  --user=webuser \
  --group=webuser \
  --with-http_stub_status_module \
  --with-http_ssl_module \
  --with-stream \
  --with-stream_ssl_module

make -j$(nproc) && make install

# 심볼릭 링크 생성
ln -sf /apps/nginx/sbin/nginx /usr/local/bin/

# systemd 서비스 등록
cat > /etc/systemd/system/web-nginx.service <<'EOF'
[Unit]
Description=Nginx Web Server
After=network-online.target
Wants=network-online.target

[Service]
Type=forking
PIDFile=/apps/nginx/logs/nginx.pid
ExecStartPre=/apps/nginx/sbin/nginx -t
ExecStart=/apps/nginx/sbin/nginx
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable --now web-nginx

# 설치 확인
if pgrep -x "nginx" > /dev/null; then
    echo -e "\e[32mNginx 정상 실행 중\e[0m"
else
    echo -e "\e[31mNginx 실행 실패\e[0m"
fi

2.2 기본 설정 파일 구조

webuser  webuser;
worker_processes  auto;

events {
    worker_connections  2048;
    use epoll;
}

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

    sendfile        on;
    tcp_nopush      on;
    tcp_nodelay     on;
    keepalive_timeout  65;

    server {
        listen       80;
        server_name  _;

        location / {
            root   /apps/nginx/html;
            index  index.html;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /apps/nginx/html;
        }
    }
}

3. 핵 기능 구현

3.1 포워드 프록시 설정

server {
    resolver 8.8.8.8 8.8.4.4;
    listen 8080;

    location / {
        proxy_pass http://$host$request_uri;
        proxy_set_header Host $host;
        proxy_connect_timeout 30s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
        proxy_buffers 256 4k;
    }
}

server {
    resolver 8.8.8.8 8.8.4.4;
    listen 8443 ssl;
    
    ssl_certificate     /apps/nginx/certs/proxy.crt;
    ssl_certificate_key /apps/nginx/certs/proxy.key;

    location / {
        proxy_pass https://$host$request_uri;
        proxy_connect_timeout 30s;
    }
}

3.2 리버스 프록시 및 로드밸싱

upstream backend_pool {
    least_conn;                    # 최소 연결 알고리즘
    
    server 10.0.1.10:8080 weight=5;
    server 10.0.1.11:8080 weight=3;
    server 10.0.1.12:8080 backup;  # 백업 서버
}

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

    location / {
        proxy_pass http://backend_pool;
        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;
    }
}

3.3 동적/정적 콘텐츠 분리

upstream app_servers {
    server 127.0.0.1:9000;
    server 127.0.0.1:9001;
}

server {
    listen 80;
    server_name www.example.com;
    root /data/web/static;

    # 정적 파일 직접 처리
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2)$ {
        expires 30d;
        add_header Cache-Control "public, immutable";
    }

    # 동적 요청 애플리케이션 서버로 전달
    location ~ \.(php|jsp|do)$ {
        proxy_pass http://app_servers;
        proxy_hide_header X-Powered-By;
    }

    location / {
        try_files $uri $uri/ =404;
    }
}

4. 로드밸런싱 알고리즘

알고리즘지시어설명
라운드 로빈기본값요청을 순차적으로 분배
가중치 라운드 로빈weight서버 성능에 따른 가중치 적용
IP 해시ip_hash클라이언트 IP 기반 세션 고정
최소 연결least_conn현재 연결 수가 가장 적은 서버 선택
최소 응답 시간fair응답 시간이 빠른 서버 우선 (타사 모듈)
URL 해시hash $request_uri요청 URI 기반 캐시 최적화 (타사 모듈)

5. 로그 포맷 및 분석

5.1 사용자 정의 로그 포맷

log_format detailed '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent '
                    '"$http_referer" "$http_user_agent" '
                    '$request_time $upstream_response_time '
                    '$upstream_addr $upstream_status';

access_log /apps/nginx/logs/access.log detailed;

5.2 로그 필드 설명

변수의미
$remote_addr클라이언트 IP 주소
$request_time전체 요청 처리 시간
$upstream_response_time백엔드 서버 응답 시간
$upstream_addr실제 요청 처리한 백엔드 서버
$http_x_forwarded_for프록시 체인을 통한 원본 클라이언트 IP

6. curl 명령어 활용

옵션기능예시
-X, --requestHTTP 메서드 지정curl -X POST URL
-H, --header요청 헤더 추가curl -H "Accept: application/json"
-d, --dataPOST 데이터 전송curl -d "key=value"
-i, --include응답 헤더 포함 출력curl -i URL
-I, --head헤더만 조회curl -I URL
-v, --verbose상세 통신 과정 출력curl -v URL
-k, --insecureSSL 인증서 검증 무시curl -k https://...
-o, --output출력 파일 지정curl -o file.html URL
-L, --location리다이렉트 따라가기curl -L URL

7. HTTP 메서드 비교

메서드목적특성
GET리소스 조회URL 파라미터, 캐시 가능, 브라우저 히스토리 저장
POST리소스 생성요청 본문 전송, 데이터 크기 제한 없음
PUT리소스 전체 수정멱등성 보장, 전체 교체
PATCH리소스 부분 수정부분 업데이트
DELETE리소스 삭제멱등성 보장
HEAD메타데이터 조회본문 없이 헤더만 반환
OPTIONS지원 메서드 확인CORS 프리플라이트에 사용

8. Tcpdump를 활용한 패킷 캡처

8.1 기본 사용법

# 특정 포트 패킷 캡처
tcpdump -n -i any port 80

# 상세 정보 출력
tcpdump -nn -v -i eth0 port 443

# 파일로 저장 (Wireshark 분석용)
tcpdump -nn -i any port 80 -w /tmp/capture.pcap

# 호스트 기반 필터링
tcpdump -nn host 192.168.1.100 and port 8080

# TCP 플래그 필터링 (SYN 패킷만)
tcpdump -nn "tcp[tcpflags] & tcp-syn != 0"

8.2 출력 해석

13:30:31.068361 IP 192.168.10.65.51238 > 192.168.10.20.80: Flags [S], seq 2461555369, win 29200, options [mss 1460,sackOK,TS val 187463682 ecr 0,nop,wscale 7], length 0

타임스탬프, 프로토콜, 출발지.포트 > 목적지.포트, TCP 플래그, 시퀀스 번호, 윈도우 크기, 옵션 순으로 표시됩니다.

9. Wireshark 분석

9.1 캡처 파일 분석 절차

  1. tcpdump로 생성한 .pcap 파일을 Wireshark로 열기
  2. 필터 적용: ip.addr==192.168.10.20 && tcp.port==80
  3. 특정 TCP 스트림 팔로우: 마우스 우클릭 → "Follow" → "TCP Stream"
  4. HTTP 요청/응답 분석: "Statistics" → "HTTP" → "Packet Counter"

9.2 유용한 디스플레이 필터

http.request.method == "GET"
http.response.code == 200
tcp.analysis.retransmission    # 재전송 패킷
tcp.flags.syn == 1             # SYN 패킷만
ssl.handshake.type == 1        # Client Hello

10. TLS/SSL 인증서 설정

10.1 OpenSSL 자체 서명 인증서 생성

# CA 개인키 및 인증서 생성
mkdir -p /apps/nginx/certs && cd /apps/nginx/certs

openssl genrsa -out ca-key.pem 4096
openssl req -new -x509 -days 3650 -key ca-key.pem -out ca-cert.pem \
  -subj "/C=KR/ST=Seoul/L=Seoul/O=MyOrg/OU=IT/CN=RootCA"

# 서버 인증서 생성
openssl genrsa -out server-key.pem 2048
openssl req -new -key server-key.pem -out server-req.pem \
  -subj "/C=KR/ST=Seoul/L=Seoul/O=MyOrg/OU=IT/CN=*.example.com"

openssl x509 -req -days 365 -in server-req.pem \
  -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial \
  -out server-cert.pem

10.2 HTTPS 서버 설정

server {
    listen 443 ssl http2;
    server_name secure.example.com;

    ssl_certificate     /apps/nginx/certs/server-cert.pem;
    ssl_certificate_key /apps/nginx/certs/server-key.pem;
    ssl_trusted_certificate /apps/nginx/certs/ca-cert.pem;

    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 1d;

    # OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;

    location / {
        root /data/web/secure;
        index index.html;
    }
}

11. TCP/UDP 스트림 프록시

11.1 TCP 프록시 설정

stream {
    upstream db_cluster {
        least_conn;
        server 10.0.2.10:3306;
        server 10.0.2.11:3306;
    }

    upstream mongo_cluster {
        server 10.0.2.20:27017;
        server 10.0.2.21:27017;
    }

    server {
        listen 3306;
        proxy_pass db_cluster;
        proxy_connect_timeout 5s;
        proxy_timeout 300s;
    }

    server {
        listen 27017;
        proxy_pass mongo_cluster;
    }
}

11.2 UDP 프록시 설정

stream {
    server {
        listen 53 udp;
        proxy_pass 8.8.8.8:53;
        proxy_timeout 1s;
        proxy_responses 1;
        error_log logs/dns-proxy.log;
    }

    server {
        listen 514 udp;
        proxy_pass syslog_backend;
        proxy_buffer_size 16k;
    }

    upstream syslog_backend {
        server 10.0.3.10:514;
        server 10.0.3.11:514;
    }
}

stream 블록은 http 블록과 동일한 계층에 위치하며, events 블록 이후에 선언합니다. TCP와 UDP 프록시 모두 --with-stream 컴파일 옵션이 필요합니다.

태그: nginx Reverse Proxy Load Balancing tcpdump wireshark

7월 17일 05:01에 게시됨