파이썬 Gunicorn·Nginx 배포 가이드: WSGI·ASGI 서버 운영

Gunicorn과 Nginx로 파이썬 WSGI·ASGI 웹 서비스를 배포하는 구조와 리버스 프록시, systemd, HTTPS·장애 점검 방법을 정리합니다.

본문 상단 광고 구역 (승인 후 자동 노출됩니다)
Gunicorn과 Nginx를 이용한 파이썬 서버 배포 구조
파이썬 Gunicorn·Nginx WSGI·ASGI 서버 배포

파이썬 웹 서비스를 운영 환경에 배포할 때는 Nginx가 외부 HTTPS 요청을 받고, 내부의 Gunicorn 또는 ASGI 서버로 전달하는 구조가 일반적입니다. Flask·Django 같은 WSGI 앱은 Gunicorn이 직접 실행할 수 있고, FastAPI 같은 ASGI 앱은 ASGI 호환 워커나 Uvicorn 계열 실행 방식을 명확히 선택해야 합니다.

NGINX 공식 리버스 프록시 설정 확인하기

핵심 요약

  • Nginx는 TLS 종료, 정적 파일, 요청 전달을 맡고 애플리케이션 서버는 파이썬 코드를 실행합니다.
  • WSGI와 ASGI는 동일하지 않으므로 프레임워크에 맞는 워커를 선택해야 합니다.
  • Gunicorn을 공인 인터넷에 직접 노출하지 말고 로컬 포트나 Unix 소켓으로 연결합니다.
  • 프록시 헤더, 타임아웃, 업로드 크기, 정상 종료, 로그와 헬스체크를 함께 검증합니다.

Nginx와 파이썬 애플리케이션 서버의 역할

사용자 요청은 보통 80·443 포트의 Nginx에 도착합니다. Nginx는 HTTPS 인증서, 정적 파일, 요청 크기와 일부 접근 제어를 처리한 뒤 proxy_pass로 내부 애플리케이션 서버에 전달합니다. Gunicorn은 마스터 프로세스가 여러 워커를 관리하며 파이썬 애플리케이션을 실행합니다.

구성요소 주요 역할 외부 공개
Nginx HTTPS·프록시·정적 파일 80/443
Gunicorn/ASGI 서버 파이썬 앱 실행 로컬 포트·소켓
systemd 시작·재시작·로그 공개하지 않음
애플리케이션 업무 로직·응답 서버를 통해 제공

개발 서버는 코드 변경 확인에 편리하지만 장애 복구, 다중 프로세스, 운영 보안을 대신하지 않습니다. 배포 전 별도 사용자 계정, 가상환경, 환경변수, 로그 경로와 읽기·쓰기 권한을 정하세요.

WSGI와 ASGI를 먼저 구분하세요

WSGI는 전통적인 동기 파이썬 웹 애플리케이션 인터페이스로 Flask와 일반 Django 배포에 널리 사용됩니다. ASGI는 비동기 요청, WebSocket, 장시간 연결 같은 기능을 지원하며 FastAPI와 Django ASGI 구성이 사용합니다. 프레임워크 이름만 보고 결정하지 말고 실제 앱 진입점이 application인지 app인지, WSGI인지 ASGI인지 확인하세요.

ASGI 앱을 Gunicorn과 결합한다면 현재 설치한 Uvicorn·Gunicorn 버전의 공식 배포 지침에서 권장 워커 패키지와 실행법을 확인해야 합니다. 오래된 블로그의 클래스 경로를 그대로 복사하면 버전 변화로 실행이 실패할 수 있습니다.

Gunicorn 실행 명령 구성

gunicorn myproject.wsgi:application \
  --bind 127.0.0.1:8000 \
  --workers 3 \
  --timeout 30 \
  --access-logfile - \
  --error-logfile -

모듈:객체 형식은 실제 프로젝트 진입점과 일치해야 합니다. 워커 수는 고정 공식만 믿지 말고 CPU, 메모리, 요청 특성, 데이터베이스 연결 한도를 고려해 부하 테스트로 정하세요. 워커를 늘리면 프로세스마다 메모리와 연결이 늘어납니다.

타임아웃을 무작정 늘리기보다 오래 걸리는 보고서 생성이나 이메일 발송을 작업 큐로 분리하는 편이 좋습니다. 애플리케이션 서버는 빠른 요청·응답에 집중하고 백그라운드 작업은 별도 워커가 처리하도록 구성하세요.

Nginx 리버스 프록시 설정

server {
    listen 80;
    server_name example.com;

    location / {
        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_pass http://127.0.0.1:8000;
    }
}

공식 NGINX 문서에 따르면 proxy_pass는 요청을 업스트림 서버로 전달하고 응답을 다시 클라이언트에 보냅니다. Host와 실제 클라이언트 IP, 원래 프로토콜을 전달하도록 헤더를 명시합니다. 다만 애플리케이션은 신뢰할 수 있는 프록시에서 온 헤더만 신뢰해야 합니다.

location과 proxy_pass 끝의 슬래시 조합에 따라 URI가 교체되는 방식이 달라질 수 있습니다. 하위 경로 배포라면 실제 요청 경로를 시험하세요. 파일 업로드는 client_max_body_size, 느린 요청은 프록시 타임아웃, 스트리밍과 WebSocket은 버퍼링·업그레이드 헤더를 용도에 맞게 별도로 설정해야 합니다.

systemd로 자동 시작과 재시작 구성

[Unit]
Description=Python Gunicorn Service
After=network.target

[Service]
User=webapp
WorkingDirectory=/srv/myapp
EnvironmentFile=/etc/myapp.env
ExecStart=/srv/myapp/.venv/bin/gunicorn myproject.wsgi:application --bind 127.0.0.1:8000 --workers 3
Restart=on-failure

[Install]
WantedBy=multi-user.target

서비스 파일의 사용자, 경로, 모듈 이름은 환경에 맞게 바꿔야 합니다. 환경 파일에는 최소 권한을 적용하고 웹 사용자가 수정할 수 없게 하세요. systemctl daemon-reload 후 시작·상태·로그를 확인하고, 서버 재부팅 뒤에도 정상 기동되는지 실제로 시험합니다.

배포할 때는 새 코드가 준비되기 전에 기존 워커를 끊지 않도록 정상 종료와 단계적 교체를 고려하세요. 데이터베이스 마이그레이션이 구버전 코드와 호환되는지도 확인해야 무중단 전환 중 오류를 줄일 수 있습니다.

HTTPS·로그·헬스체크 운영 점검

실제 서비스에는 신뢰할 수 있는 인증서로 HTTPS를 적용하고 HTTP 요청을 HTTPS로 전환합니다. 인증서 자동 갱신은 예약만 믿지 말고 갱신 테스트와 만료 알림을 구성하세요. 애플리케이션 비밀값은 저장소가 아니라 제한된 환경 파일이나 비밀 관리 서비스에서 제공합니다.

Nginx 접근 로그와 애플리케이션 오류 로그에는 요청 식별자를 함께 남기되 비밀번호, Authorization 헤더, 세션 쿠키를 기록하지 마세요. 헬스체크는 프로세스 존재뿐 아니라 필요한 의존성 상태를 적절히 확인하되, 외부에 내부 버전과 상세 오류를 노출하지 않아야 합니다.

502 오류는 애플리케이션 서버 미기동, 잘못된 포트·소켓, 권한 문제를 먼저 봅니다. 504는 처리시간과 타임아웃을 확인하고, 정적 파일 404는 Nginx 경로와 파일 권한을 점검하세요. 설정 변경 전 nginx -t로 문법을 검사한 뒤 재적용합니다.

배포 후에는 외부 네트워크에서 홈페이지, 로그인, 파일 업로드, 큰 응답, 오류 페이지를 직접 확인하세요. 서버 내부의 단순 호출만 성공해도 DNS·방화벽·인증서·프록시 헤더 문제는 남아 있을 수 있습니다. 롤백할 이전 버전과 설정 파일도 준비해 두는 것이 안전합니다.

실수 방지 체크리스트

  • 앱이 WSGI인지 ASGI인지 확인합니다.
  • Gunicorn을 127.0.0.1 또는 Unix 소켓에 바인딩합니다.
  • 워커 수를 메모리와 DB 연결 한도에 맞춥니다.
  • Host·실제 IP·프로토콜 프록시 헤더를 검증합니다.
  • Nginx 설정을 nginx -t로 검사합니다.
  • HTTPS 인증서 갱신과 만료 알림을 시험합니다.
  • 환경변수 파일과 실행 사용자의 권한을 제한합니다.
  • 로그에서 비밀값과 개인정보를 제외합니다.
  • 정상 종료와 자동 재시작을 시험합니다.
  • 502·504·업로드·정적 파일 경로를 점검합니다.

자주 묻는 질문

1. Nginx 없이 Gunicorn만 공개해도 되나요?

기술적으로 요청을 받을 수 있지만 운영에서는 TLS, 정적 파일, 버퍼링과 접근 제어를 위해 리버스 프록시를 두는 구성이 일반적입니다.

2. Flask 개발 서버를 운영에 써도 되나요?

개발 서버는 운영용 프로세스 관리와 안정성을 대신하지 않으므로 운영 서버를 사용하세요.

3. FastAPI도 일반 Gunicorn 명령이면 되나요?

FastAPI는 ASGI 앱이므로 현재 공식 문서에 맞는 ASGI 실행 방식이나 호환 워커가 필요합니다.

4. workers는 CPU 수의 두 배면 되나요?

그 공식은 출발점일 뿐입니다. 메모리, I/O, DB 연결, 실제 부하를 측정해 정해야 합니다.

5. 502 Bad Gateway는 무엇을 확인하나요?

애플리케이션 서버 상태, bind 주소, 포트·소켓, 파일 권한과 Nginx 오류 로그를 확인하세요.

6. 504 Gateway Timeout은 왜 생기나요?

업스트림 응답 지연이나 타임아웃 설정 때문일 수 있습니다. 긴 작업은 큐 분리도 검토하세요.

7. X-Forwarded-Proto가 왜 필요한가요?

앱이 원래 요청이 HTTPS였음을 알고 올바른 URL과 보안 동작을 만들 때 사용합니다.

8. 정적 파일은 누가 제공하나요?

배포 구조에 따라 다르지만 Nginx가 지정 디렉터리의 정적 파일을 직접 제공할 수 있습니다.

9. 설정을 바꿀 때 바로 재시작하나요?

먼저 문법을 검사하고 가능하면 정상 재로드해 기존 연결 영향을 줄이세요.

10. Docker를 쓰면 Nginx가 필요 없나요?

컨테이너는 패키징 방식입니다. TLS 종료와 프록시 역할은 로드밸런서, 인그레스 또는 Nginx가 여전히 담당할 수 있습니다.

공식 출처와 확인일

실제 확인일: 2026년 9월 10일. 배포 명령과 워커 권장은 버전에 따라 달라질 수 있으므로 설치한 버전의 공식 문서를 다시 확인하세요.

본문 하단 광고 구역