- Published on
Nginx HTTPS에서 OAuth 콜백 502·무한리다이렉트 해결
- Authors
- Name
- 스타차일드
- https://x.com/ETFBITX
서드파티 OAuth 로그인(구글/깃허브/카카오 등)을 Nginx 리버스 프록시 뒤에서 운영하다 보면, 로컬에서는 잘 되는데 운영 HTTPS 환경에서만 콜백이 502 Bad Gateway로 터지거나, 로그인 성공 후 다시 로그인 페이지로 튕기며 무한 리다이렉트가 반복되는 케이스가 자주 나옵니다.
이 글은 “왜 OAuth 콜백 구간에서만” 문제가 잘 드러나는지(리다이렉트, 쿠키, 프록시 헤더가 동시에 얽히기 때문), 그리고 Nginx 설정과 애플리케이션 설정을 어떤 순서로 점검하면 빠르게 수습되는지를 실전 관점에서 정리합니다.
증상으로 분류하기: 502 vs 무한 리다이렉트
1) OAuth 콜백 요청에서 502 Bad Gateway
대개 Nginx가 업스트림(앱 서버)과 통신에 실패한 상황입니다.
- 업스트림 주소/포트 오류
- 업스트림이 HTTP인데 Nginx가 HTTPS로 붙으려는 설정 실수
- 업스트림 타임아웃(콜백 처리 중 외부 통신/DB 지연)
- 업스트림이 리다이렉트를 잘못 생성해 루프를 만들고, 그 과정에서 커넥션이 터지는 경우
2) 로그인 후 무한 리다이렉트(로그인 페이지로 계속 복귀)
대부분 “세션 쿠키가 유지되지 않음” 또는 “앱이 자신을 HTTP로 인식”하는 문제입니다.
X-Forwarded-Proto미설정으로 앱이http기준 URL을 만들고 다시https로 리다이렉트되며 루프- OAuth
redirect_uri가 등록값과 미세하게 다름(스킴/호스트/포트/경로/트레일링 슬래시) SameSite/Secure쿠키 속성 문제로 콜백 시 세션이 비어 CSRFstate검증 실패- 프록시 환경에서
Host헤더가 바뀌어 콜백 URL을 잘못 계산
먼저 확인할 것: OAuth 리다이렉트 URI는 1바이트도 달라지면 실패한다
운영에서 가장 흔한 실수는 “등록한 리다이렉트 URI”와 “실제로 생성되는 콜백 URL”이 다르게 되는 것입니다.
체크리스트:
- 스킴이
https인지 - 도메인이 정확히 일치하는지(서브도메인 포함)
- 포트가 포함되는지(
:443은 보통 생략되지만, 일부 프레임워크는 환경에 따라 붙입니다) - 경로가 정확히 일치하는지(
/oauth/callbackvs/oauth/callback/) - 쿼리 파라미터 포함 여부(대부분 금지 또는 고정값만 허용)
이 불일치가 있으면 OAuth 제공자에서 바로 에러를 내기도 하지만, 일부 구현에서는 앱이 다시 로그인 시작점으로 리다이렉트하면서 “무한 로그인 루프”처럼 보이기도 합니다.
Nginx에서 반드시 전달해야 하는 프록시 헤더
HTTPS 종단이 Nginx에서 끝나고, 업스트림은 HTTP로 받는 구조(TLS termination)에서는 앱이 원래 요청 스킴이 https였다는 사실을 헤더로 전달받아야 합니다.
아래는 OAuth 콜백 문제를 줄이는 “기본형”입니다.
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
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_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
핵심은 proxy_set_header X-Forwarded-Proto $scheme; 입니다. 이게 없으면 앱은 자신이 http로 요청받았다고 판단해 콜백 URL, 절대경로 리다이렉트, 쿠키 Secure 처리 등을 잘못합니다.
무한 리다이렉트의 1순위 원인: 앱이 HTTPS를 모른다
현상
- 브라우저 네트워크 탭에서
302가 반복 Location헤더가http://example.com/...로 내려오고, 브라우저가 HSTS 또는 Nginx 리다이렉트 정책으로 다시https://...로 바꾸며 루프
해결
- Nginx에서
X-Forwarded-Proto전달 - 앱 프레임워크에서 “프록시 신뢰” 설정 활성화
예시: Express(세션/쿠키 포함)
import express from 'express'
import session from 'express-session'
const app = express()
// 프록시 뒤에 있을 때 필수
app.set('trust proxy', 1)
app.use(session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: {
secure: true,
sameSite: 'lax'
}
}))
예시: Spring Boot(리버스 프록시 헤더 처리)
server:
forward-headers-strategy: framework
프레임워크가 X-Forwarded-*를 신뢰하도록 설정하지 않으면, Nginx가 헤더를 보내도 앱이 무시할 수 있습니다.
OAuth 콜백에서만 세션이 사라지는 이유: SameSite·Secure·도메인
OAuth는 대개 다음 흐름입니다.
- 우리 서비스에서 로그인 시작
- OAuth 제공자 페이지로 이동(다른 도메인)
- 제공자가 우리 서비스 콜백으로 다시 이동
이때 2번과 3번 사이에서 브라우저는 쿠키 정책을 엄격하게 적용합니다. 특히 state 검증(세션 기반)이 있는 구현이라면, 콜백에서 세션 쿠키가 안 붙는 순간 로그인 플로우가 깨지고 “다시 로그인 시작”으로 되돌아가 루프가 됩니다.
권장 쿠키 설정
- HTTPS 운영이면 세션 쿠키는
Secure=true - 일반적인 OAuth 리다이렉트는
SameSite=Lax로 충분한 경우가 많음 - 만약
POST기반 콜백 또는 iframe/서드파티 컨텍스트가 있으면SameSite=None이 필요할 수 있고, 이 경우Secure=true가 필수
주의: SameSite=None인데 Secure=false면 최신 브라우저에서 쿠키가 폐기됩니다.
502의 대표 원인: 업스트림 연결/타임아웃/리졸브
OAuth 콜백 처리에서는 토큰 교환을 위해 외부로 HTTP 호출을 하는 경우가 많습니다. 이때 업스트림이 느려지면 Nginx가 upstream timed out로 502를 냅니다.
Nginx 에러 로그에서 먼저 확인
sudo tail -n 200 /var/log/nginx/error.log
자주 보이는 패턴:
connect() failed (111: Connection refused) while connecting to upstreamupstream timed out (110: Connection timed out) while reading response header from upstreamno live upstreams
타임아웃을 현실적으로 조정
콜백에서 토큰 교환/유저정보 조회가 포함되면 1~3초 이상 걸릴 수 있습니다. 기본값이 짧거나, 업스트림이 순간적으로 지연되면 502가 납니다.
location / {
proxy_pass http://127.0.0.1:8080;
proxy_connect_timeout 5s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
send_timeout 30s;
}
다만 타임아웃을 늘리는 것은 “증상 완화”일 뿐입니다. 콜백 처리 코드가 외부 API에 의존한다면, 지연/실패에 대한 방어(재시도, 서킷브레이커, 비동기 처리)를 함께 고민해야 합니다. 분산 환경에서 장애 전파를 줄이는 관점은 MSA에서 Saga 보상 트랜잭션 설계 체크리스트도 참고할 만합니다.
프록시 리다이렉트 교정: proxy_redirect와 절대 URL
앱이 http://127.0.0.1:8080 같은 내부 주소로 리다이렉트를 만들어버리는 경우가 있습니다. 이때 브라우저는 내부 주소로 접근할 수 없고, 흐름이 깨지거나 루프가 됩니다.
가능한 해결:
- 앱에서 외부 베이스 URL을 명시(권장)
- Nginx에서
proxy_redirect로 보정(임시 처방)
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect http://127.0.0.1:8080/ https://example.com/;
}
근본적으로는 앱이 Host와 X-Forwarded-Proto를 기반으로 올바른 절대 URL을 생성하도록 만드는 게 안전합니다.
HTTP에서 HTTPS로 강제 리다이렉트 시 주의점
80 포트에서 443으로 넘기는 설정 자체는 흔하지만, 잘못하면 OAuth 콜백과 충돌할 수 있습니다.
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
}
여기서도 $host가 예상과 다르게 들어오면(예: 내부 로드밸런서 헬스체크, 잘못된 Host 헤더) 리다이렉트가 꼬일 수 있습니다. OAuth 제공자에 등록한 도메인과 실제 리다이렉트 도메인이 달라지지 않도록, 운영에서는 canonical host를 강제하는 편이 안전합니다.
디버깅 루틴: 15분 안에 원인 좁히기
1) 브라우저에서 리다이렉트 체인 확인
- 네트워크 탭에서
302반복 여부 Location이http로 내려오는지https인지- 콜백 요청에 쿠키가 붙는지
2) Nginx access/error 로그에서 콜백 경로만 필터
sudo grep -E "oauth|callback" /var/log/nginx/access.log | tail -n 100
sudo grep -E "upstream|oauth|callback" /var/log/nginx/error.log | tail -n 200
3) curl로 헤더만 재현
curl -I https://example.com/oauth/callback
Location이 이상한지Set-Cookie에Secure/SameSite가 기대대로인지
4) 업스트림 직접 호출
Nginx를 거치지 않고 업스트림이 정상인지 확인합니다.
curl -I http://127.0.0.1:8080/oauth/callback
여기서부터 느리거나 5xx면 Nginx 문제가 아니라 앱 문제일 확률이 큽니다.
운영 환경(컨테이너/서버리스)에서의 추가 함정
- 컨테이너가 재시작/스케일링되면서 세션이 유실(메모리 세션 사용 시)
- 콜백 처리 중 외부 통신 지연으로 502 발생
특히 서버리스/오토스케일 환경에서는 콜드스타트나 순간 부하로 콜백이 느려질 수 있습니다. Cloud Run 계열을 쓴다면 GCP Cloud Run 503·콜드스타트 줄이는 설정 7가지처럼 “요청 지연 자체를 줄이는 튜닝”이 OAuth 성공률에 직접 영향을 줍니다.
세션을 서버 메모리에 두는 방식이라면, OAuth state 검증이 인스턴스 간에 깨질 수 있으니 Redis 같은 외부 세션 스토어를 고려하세요.
실전 권장 설정 묶음(요약)
- Nginx에서 다음 헤더를 항상 전달
Host,X-Forwarded-Proto,X-Forwarded-For
- 앱에서 프록시 신뢰 설정 활성화
- 세션 쿠키는 HTTPS에서
Secure=true - OAuth
redirect_uri는 등록값과 완전 일치 - 502가 보이면 에러 로그에서
upstream키워드로 먼저 분류(연결 거부 vs 타임아웃)
체크리스트: 이 조합이면 대부분 끝난다
- Nginx:
proxy_set_header X-Forwarded-Proto $scheme; - 앱: 프록시 신뢰(
trust proxy또는forward-headers-strategy) - 쿠키:
Secure/SameSite정확히 - OAuth 콘솔:
https://example.com/...콜백 URI 정확히 - 502면: 업스트림 상태/타임아웃/외부 API 지연 확인
여기까지 맞춰도 간헐적으로만 문제가 난다면, 그때는 “콜백 처리 경로의 지연/실패가 전체 로그인 플로우를 깨는 구조”일 수 있습니다. 이 경우 콜백에서 꼭 필요한 최소 작업만 수행하고(토큰 교환, 사용자 식별), 나머지 프로필 동기화/권한 계산은 비동기로 넘기는 방식이 운영 안정성에 유리합니다.