FastAPI + Nginx 조합으로 서비스를 배포할 때 가장 자주 겪는 문제 중 하나가 있다.
HTTPS 로 접속했는데 왜 HTTP로 리다이렉트 된다.
"/"로 끝나는 경로만 리다이렉트가 발생한다.
이 문제는 단순히 서버 한 곳의 문제가 아니라,
FastAPI의 URL 정책, Nginx의 프록시 동작, Uvicorn의 proxy 설정 문제가 서로 엇갈리면서 발생하는 현상이다.
전체구조 - Nginx는 HTTPS 종료 지점 이다.
우리가 사용하는 구조는 대부분 아래와 같다.

클라이언트는 HTTPS로 접속하지만, FastAPI는 내부적으로 HTTP로 톧신한다.
즉, Nginx가 SSL을 종료하고 내부 FastAPI로 요청을 넘겨주는 구조다.
FastAPI는 원래 요청이 HTTPS였는지 알 수 없다.
Nginx가 Forwarded 헤더들을 제대로 전달하지 않으면 FastAPI는
HTTP로 들어왔다고 판단한다.
이것이 잘못된 redirect를 만드는 첫번째 원인이다.
Nginx의 proxy_pass
location /mm/ {
proxy_pass http://backend:4000/mm/;
}
위 설정은 다음과 같이 동작한다.
클라이언트 요청
https://example.com/mm/users/list
Nginx가 백엔드로 전달하는 요청
http://backend:4000/mm/users/list
여기까지는 문제없다.
하지만, FastAPI가 리다이렉트를 발생시키기 시작하면 상황이 달라진다.
FastAPI는 왜 redirect를 만드는가
FastAPI(Starlette)는 URL 끝 슬래시(/) 를 엄청 중요하게 본다.
예를들어 라우트를 이렇게 정의했다면
@app.get("/mm/user/list/")
클라이언트는 이렇게 요청하면
/mm/user/list
FastAPI는 바로 이렇게 판단한다.
슬래시가 빠졌네, 원래 URL은 /list/ 다
➡️ 307 Temporary Redirect 발생
반대 케이스도 마찬가지이다.
즉, FastAPI는 라우트의 슬래시와 요청 슬래시가 다르면 무조건 redirect를 발생시킨다.
🌟참고용 프레임워크 기본 동작 리다이렉트 여부
| 프레임 워크 | 기본 동작 |
| FastAPI | 자동 리다이렉트 |
| Django | 자동 리다이렉트 |
| Spring Boot | 리다이렉트 안 함 |
| NestJS | 설정에 따라 다름 |
| Express.js | 리다이렉트 안 함 |
| Flask | 리다이렉트 안 함 |
| ASP.NET Core | 리다이렉트 안 함 |
리다이렉트를 안하는 경우에는 정확히 일치하는 경로만 매칭되고, 그렇지 않으면 404를 반환한다.
따라서 슬래시 정책이 맞지 않으면 redirect는 무조건 한 번 발생한다.
문제는 그 redirect URL이 엉망이 될 수 있다는 점이다.
FastAPI가 redirect URL을 HTTPS ➡️ HTTP 로 잘못되게 만드는 이유
FastAPI는 redirect Location을 만들 때 다음 값을 참고한다.
- Host
- Scheme(http/https)
- Port
하지만 Nginx가 이것을 제대로 전달하지 않으면 https를 http로 redirectLocation이 만들어진다.
이게 브라우저로 그대로 전달되면
Mixed Content 정책 위배 ! !
Mixed Content: The page at 'https://example.com' was loaded over HTTPS,
but requested an insecure resource 'http://example.com/api'.
This request has been blocked; the content must be served over HTTPS.
가 된다...
uvicorn에서 --proxy-headers 옵션
Nginx는 원래 요청 정보를 FastAPI에 알려주려고 이런 헤더를 넣는다.
X-Forwarded-Proto: https
X-Forwarded-Host: example.com
X-Forwarded-Port: 443
하지만, 문제는
Uvicorn은 기본적으로 이 헤더들을 신뢰하지 않는다.
보안 때문인데, 해커가 헤더를 조작할 수도 있기 때문이다.
그래서 FastAPI에게 믿어도 된다는 옵션을 줘야한다.
그 옵션이
--proxy-headers
이다.
해결방법
1. 슬래시(/) 정책 통일
라우트와 프론트 호출 URL을 둘 다 /path 또는 둘 다 /path/ 로 맞추기
- 일반적으로 REST API 관례 상 '/path' 트레일링 슬래시 (Trailing Slash) 없음 으로 진행해야합니다.
- 예외
1. 디렉토리/컬렉션을 명시적으로 표현할 때: `/static/images/`, `/api/users/` (컬렉션)
2. 루트 경로: `/` (HTTP 요청에서 경로 부분이 비어있거나 `/`인 경우)
2. Nginx에서 헤더 정확히 넘기기
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
3. uvicorn에서 proxy headers 활성화
uvicorn main:app --host 0.0.0.0 --port 4000 --proxy-headers
FastAPI + Nginx 환경에서 HTTPS 가 HTTP로 튀는 문제는
결국 FastAPI의 슬래시 redirect + Nginx의 헤더 처리 + uvicorn proxy 설정이 서로 맞지 않아 발생하는 현상이다.
이 세 가지를 올바르게 잡아주면 redirect 문제는 해결된다.
'Backend · Infra' 카테고리의 다른 글
| Ai가 브라우저 보는 눈👀 : Cursor에서 Browser Tools MCP 사용하는 방법 (윈도우 + WSL) (0) | 2025.10.24 |
|---|---|
| PKCE란? OAuth2 인증을 안전하게 만드는 핵심 보안 메커니즘 (2) | 2025.07.22 |
| Figma 살 돈이없다면? Penpot self-hosting으로 대체하자 (3) | 2025.07.21 |
| MySQL부터 Qdrant 까지 DB 종류 한눈에 보기 (1) | 2025.07.09 |
| [MySQL InnoDB] 외래키(Foreign Key) 설정 시 주의사항 (0) | 2025.06.16 |