본문 바로가기
IT_알토르/기술 및 코드과제

13. 웹 백엔드 인프라 구축 (EC2 서버 설정, HTTPS 적용, 도메인 연결, 포트포워딩)

by jys275 2025. 5. 8.

백엔드 코드 Github에 업로드

이때, OpenAI Key와 같은 민감 정보는 제외하고 업로드 : API Key 재생성해야 함

 

 

백엔드 코드(app.py) EC2 인스턴스에서 클론 받기

백엔드(Flask) 코드를 GitHub에 올려놓았음 : 그걸 AWS EC2 서버 안으로 복사해 오는 과정 : EC2 서버(Ubuntu)에 SSH 접속 후, git clone 명령어로 GitHub의 코드를 EC2 안에 다운로드해야 함

 

Git 설치(EC2 서버 SSH 접속한 환경의 홈 디렉토리에서 실행)

- sudo apt update

- sudo apt install git -y 


깃허브에서 백엔드 코드 클론
- git clone 깃허브 주소


디렉토리 이동, 코드 확인
- cd portfolio-backend
- ls

즉, EC2 서버에서 GitHub 백엔드 코드(app.py) 클론(다운로드) 받기까지 성공한 상태인 것

 

 

백엔드 코드 EC2 인스턴스에서 실행하기

필요한 패키지 설치(파이썬)

- sudo apt install python3-pip -y

필요한 패키지 설치(Flask)

지금 사용하는 Ubuntu 환경(Python 3.12)에서는 시스템 안정성을 위해 기본적으로 pip install을 막고 있음 : 가상환경 또는 우회 설치 옵션 중 하나를 선택해야 함 : 가상환경 생성 후 Flask 설치하기

sudo apt install python3.12-venv -y     // venv 패키지 설치
python3 -m venv venv     // venv(가상환경) 생성
source venv/bin/activate     // 가상환경 활성화, 프롬프트 앞에 (venv) 표시가 생기면 성공
pip install flask flask-cors requests     // 가상환경 안에서 필요한 패키지 설치
python app.py

Running on all addresses (0.0.0.0) : 0.0.0.0 : 모든 네트워크 인터페이스에서 접근 허용 : 즉, 외부에서도 접근 가능 : 단, AWS 보안 그룹 포트가 열려 있어야 함 : Running on http://127.0.0.1:5001 : 127.0.0.1 : 서버 자신만 접근 가능 (localhost) : Running on http://172.31.37.6:5001 : 172.31.37.6 : EC2 내부 IP : 내부 통신에 사용되므로 같은 VPC에 있는 인스턴스만 접근 가능

 

백엔드(Flask) 코드를 app.run(port=5001)으로 코딩했었음 : 이 서버가 로컬(내 컴퓨터)에서만 실행되면 외부에서는 접근할 수 없음 : 예 : 127.0.0.1:5001 : 내 컴퓨터에서만 작동 : 프론트엔드(Vercel에 올라간 웹사이트)에서 이 API를 쓰고 싶어도 연결 안 됨 : 그래서 AWS EC2 리눅스 서버를 활용해서 외부에서 접속 가능한 서버를 열어야 함 : 어떻게? : 0.0.0.0:5001로 서버를 열기 : 예 : http://<퍼블릭 IP>:5001를 통해 전 세계 어디서든 요청 가능 : 즉, EC2 서버도 5001 포트를 외부에 개방해줘야 함 : 보안 그룹에서 5001 포트를 열어야함

 

API 요청 테스트

API 요청을 테스트할 수 있는 도구인 Postman(https://www.postman.com/downloads/) 사용 : Body 탭 클릭 : raw 선택 : JSON 선택 : 다음과 같은 JSON 작성 : {"message": "자기소개 해줘",  "thread_id": null}

5001 포트를 개방하지 않고 API 요청

보안 그룹에서 5001 포트를 열지 않았다면 외부(브라우저, 프론트엔드 등)에서 절대 접근 불가 : AWS에서는 보안 그룹이 방화벽 역할을 함 : 허용한 포트 외에는 모두 차단 : 즉, 위와 같이 사용자가 입력한 메시지 : "message": "자기소개 해줘"라는 데이터를 POST 방식으로 서버로 보냈을 때 응답이 오지 않음

 

5001 포트를 개방하고 API 요청

AWS 인바운드 규칙 추가 : 5001 포트 개방

 

보안 그룹에서 5001 포트를 추가한 이후에는 아래와 같이 API 응답이 정상적이게 돌아오는 것을 확인

 

 

Let’s encrypt를 이용하여 https로 전환, Ngnix에서 포트포워딩

EC2에 띄운 Flask 백엔드 서버를 https 적용할 것임 : 기존 백엔드 서버는 "http://<퍼블릭 IP>:5001"으로만 열려 있어, 보안되지 않은 상태임 : 실제 웹사이트에서는 사용자 요청이나 API 호출은 반드시 https 기반으로 통신해야 함 : 또한, Vercel 프론트엔드 웹사이트는 https가 사용되고 있기 때문에 포트번호가 애초에 다름 : 기존 백엔드 코드를 사용한다면 요청이 갈 수 없음 : 즉, Let's Encrypt를 사용하여 외부에서 https로 접속 가능하도록 SSL 인증서를 적용할 예정

 

일단 Let's encrypt를 사용하려면, 도메인이 필요함 : <퍼블릭 IP>.com과 같은 IP 기반으로 된 도메인의 인증서를 발급하지 않음 : 즉. 도메인이름.com 같은 메인 도메인이 필요 : 그리고 api.도메인이름.com과 같이 API 서버를 위한 서브 도메인을 생성 : 관습이기도 하며, 역할 분리와 관리 편의를 위해 

 

도메인 구매

가비아(https://www.gabia.com/)에서 도메인 구매 : 아래와 같이 DNS 설정(A 레코드 등록) : 값/위치에 EC2 퍼블릭 IP 주소 입력

저장하면 api.jysdev.com 서브 도메인이 EC2 서버를 가리키게 됨 : 적용되었는지 터미널에서 확인 : ping api.jysdev.com

 

현재까지의 상황 정리

더보기

Flask 백엔드 서버는 app.py에 있음 : portfolio-website-backend/ 폴더 안에서 venv라는 가상환경을 만들어 실행 중 : 서버를 5001번 포트에서 실행시킴 : 지금 원하는 시나리오는 사용자가 'https://api.jysdev.com/sendMessage'로 요청을 보내면 : 실제로는 Flask 백엔드 서버(localhost:5001)가 응답하도록 하고 싶음 : 그런데 Flask는 기본적으로 'http://127.0.0.1:5001' : 내부 로컬 네트워크에서만 동작 : 그래서 Nginx가 나서야 함 : 사용자는 Nginx에게 요청 : Nginx는 Flask에게 대신 전달 (Proxy) : 응답을 다시 돌려줌

 

이제 도메인 주소 : 'api.jysdev.com'가 HTTPS가 적용되길 바람 : 그러면 적용된 'https://api.jysdev.com' 도메인이 사용자에게 공개되는 API 주소(443포트, 보안 연결) : Nginx가 외부 HTTPS 요청을 받아 Flask 서버로 전달(proxy 역할) : Flask(app.py)는 실제로 OpenAI API에 요청하고 응답 생성 : 5001 포트는 Flask 서버가 실행되고 있는 포트 (내부 전용) : 443 포트는 HTTPS 요청 수신 포트 (외부 공개)

즉, 클라이언트는 Flask를 직접 몰라도 됨 : 오직 'https://api.jysdev.com'만 사용하면 됨 : 모든 보안, 경로 중계는 Nginx가 알아서 처리할 예정

 

Certbot 설치 (Let's Encrypt를 위한 도구)
Certbot은 Let's Encrypt에서 무료로 SSL 인증서를 자동 발급 및 설정해 주는 툴 : EC2에 접속한 상태에서 아래 명령을 실행

sudo apt install certbot python3-certbot-nginx -y

 

 

이후에 도메인이 진짜 본인의 도메인인지 확인을 먼저 해야 함 : 도메인 소유 인증(DV) : 어떻게? : Certbot이 도메인에 요청을 보냄 : 그 요청이 내 서버(Nginx)에 도착해서 특정 응답을 반환하는지 확인해야 함 : 확인이 되면 인증서를 발급해줌 : 이 인증을 받으려면 HTTP로 요청을 수신할 수 있어야함 : 그러면 Nginx가 listen 80으로 열려 있어야 함 : 즉, Cerbot은 HTTP를 통해 도메인 확인을 먼저 시도하기 때문에, Certbot보다 미리 Nginx 설정을 만들어 api.jysdev.com 도메인이 HTTP 요청을 수신할 수 있게 해야함 

 

Nginx HTTP 구성

1. Nginx 설정 파일 생성

Nginx 설정 디렉토리에서 도메인용 config 파일 생성

sudo nano /etc/nginx/sites-available/api.jysdev.com

 

2. Nginx 설정 내용

위의 설정 파일에 아래와 같은 내용 입력

# 80번 포트(HTTP)에서 api.jysdev.com 도메인으로 들어오는 요청 처리
server {
    listen 80;  # HTTP 요청 수신
    server_name api.jysdev.com;  # 이 도메인으로 들어온 요청만 해당 설정 적용

    # 모든 요청을 내부 Flask 서버로 전달 (http://127.0.0.1:5001)
    location / {
        proxy_pass http://127.0.0.1:5001;  # Flask 서버 포트
        proxy_set_header Host $host;  # 원래 요청한 도메인 정보 전달
        proxy_set_header X-Real-IP $remote_addr;  # 사용자 IP 전달
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;  # 프록시 경유 정보
        proxy_set_header X-Forwarded-Proto $scheme;  # HTTP 또는 HTTPS 여부 전달
    }
}

Ctrl + O : 저장 : Enter : Ctrl + X : 종료

 

3. 설정을 sites-enabled에 링크해서 Nginx가 읽도록 하기

# 설정 파일을 활성화하는 symbolic link 생성
sudo ln -s /etc/nginx/sites-available/api.jysdev.com /etc/nginx/sites-enabled/

 

4. 설정 파일에 문법 오류가 없는지 확인

 

5. Nginx 재시작 (설정 적용)

# 설정 변경 사항을 반영하여 Nginx 다시 시작
sudo systemctl restart nginx

 

Certbot을 이용한 SSL 인증서 발급 (HTTPS 적용)

# Certbot 실행 : Nginx 설정을 기반으로 도메인 인증 및 SSL 설정 자동화
sudo certbot --nginx -d api.jysdev.com

이메일 주소 입력 : 인증서 갱신 실패 시 알림 받을 주소 : 약관 동의 : Y 입력 : 기록 저장 여부 : N 해도 무방 : 인증서 경로 /etc/... : HTTPS 연결 시 사용할 인증서 및 개인키 저장 위치 : 자동 갱신 설정 완료 : 인증서가 90일짜리 : cron으로 자동 갱신까지 예약됨 : 최종 결과 : HTTPS 주소 접속 가능 : 보안 연결, 브라우저 주소창 자물쇠 표시 : 지금부터는 http://<퍼블릭 IP>:5001과 같은 IP + 포트 형식은 안 써도 됨 : 오직 https://api.jysdev.com 형태만 노출되면 됨

 

Nginx 포트 포워딩 작동 확인

현재까지 AWS EC2 보안 그룹에서 22(SSH), 80(HTTP), 5001(Flask, Nginx 내부 포워딩용)포트만 열려 있는 상태 : 이제 443 포트도 개방해야 함 : HTTPS용 : 외부 브라우저 요청 허용 : 보통 5001은 EC2 내부용이므로, 443만 외부에 개방되어 있으면 충분

 

Postman을 통해 https://api.jysdev.com/sendMessage에 Post 요청을 보내기 : 응답이 정상적으로 돌아옴 : 443 → 5001 포워딩이 정상적으로 작동하고 있다는 것을 확인할 수 있음