참고 - 배포 Nginx 와 uWSGI(위스기)

JungSik Heo·2025년 5월 31일

장고로 개발을 하고나면 runserver로 테스트를 했지만, 직접 배포를 runserver로 하게되면 보안, 안정성, 효율 등 여러 면에서 좋지않다.

🧠 비유로 이해

  • Nginx: 건물 입구에서 손님을 분산시키고 안내하는 리셉션
  • Gunicorn: 실제로 음식(웹 페이지)을 만드는 주방 셰프
  • 손님(요청)이 많으면 리셉션(Nginx)이 없으면 주방(Gunicorn)이 난리 나요.

NGINX 란?

이전에 gunicorn을 이용해 서버 가동을 했다면 이제는 웹서버인 Nginx와 연동해 서비스를 꾸려나가볼 것입니다.

우선 Nginx는 트래픽이 많은 웹사이트의 서버(WAS)를 도와주는 고성능 경량 웹 서버입니다.
apache의 단점들을 보완해 나온 것이 Nginx인데, 장점을 이야기해보면 크게 3가지가 있습니다.

7000 명 이상의 동시 접속자 있으면 NGINX를 추천하고 있다.

높은 성능
높은 동시성
낮은 자원 사용

특징)

  • Single Thread 기반으로 context switching을 하지 않음
  • 이벤트 지향 아키텍처(Event-driven Architecture) 방식 이용
  • 메모리 생성 속도 ↑, 적은 쓰레드로 많은 클라이언트 처리
  • apache가 제공하는 모든 기능 제공 (LB, 메일 프록시 등)

2.Gunicorn

Gunicorn(Green Unicorn)은 Python Web Server Gateway Interface(WSGI) HTTP서버입니다. Python 웹 어플리케이션의 높은 트래픽을 쉽게 처리할 수 있는 가볍고 안정적인 서버입니다.

WSGI(WebSever Gateway Interface)

파이썬 애플리케이션이 웹서버와 통신하기 위한 인터페이스로 웹서버의 요청을 해석을 해서 파이썬애플리케이션에게 전달해줍니다. 대표적으로 gunicorn과 uWSGI가 있습니다.

보통은 WS + CGI + Django
에서 WSGI로 gunicorn이나 uWSGI를 많이 사용하는 것 같은데, gunicorn보다 uWSGI가 효율적인 면에서 좋은 것 같아서 uWSGI를 이용해보려고 한다.

WSGI 와 장고

environ 딕셔너리 + start_response 함수

Django는 보통 wsgi.py를 통해 실행되며, 다음과 같은 방식으로 요청 정보를 받음:

def application(environ, start_response):
    # environ은 CGI에서 유래된 환경변수 형식의 딕셔너리
    ...
{
    'REQUEST_METHOD': 'GET',
    'PATH_INFO': '/home/',
    'QUERY_STRING': 'page=2',
    'CONTENT_TYPE': 'text/html',
    'CONTENT_LENGTH': '123',
    'SERVER_NAME': 'localhost',
    'SERVER_PORT': '8000',
    ...
}

✅ 전체 흐름 개요 (소스 기반)

[요청] --> [WSGI 서버 (gunicorn, uwsgi, runserver)] 
        --> [Django의 wsgi.py의 application(environ, start_response)] 
        --> [Django의 WSGIHandler 호출] 
        --> [HttpRequest 객체 생성] 
        --> [URL 매칭 및 View 실행] 
        --> [HttpResponse 반환] 
        --> [start_response로 응답 반환]
  1. wsgi.py (Django 프로젝트 생성 시 기본 포함)
    manage.py runserver 또는 gunicorn, uwsgi가 실행할 진입점입니다.
import os
from django.core.wsgi import get_wsgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')

application = get_wsgi_application()  # 👈 WSGI 인터페이스로 사용할 application 객체
  • 이 application 객체는 WSGI 서버가 요청을 전달하는 WSGI callable입니다.

  • get_wsgi_application()은 내부적으로 WSGIHandler 인스턴스를 반환합니다.

class WSGIRequest(HttpRequest):
    def __init__(self, environ):
        self.environ = environ
        self.path_info = environ.get('PATH_INFO', '/')
        self.method = environ.get('REQUEST_METHOD', 'GET')

environ에서 CGI 스타일의 값들을 추출해 HttpRequest 객체로 래핑

✅ 핵심 요약: 톰캣 vs 유니콘

항목Apache TomcatGunicorn (Green Unicorn)
대상 언어JavaPython
실행 대상Java Servlet, JSP (Spring 등)WSGI 기반 Python 앱 (Django, Flask 등)
표준Servlet API, Java EE 일부WSGI (PEP 3333)
정적 파일 처리가능하지만 비효율적안 함 (보통 Nginx와 연동)
주 사용 환경Java 웹 앱 (Spring MVC 등)Python 웹 앱 (Django, Flask 등)
예시 실행tomcat/bin/startup.shgunicorn myapp.wsgi:application
멀티 프로세스/스레드Java 기반 처리 (스레드 중심)Python 기반 처리 (워크 프로세스 방식)

Nginx는 프록시(reverse proxy) 역할로,
정적 파일 처리, 보안, 성능, 부하 분산 등을 담당하고
Gunicorn은 오직 Python 애플리케이션 실행에 집중

💡 왜 Nginx를 앞에 두나? (구체적 이유)

1. 📁 정적 파일을 빠르게 처리

  • 이미지, CSS, JS 파일은 Django가 처리하면 느림
  • Nginx는 C로 작성되어 매우 빠르게 정적 파일을 서빙함
    +/static/, /media/ 요청은 Gunicorn으로 보내지 않고 Nginx가 직접 응답

2. 🧱 보안 기능 제공

  • HTTPS(SSL 인증서) 처리
  • 요청 크기 제한, IP 차단, DDoS 방어 등

Gunicorn은 이런 기능이 없음

3. 🔄 리버스 프록시로서 로드 밸런싱

  • 여러 개의 Gunicorn 워커 또는 여러 서버로 요청을 분산
  • 예: upstream 설정을 통해 Gunicorn 프로세스를 여러 개 돌림

4. 🚫 Gunicorn은 HTTP 서버로는 부족

Gunicorn은 요청을 받아 처리할 수는 있지만,

정적 파일 처리 없음
연결 제한
오류 처리 미흡

프로덕션에서는 프록시 없이 쓰지 말 것이 권장사항

5. 📉 성능 최적화

Nginx는 비동기 이벤트 기반 → 수천 개의 연결을 효율적으로 처리

Gunicorn은 워커 수에 따라 병렬 처리 한계가 있음

[클라이언트 요청]
      ↓
   [Nginx]         ← 정적 파일, SSL, 압축, 보안
      ↓
  [Gunicorn]       ← Django/Flask WSGI 앱 실행
      ↓
  [애플리케이션 응답]

⚠️ Gunicorn 단독으로 쓰면 어떤가?

  • 개발 환경에서는 OK (python manage.py runserver와 비슷)

하지만 프로덕션에서는 문제가 생길 수 있음:

  • 정적 파일 느림
  • SSL 미지원
  • 보안 설정 없음
  • 부하 분산 불가

https://moondol-ai.tistory.com/467

https://velog.io/@jimin_lee/Nginx%EC%99%80-Gunicorn-%EB%91%98-%EC%A4%91-%ED%95%98%EB%82%98%EB%A7%8C-%EC%8D%A8%EB%8F%84-%EB%90%A0%EA%B9%8C

profile
쿵스보이(얼짱뮤지션)

0개의 댓글