PR CENTER

뉴스룸     |     료실

mobile background

PR CENTER

Nginx 개요 및 핵심 개념

관리자
2026-07-27
조회수 14

1. Nginx vs Apache httpd — nginx가 강력한 이유

두 서버 모두 웹/리버스 프록시 역할을 하지만, '동시성을 처리하는 방식'이 근본적으로 다릅니다. 이 차이가 nginx의 성능·안정성 우위의 핵심입니다.

 

[핵심 차이: 연결 처리 모델]

   • Apache httpd (prefork/worker)

     - 연결(Connection)당 프로세스 또는 스레드 1개를 할당하는 블로킹 모델.

       동시 접속 1만 개면 프로세스/스레드도 그만큼 필요.

     - 연결 수↑ = 메모리·컨텍스트 스위칭 비용 급증

     - 느린 클라이언트(Slowloris 등)가 워커를 오래 점유

     - C10K(동시 1만 연결) 지점에서 성능 급락

   • Nginx (event-driven)

      - 비동기 이벤트 루프 기반. 워커 프로세스 1개가 epoll/kqueue로 수천~수만 개 연결을 동시에 처리.

     - 연결 수가 늘어도 메모리는 완만하게 증가

     - 느린 연결은 대기 큐에 두고 다른 연결 계속 처리

     - 고동시성·정적 콘텐츠·프록시에서 압도적


2. Nginx 프로세스 구조 (master 1 - worker N)

Nginx는 실행 시 1개의 master 프로세스와 N개의 worker 프로세스로 구성됩니다.

 

   • master process (root 권한)

     - 설정 파일 읽기·검증

     - 워커 프로세스 생성/종료

     - 시그널 수신, 로그·소켓 오픈

     - 실제 클라이언트 요청은 처리하지 않음(관리만)

   • worker process (비권한 유저)

     - 이벤트 루프를 돌며 실제 요청을 처리

     - 보통 CPU 코어 수만큼 실행 (worker_processes auto;)

   • cache manager / loader

    - 프록시 캐시 사용 시 만료 항목 정리, 부팅 시 디스크 캐시 메타데이터 로드

 

[이 구조의 장점]

   - 안정성(Isolation): 워커는 독립 프로세스. 하나가 크래시해도 다른 워커는 영향 없고 master가 즉시 재생성. 장애가 전체로 번지지 않음.

   - 확장성(Scalability): 워커 수를 코어 수에 맞춰 늘려 멀티코어 활용.

   - Graceful Reload(무중단 설정 반영): reload 시 새 설정으로 새 워커를 띄우고, 기존 워커는 처리 중 요청을 끝낸 뒤 종료. 연결 끊김 없이 

     설정 교체.

   - 권한 분리(Security): master는 root로 80/443 특권 포트를 열고, 워커는 비권한 유저로 요청 처리. 취약점이 있어도 피해 범위 제한.

 

[특징 - 모든 워커는 동일한 설정을 공유]

   - 모든 워커는 완전히 동일한 설정. master가 설정을 읽어 워커를 fork하므로 "이 워커만 다른 설정"은 불가능.

   - 워커 간 상태 공유는 최소화(락 경합↓). 공유가 필요한 것(캐시 존, rate-limit 카운터, SSL 세션 캐시)만 공유 메모리(shared memory zone)로 명시적 공유.

  - 연결 분배는 커널 accept 또는 accept_mutex / SO_REUSEPORT로 워커에 분산.

 

[주요 제어 시그널]

   • 무중단(graceful) 계열

     - SIGHUP   = reload(설정 재적용)

     - SIGUSR2 &nbsp= 바이너리 업그레이드(실행 중 nginx 교체)

     - SIGQUIT &nbsp= graceful shutdown(진행 중 요청 완료 후 종료)

   • 즉시 종료(무중단 아님)

     - SIGTERM / SIGINT = fast shutdown(진행 중 요청을 끊고 바로 종료)

     - 서비스를 깔끔히 내리려면 SIGTERM보다 SIGQUIT을 사용.


3. Nginx 리버스 프록시 - 무엇이고 왜 필요한가

- Nginx가 실무에서 가장 많이 쓰이는 형태가 리버스 프록시(reverse proxy)입니다.

- 클라이언트의 요청을 nginx가 대신 받아 뒤의 실제 서버(백엔드/WAS)로 전달하고, 그 응답을 다시 클라이언트에게 돌려주는 구조입니다.

58b3e87101190.png


4. 설정 구조와 기능 가이드

설정은 지시어(directive)와 블록(context)의 계층 구조입니다. 바깥 컨텍스트 설정은 안쪽으로 상속되며, 안쪽에서 재정의가 가능합니다.


    main                     # 전역 (worker_processes, user, pid ...)

     |- events                 # 연결 처리 (worker_connections ...)

     |- http                   # HTTP 전반 (log_format, gzip, upstream ...)

     |    |- upstream          # 백엔드 서버 그룹 (로드밸런싱)

     |    |- server            # 가상 호스트 하나

     |         |- location     # URI 경로별 처리 규칙

    (stream)                   # TCP/UDP 프록시 (http와 별개, 5장 참고)


4.1 server 블록 기본 설정

bf0e461655f47.png


4.2 server_name 을 통한 가상 호스팅

       요청의 Host 헤더를 각 server의 server_name과 비교해 매칭되는 server로 라우팅.

ac70e51e96a05.png


4.3 location 과 리버스 프록시

      [location 매칭 규칙 / 우선순위]

          = /path       정확히 일치                                          (1, 최상)

          ^~ /path     접두어 일치 + 이후 정규식 검사 중단    (2)

          ~ 정규식      정규식(대소문자 구분)                          (3)

          ~* 정규식    정규식(대소문자 무시)                          (3)

          /path          일반 접두어 일치(가장 긴 것 우선)         (4)

 

[항목별 예시]

      location = /healthz           { return 200; }                       # /healthz 만

      location ^~ /img/              { root /var/www; }                 # /img/* 는 정규식보다 먼저

      location ~ \.(png|jpg)$    { expires 30d; }                     # .png .jpg (대소문자 구분)

      location ~* \.(png|jpg)$   { expires 30d; }                    # .png .PNG .JPG 모두

      location /api/                     { proxy_pass http://be; }     # /api/... 서브트리

      location /api/v2/               { proxy_pass http://be2; }   # 더 긴 접두어가 우선

 

      매칭 순서: (1) = 정확 -> (2) ^~ 최장 접두어 -> (3) ~ / ~* 정규식(파일 등장 순서) -> (4) 일반 접두어(최장). =나 ^~로 확정되면 

      정규식은 검사 안 함.

      * prefix는 "세그먼트"가 아니라 "문자열 시작" 기준 -> /pathxyz 도 걸림.

       정확히 잡으려면 &quot= /path" + "/path/" 조합.

 

[proxy_pass 슬래시 규칙]  (location /path/ + 요청 /path/api/users 기준)

      proxy_pass http://be;      -> /path/api/users      (URI 없음: 원본 그대로)

      proxy_pass http://be/;     -> /api/users               (/path/ -> / 치환)

      proxy_pass http://be/v2/;  -> /v2/api/users      (/path/ -> /v2/ 치환)

      proxy_pass http://be/v2;   -> /v2api/users        (슬래시 없어 v2api 로 붙음)


      * 규칙: location과 proxy_pass의 트레일링 슬래시를 맞춰라(둘 다/둘 다 없이).

      * 슬래시 불일치 함정: location /path + proxy_pass http://be/ + 요청

        /path/users -> "//users" (더블 슬래시).

      * 정규식 location에는 proxy_pass에 URI를 붙일 수 없음 -> 캡처로 직접 구성:

         location ~ ^/path/(.*)$ { proxy_pass http://be/newbase/$1; }

      * proxy_pass에 변수가 들어가면 자동 치환 규칙이 적용되지 않고 경로를 전적으로 직접 지정

        (APMS 설정 #2가 이 경우).


[실무 사례 — prefix != proxy_pass 경로를 일부러 다르게 쓰는 경우]

      1. /api 프리픽스 벗기기(가장 흔함)

         location /api/ { proxy_pass http://be/; }   # /api/users -> /users

      2. 게이트웨이 분기(BFF/MSA)

         location /api/users/  { proxy_pass http://user-svc/; }

         location /api/orders/ { proxy_pass http://order-svc/; }

      3. 컨텍스트 패스 부착

         location / { proxy_pass http://be/app/; }   # /login -> /app/login

      4. 버전/리네이밍 흡수

         location /payment/ { proxy_pass http://be/billing-v2/; }

      5. 내부 구조 은닉(보안/추상화)

         location /download/ { proxy_pass http://storage/internal/files/; }


      * 다르게 갈 땐 백엔드의 절대 URL·리다이렉트(Location 헤더)·쿠키 path가

         공개 경로와 어긋남 -> proxy_redirect로 Location도 보정. 특별한 이유 없으면

         prefix와 백엔드 경로를 동일하게.


4.4 프록시 헤더 컨트롤

       프록시가 요청을 백엔드로 넘길 때 원래 클라이언트 정보를 헤더로 넣어줘야 함.

       안 하면 백엔드는 모든 요청이 nginx(로컬)에서 온 것으로 착각.

1e7a7404a059e.png


4.5 SSL/TLS 종단 (Termination)

       nginx가 HTTPS를 복호화(종단)하고 내부 백엔드와는 평문 HTTP로 통신하는 구성.

b34b4c4e2bcf2.png


4.6 return - 즉시 응답 반환

cd93802eb36a5.png


5. 심화 기능 가이드

5.1 서브리퀘스트 (auth_request 등)

      본 요청 처리 전에 내부적으로 다른 요청을 한 번 더 보내는 기능.

9e56817a27b85.png


      [서브리퀘스트를 쓰는 다른 기능들]

           - mirror     : 요청을 다른 location으로 복제(응답 버림). 트래픽 섀도잉/테스트

           - SSI        : 페이지 안에서 다른 경로를 끌어와 조립 (ssi on; + include virtual)

           - addition   : 본문 앞/뒤에 다른 location 내용 덧붙임 (add_before/after_body)

           - slice      : 대용량 파일을 Range 단위로 쪼개 가져와 캐싱

 

           # mirror 예시

              location / { mirror /mirror; proxy_pass http://main; }

              location = /mirror { internal; proxy_pass http://shadow$request_uri; }

 

      * 서브리퀘스트 vs 내부 리다이렉트

         : X-Accel-Redirect, error_page, try_files, rewrite...last 는 서브리퀘스트가 아니라 "내부 리다이렉트" (본 요청 자체가 다른 location으로

           갈아탐). X-Accel-Redirect는 백엔드가 인증만 하고 응답 헤더로 파일 경로를 주면 nginx가 대신 파일을 전송


5.2 Access Control List (IP 기반 접근 제어)

4313abfe7d98f.png


5.3 로드밸런싱 (upstream)

aeb693ea77d8c.png


5.4 Sticky Session (세션 고정)

3a9ed569b4dd1.png


5.5 TCP/UDP 프록시 (stream)

0b2a9fd208663.png


5.6 CORS 대응

5704eaf53f804.png


5.7 캐싱 (proxy_cache)

4560cb58644aa.png


6. 로깅 설정 및 로그 필드 설명

로그는 access_log(요청 기록)와 error_log(오류/진단)로 나뉨. log_format으로 필드를 자유롭게 조합.

 

[샘플 로그 한 줄]

      192.0.2.10 - alice [09/Jul/2026:13:22:01 +0900] "GET /api/users HTTP/1.1"

      200 1024 "https://app.example.com" rt=0.042 urt=0.037 up=10.0.0.12:8080

 

      192.0.2.10                             &nbsp= $remote_addr    접속한 상대 IP(프록시 뒤면 프록시)

      alice                                       &nbsp= $remote_user    Basic 인증(Authorization 헤더)

                                                                                      사용자명. 토큰/쿠키는 안 잡힘(-)

      09/Jul/2026:13:22:01         &nbsp= $time_local     요청 처리 시각

      GET /api/users HTTP/1.1     = $request        요청 라인(메서드·URI·버전)

      200                                         = $status         nginx가 클라에 보낸 최종 코드

                                                                                (백엔드 값 or nginx 자체 생성)

      1024                                       = $body_bytes_sent 응답 본문 바이트 수

      https://app.example.com   = $http_referer   유입 Referer

      rt=0.042                               &nbsp= $request_time         전체 요청 처리 시간

      urt=0.037                             &nbsp= $upstream_response_time 백엔드 응답까지 시간

      up=10.0.0.12:8080               = $upstream_addr   처리한 백엔드 주소

 


[로그 포맷 정의 (http 컨텍스트)]

      log_format main '$remote_addr - $remote_user [$time_local] '

                                    '"$request" $status $body_bytes_sent '

                                    '"$http_referer" "$http_user_agent" '

                                    '"$http_x_forwarded_for" '

                                    'rt=$request_time uct=$upstream_connect_time '

                                    'urt=$upstream_response_time cs=$upstream_cache_status';

      access_log /var/log/nginx/access.log main;

      error_log  /var/log/nginx/error.log  warn;   # debug/info/notice/warn/error/crit

 

[주요 로그 필드]

      $remote_addr                                  클라이언트(또는 직접 연결 프록시) IP

      $remote_user                                   HTTP Basic 인증 Authorization 헤더의 사용자명

                                                                 (Bearer 토큰·쿠키 로그인은 안 잡힘 -> 대개 -)

      $time_local/$time_iso8601            요청 시각(로컬/ISO8601)

      $request                                           요청 라인 전체 (예: GET /api/x HTTP/1.1)

      $request_method/$request_uri    메서드 / 원본 요청 URI(쿼리 포함)

      $status                                              nginx가 클라에 보낸 최종 응답 코드. 백엔드 값을

                                                                 전달하거나 nginx가 자체 생성(502·504·413·301·499).

                                                                 백엔드 코드만 보려면 $upstream_status

      $body_bytes_sent                           응답 본문 바이트 수(헤더 제외)

      $http_referer/$http_user_agent    Referer / User-Agent 헤더

      $http_x_forwarded_for                   프록시 체인상의 클라이언트 IP 목록

      $request_time                                  전체 요청 처리 시간(클라 수신~응답 완료, 초)

      $upstream_connect_time               백엔드 연결에 걸린 시간

      $upstream_response_time             백엔드가 응답하기까지 시간(병목 진단 핵심)

      $upstream_addr                               실제 처리한 백엔드 주소(LB 추적)

      $upstream_cache_status                캐시 HIT/MISS 등

      $ssl_protocol/$ssl_cipher               TLS 버전 / 암호 스위트

 

[빠른 진단]

      - rt는 큰데 urt가 작다                          -> 느린 클라이언트/네트워크

      - rt와 urt 둘 다 크다                             -> 백엔드가 느린 것

      - up($upstream_addr)                      -> 어느 백엔드가 처리했는지 확인


                                                                                                                                                                                                        ⭐발표자 : 이경훈님



0 0

페이지 바로가기

@2024 K2SYSTEMS. All rights reserved.

HOME       |       ABOUT US       |       SOLUTION       |       PR CENTER       |       CONTACT       |       인재채용       |       kakao i cloud 고객센터  

@2024 K2SYSTEMS. All rights reserved.