SSL와 Nginx란?
이제까지 작업한 내용을 바탕으로 보안 요소를 보완하겠습니다. 특히 환자 정보와 같은 민감한 데이터를 다루는 시스템에서는 데이터의 기밀성과 서버의 안정성을 확보하는 것이 필수적입니다. 이번 포스팅에서는 HTTP의 한계를 극복하는 SSL/TLS 프로토콜과 서버의 방어막 역할을 하는 Nginx의 필요성에 대해 정리합니다.

웹 통신의 기본인 HTTP(HyperText Transfer Protocol)는 데이터를 전송할 때 암호화 과정을 거치지 않습니다.
- HTTP (TCP/80): 클라이언트와 서버가 주고받는 데이터 패킷이 평문(Plaintext) 상태로 전송됩니다. 만약 중간 경로(라우터, 스위치 등)에서 패킷 캡처 도구(Wireshark 등)를 사용하면 JSON 데이터 내의 민감 정보가 그대로 노출됩니다.
- HTTPS (TLS/443): HTTP에 TLS(Transport Layer Security) 프로토콜을 결합한 방식입니다. 데이터를 전송하기 전 암호화 과정을 거치며, 해커가 패킷을 가로채더라도 내용을 해독할 수 없어 데이터의 기밀성이 유지됩니다.

보안 통신을 이해하기 위해서는 네트워크 계층의 두 가지 핵심 프로토콜을 알아야 합니다.
① TCP (Transmission Control Protocol)
TCP는 데이터의 신뢰성 있는 전송을 보장하는 전송 계층 프로토콜입니다.
- 3-Way Handshake: 데이터를 보내기 전, 클라이언트와 서버가 서로 연결될 준비가 되었는지 세 단계를 거쳐 확인합니다.
- 특징: 패킷이 유실되면 재전송을 요청하고, 보낸 순서대로 데이터를 조립합니다. 하지만 데이터 자체를 암호화하지는 않습니다.
② TLS (Transport Layer Security)
과거 SSL(Secure Sockets Layer)이라 불리던 프로토콜의 표준화된 최신 버전입니다.
- 역할: TCP 연결이 수립된 직후, 그 위에서 실행되어 통신 세션을 암호화합니다.
- Handshake 과정: 공개키 암호화 방식을 사용해 서버의 신원을 확인하고, 통신에 사용할 '대칭키'를 안전하게 교환합니다.
- 결과: TCP 위에서 오가는 모든 데이터가 암호화되어 전송됩니다.
실시간 데이터 전송을 위해 사용하는 웹소켓 역시 보안 계층이 필요합니다.
- WS (ws://): 일반 웹소켓 프레임이 평문으로 전송됩니다. 실시간 환자 상태 데이터가 중간에 노출될 위험이 있습니다.
- WSS (wss://): 웹소켓 프레임을 TLS 계층 위에서 전송합니다. HTTPS와 마찬가지로 실시간 세션 전체를 암호화하여 데이터의 무결성과 기밀성을 보장합니다.

애플리케이션 서버(Uvicorn) 앞에 Nginx를 두는 Reverse Proxy 구조는 보안의 기본 원칙입니다.
FastAPI를 실행하는 Uvicorn은 Python 코드를 효율적으로 처리하는 데 집중되어 있습니다. 따라서 다음과 같은 외부 공격에 취약할 수 있습니다.
또한 8000번 포트를 외부로 직접 노출하는 것은 내부 시스템의 구조를 노출하는 것과 같습니다.
만약 8000번 포트를 직접 열어두면, 공격자는 "아, 이 서버는 아마도 Python(FastAPI/Django)이나 Node.js로 돌아가는 애플리케이션 서버겠구나"라고 바로 짐작할 수 있습니다. 특정 기술 스택이 드러나면 그 기술의 취약점(CVE)을 노린 맞춤형 공격이 들어오기 쉬워집니다.
- 표준 포트 사용: 외부에서는 표준 포트인 80(HTTP) 또는 443(HTTPS)만 열어둡니다.
- 포트 포워딩: Nginx가 80/443으로 들어온 요청을 받아 내부망에 있는 8000번 포트로 안전하게 전달합니다. 공격자는 내부 서버의 실제 위치와 포트를 알 수 없게 됩니다.

Proxy(프록시)는 한마디로 대리인입니다. 네트워크 통신에서 클라이언트와 서버 사이의 중계 역할을 수행하는 서버를 의미합니다. 프록시는 그 위치와 목적에 따라 Forward Proxy와 Reverse Proxy로 나뉩니다.
1. Forward Proxy (일반적인 프록시)
우리가 흔히 '프록시'라고 부르는 것은 Forward Proxy입니다. 이 서버는 클라이언트(사용자)의 바로 앞에 위치합니다.
- 동작: 클라이언트가 외부 인터넷(서버)에 접속하려고 할 때, 직접 가지 않고 프록시 서버에 요청을 보냅니다. 프록시 서버가 대신 인터넷에 접속해 데이터를 가져와 클라이언트에게 전달합니다.
- 주요 목적
- 클라이언트 은닉: 서버는 실제 클라이언트의 IP를 알 수 없고 프록시 서버의 IP만 보게 됩니다.
- 접근 제어: 특정 사이트 접속을 차단하거나(회사/학교), 반대로 차단된 사이트에 우회 접속할 때 사용합니다.
- 캐싱: 자주 방문하는 사이트의 데이터를 프록시 서버에 저장해두어 속도를 높입니다.
2. Reverse Proxy (리버스 프록시)
Nginx를 통해 구현하는 것이 바로 Reverse Proxy입니다. 이 서버는 백엔드 서버(FastAPI 등)의 바로 앞에 위치합니다.
- 동작: 클라이언트는 인터넷을 통해 서버로 요청을 보낸다고 생각하지만, 실제로는 리버스 프록시(Nginx)에 도달합니다. 리버스 프록시는 이 요청을 내부망에 있는 실제 서버(FastAPI:8000)로 전달하고, 서버의 응답을 받아 다시 클라이언트에게 보내줍니다.
- 주요 목적
- 서버 보안 (구조 은닉): 외부 사용자는 실제 백엔드 서버의 IP나 포트(8000)를 알 수 없습니다. 오직 리버스 프록시의 IP만 보게 됩니다.
- 로드 밸런싱: 요청이 많을 때 여러 대의 서버로 부하를 나누어 전달합니다.
- SSL 터미네이션: 암호화(HTTPS) 처리를 리버스 프록시가 전담하여 백엔드 서버의 부담을 줄여줍니다.
구현
원래 Nginx와 SSL은 VM을 설치하고 그 위에 사용하는게 옳지만 연습을 위해서 로컬에서 진행해보겠습니다.
로컬 환경(Windows)에서 Nginx를 설치하고, Self-signed SSL(자체 서명 인증서)을 적용하여 HTTPS와 WSS 통신을 구현해 봅시다.
Nginx 설치 (Windows)
가장먼저 Nginx 공식 다운로드 페이지에 들어가 nginx/Windows-x.x.x (Mainline 또는 Stable) 버전을 다운 받습니다.

다운로드한 파일의 압축을 풀고, 경로가 복잡하지 않은 곳에 옮겨둡니다. 폴더 안의 nginx.exe를 더블 클릭합니다.

Nginx는 실행되어도 메모장처럼 창이 뜨지 않고 백그라운드에서 조용히 돌아갑니다. 제대로 켜졌는지 확인하기 위해 브라우저에서 http://localhost를 쳤을 때 "Welcome to nginx!" 화면이 나오면 성공입니다.
로컬용 SSL 인증서 생성 (OpenSSL)
현재 프로젝트에서는 실제 도메인이 없으므로, 우리끼리만 약속한 가짜 자체 서명 인증서를 만듭니다. Windows에 Git이 설치되어 있다면 Git Bash를 사용하세요. Nginx 폴더 안에 ssl이라는 폴더를 만듭니다. 해당 폴더에서 터미널을 열고 아래 명령어를 입력합니다.
설치 과정에서 Common Name (e.g. server FQDN or YOUR name) []: localhost 로만 잘 입력하면 됩니다.
명령어가 끝나고 해당 폴더에 server.crt와 server.key 파일이 생겼다면 인증서 준비는 끝입니다.
# 1. 개인키(key)와 인증서(crt) 한 번에 생성
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout server.key -out server.crt
Nginx 설정 파일(nginx.conf) 작성
이제 Nginx에게 "이 인증서를 사용해서 443번 포트를 열고, 8000번(FastAPI)으로 연결해줘"라고 지시해야 합니다. 다운받은 nginx-1.29.4 폴더에 nginx.conf 파일을 열고 기존 내용을 지운 뒤 아래 코드를 복사해서 붙여넣습니다.
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
server {
listen 443 ssl; # HTTPS 표준 포트인 443번을 엽니다.
server_name localhost;
# 🔐 아까 만든 인증서 파일들의 경로 (절대경로로 적는 게 가장 안전합니다)
ssl_certificate "C:/Users/su888/OneDrive/바탕 화면/nginx/ssl/server.crt";
ssl_certificate_key "C:/Users/su888/OneDrive/바탕 화면/nginx/ssl/server.key";
# 🏥 일반 API 요청 처리 (FastAPI:8000으로 전달)
location / {
proxy_pass http://127.0.0.1:8000;
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;
}
# 📡 웹소켓 요청 처리 (wss:// 지원)
location /ws/ {
proxy_pass http://127.0.0.1:8000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
}
}
# HTTP(80)로 접속해도 HTTPS(443)로 자동 연결해주는 설정
server {
listen 80;
server_name localhost;
return 301 https://$host$request_uri;
}
}
Nginx 실행 및 설정 적용
Nginx를 적용하기 전에 FastAPI를 먼저 실행합니다. VS Code에서 기존처럼 서버를 띄워둡니다.
Nginx 폴더에서 터미널을 열고 다음 명령어를 칩니다.
start nginx
Nginx 테스트
마지막으로 Nginx가 잘 켜졌다면 postman으로 기존의 http://localhost:8000/api/v1/audio 말고 Nginx에서 SSL를 설정한 https://localhost/api/v1/audio 로 실행합니다.

'FastAPI' 카테고리의 다른 글
| [FastAPI] Redis를 이용한 검색 속도 향상/로그인 세션 관리 (0) | 2025.12.24 |
|---|---|
| [FastAPI] JWT를 이용한 회원가입/로그인 서버 구현 (0) | 2025.12.21 |
| [FastAPI] Azure Service Bus와 Function App을 활용한 데이터 전송 (2) (0) | 2025.12.18 |
| [FastAPI] Azure Service Bus와 Function App을 활용한 데이터 전송 (1) (0) | 2025.12.18 |
| [FastAPI] Naver API를 사용한 거리 및 최단경로 시간 탐색 (0) | 2025.12.17 |