기술블로그

Flask 백엔드 배포 & CORS 문제 해결기 (AWS EC2 + DuckDNS)

Chansman 2025. 4. 27. 04:45

🚀 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️⃣ 🎉 최종 결과


5️⃣ 📝 느낀점 & 팁

  • CORS 문제는 무조건 서버 하나에서만 관리
  • Nginx는 가급적 프록시 역할에만 충실하게!
  • SSL 설정 시 Certbot + DuckDNS 조합 추천
  • 서버 설정 후에는 항상 nginx -t로 점검 습관 들이기

✅ 마무리

처음부터 끝까지 수많은 삽질 끝에 얻은 값진 경험! 같은 문제로 고생하는 분들께 도움이 되길 바랍니다 😄

 

🌐 CORS란?

CORS (Cross-Origin Resource Sharing)
👉 교차 출처 리소스 공유 라고 해!


🎯 쉽게 설명하면?

브라우저는 보안 때문에,
"다른 출처(도메인)의 서버에 함부로 요청하지 마!" 라고 기본적으로 막아놨어.

하지만 요즘 웹은 프론트엔드와 백엔드가 분리되어 있잖아?

이렇게 도메인이 다르면 브라우저가:

❌ "어? 다른 출처인데? 이거 위험할 수도 있어!"
요청 차단!!

이게 바로 CORS 정책이야.


🚨 예시

  1. 같은 출처
    프론트와 API가 같은 도메인이라면 → 문제 없음!
  2. 다른 출처 (Cross-Origin)
    프론트에서 다른 도메인으로 요청하면 → 브라우저가 차단!

그래서 서버가 아래와 같은 응답을 줘야 해.

arduino
복사편집
Access-Control-Allow-Origin: https://oz-flask-form.vercel.app

➡️ 그러면 브라우저가
"아~ 서버가 허락했네? 요청 허용해줄게!" 라고 풀어주는 거지.


✅ 정리하면?

구분설명
CORS 교차 출처 요청을 제어하는 보안 정책
왜 필요할까? 다른 도메인 간 데이터 요청 시 보안 유지
누가 막을까? 브라우저가 차단 (서버가 아님!)
해결 방법 서버가 허용 헤더를 추가해줘야 함

⚡ 그래서 상빈님이 한 일은?

  1. Flask에서 CORS 설정
    "이 프론트는 내 API 사용해도 돼!" 라고 서버에 허락 코드 넣기.
  2. Nginx 중복 설정 제거
    중복 허락 때문에 브라우저가 헷갈려서 차단했던 것 해결!

😄 쉽게 비유하자면?

  • CORS = 클럽 입장 심사 기준 🎤
  • 브라우저 = 클럽 경비원
  • 프론트엔드 = 입장하려는 손님
  • 백엔드 = 클럽 주인