🚀 Flask 백엔드 배포 & CORS 문제 해결기 (AWS EC2 + DuckDNS)
1️⃣ 프로젝트 개요
- 백엔드: Flask + Gunicorn
- 서버: AWS EC2 (Amazon Linux)
- 프록시 서버: Nginx
- 도메인: DuckDNS (leeturnpy.duckdns.org)
- SSL 인증서: Certbot 이용
- 프론트엔드: Vercel 배포
2️⃣ 작업 순서
✅ 1. EC2 서버 설정
- Amazon Linux 인스턴스 생성
- Python 가상환경(.venv) 설정
- Flask 프로젝트 배포
✅ 2. Gunicorn 실행 스크립트 작성
- launch.sh / terminate.sh 스크립트로 서버 관리
# launch.sh 예시
gunicorn -w 4 -b 127.0.0.1:8000 app:application
✅ 3. Nginx 리버스 프록시 & SSL 설정
- DuckDNS로 도메인 연결
- Certbot으로 SSL 인증서 발급
server {
listen 443 ssl;
server_name leeturnpy.duckdns.org;
ssl_certificate /etc/letsencrypt/live/leeturnpy.duckdns.org/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/leeturnpy.duckdns.org/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_ssl_verify off;
}
}
3️⃣ ⚡ 발생한 주요 오류 & 해결 과정
❌ [문제 1] Certbot 설치 이슈
- Amazon Linux에서 snap 미지원으로 인한 설치 실패
- 해결: yum + pip 혼합 설치로 진행, DNS 인증 방식 사용
❌ [문제 2] CORS 에러 지옥
- 프론트(Vercel) ➡️ 백엔드(DuckDNS) API 호출 시 지속적인 CORS 에러 발생
🔹 원인
- Flask와 Nginx에서 CORS 헤더 중복 설정
- 브라우저 에러 메시지:
Origin header contains multiple values ... only one is allowed.
🎯 최종 해결 방법
- Nginx에서 CORS 설정 제거
- Flask에서만 CORS 관리
from flask_cors import CORS
CORS(application, resources={r"/*": {"origins": "https://oz-flask-form.vercel.app"}}, supports_credentials=True)
- Nginx는 프록시 역할만 수행
❌ [문제 3] Nginx 설정 오류
- location 블록 주석 처리 중 중괄호 오류 발생
[emerg] "location" directive is not allowed here
- 해결: 주석 처리 시 중괄호 정리
❌ [문제 4] DB 연결 테스트 시 에러
- SQLAlchemy 사용 시 text() 누락
ArgumentError: Textual SQL expression 'SELECT 1' should be explicitly declared as text('SELECT 1')
- 해결: 올바른 구문으로 수정
from sqlalchemy import text
db.session.execute(text('SELECT 1'))
4️⃣ 🎉 최종 결과
- https://leeturnpy.duckdns.org/ 에서 API 정상 동작
- 프론트엔드와 백엔드 API 연동 성공!
- CORS 문제 완벽 해결 💪
5️⃣ 📝 느낀점 & 팁
- CORS 문제는 무조건 서버 하나에서만 관리
- Nginx는 가급적 프록시 역할에만 충실하게!
- SSL 설정 시 Certbot + DuckDNS 조합 추천
- 서버 설정 후에는 항상 nginx -t로 점검 습관 들이기
✅ 마무리
처음부터 끝까지 수많은 삽질 끝에 얻은 값진 경험! 같은 문제로 고생하는 분들께 도움이 되길 바랍니다 😄
🌐 CORS란?
CORS (Cross-Origin Resource Sharing)
👉 교차 출처 리소스 공유 라고 해!
🎯 쉽게 설명하면?
브라우저는 보안 때문에,
"다른 출처(도메인)의 서버에 함부로 요청하지 마!" 라고 기본적으로 막아놨어.
하지만 요즘 웹은 프론트엔드와 백엔드가 분리되어 있잖아?
- 프론트: https://oz-flask-form.vercel.app
- 백엔드(API): https://leeturnpy.duckdns.org
이렇게 도메인이 다르면 브라우저가:
❌ "어? 다른 출처인데? 이거 위험할 수도 있어!"
요청 차단!!
이게 바로 CORS 정책이야.
🚨 예시
- 같은 출처
프론트와 API가 같은 도메인이라면 → 문제 없음! - 다른 출처 (Cross-Origin)
프론트에서 다른 도메인으로 요청하면 → 브라우저가 차단!
그래서 서버가 아래와 같은 응답을 줘야 해.
arduino
복사편집
Access-Control-Allow-Origin: https://oz-flask-form.vercel.app
➡️ 그러면 브라우저가
"아~ 서버가 허락했네? 요청 허용해줄게!" 라고 풀어주는 거지.
✅ 정리하면?
구분설명
CORS | 교차 출처 요청을 제어하는 보안 정책 |
왜 필요할까? | 다른 도메인 간 데이터 요청 시 보안 유지 |
누가 막을까? | 브라우저가 차단 (서버가 아님!) |
해결 방법 | 서버가 허용 헤더를 추가해줘야 함 |
⚡ 그래서 상빈님이 한 일은?
- Flask에서 CORS 설정
"이 프론트는 내 API 사용해도 돼!" 라고 서버에 허락 코드 넣기. - Nginx 중복 설정 제거
중복 허락 때문에 브라우저가 헷갈려서 차단했던 것 해결!
😄 쉽게 비유하자면?
- CORS = 클럽 입장 심사 기준 🎤
- 브라우저 = 클럽 경비원
- 프론트엔드 = 입장하려는 손님
- 백엔드 = 클럽 주인
'기술블로그' 카테고리의 다른 글
📂 프론트엔드 파일 구조 설명 (0) | 2025.04.28 |
---|---|
리눅스 서버 관리 필수 명령어 정리 (Flask + Nginx + AWS) (0) | 2025.04.27 |
백엔드 내부(admin용) 페이지(시작단계 확인) (0) | 2025.04.26 |
백엔드, 프론트엔드 로컬 연동 설정 및 검증 진행 (0) | 2025.04.26 |
특정파일만 git push 하고싶을경우 (stash 활용) (0) | 2025.04.25 |