알토르 5주차 과제
- EC2서비스에 github에 있는 파이썬 코드 clone을 해오기
- 파이썬코드를 EC2서비스에서 실행시키기
- SSH연결 된 윈도창을 꺼도 파이썬코드 실행이 되게끔 만들기
- 서브도메인을 생성하기
- api.도메인.com
- 서브도메인을 화면에 입력하면 welcome to nginx
- 서브도메인 SSL인증서 설치, let’s encrypt를 이용해보기
- 80번 포트 ⇒ 443포트
1. EC2 Instance에 github에 있는 파이썬 코드 clone을 해오기

2. 파이썬코드를 EC2서비스에서 실행시키기
🔥 Flask 프로젝트에서 venv를 써야 하는 이유
- 패키지 충돌 방지
전역 파이썬에 Flask, SQLAlchemy, requests 등 설치하다 보면
다른 프로젝트랑 버전 충돌 발생 가능 (Flask는 버전 차이 크다) - 환경 복제 용이
requirements.txt만 있으면 협업자가 동일 환경 재현 가능
pip freeze > requirements.txt
pip install -r requirements.txt
- 배포 대비
나중에 AWS, Docker, Kubernetes에 올릴 때도
venv 기반 의존성 관리가 표준이에요.
📌 실습 예시
1. 가상환경 생성
apt install update
apt-get install python3-venv -y
python3 -m venv venv
2. 활성화
- 리눅스 / 맥:
source venv/bin/activate
- 윈도우 (PowerShell):
venv\Scripts\Activate.ps1

3. Flask 설치
pip install flask
pip install flask-cors dotenv openai
vi .env
###
OPENAI_KEY=sk-***
ASSISTANT_KEY=skk-***
###


xxx
4. 실행
python app.py

3. SSH연결 된 윈도창 종료 후 파이썬코드 실행이 되게끔 만들기
🚀 Flask 앱을 EC2에서 systemd 서비스로 등록하는 방법
1️⃣ 서비스 실행 사용자 확인
EC2 기본 계정이 보통 ec2-user (Amazon Linux) 또는 ubuntu (Ubuntu) 입니다.
👉 해당 계정을 확인:
whoami
2️⃣ Flask 앱 경로 확인
/home/ubuntu/flask-chat-app/
app.py 실행 파일과 venv/ 가 그 안에 있다고 가정합니다.
3️⃣ 서비스 파일 작성
nano /etc/systemd/system/flaskapp.service
내용:
[Unit]
Description=Flask App
After=network.target
[Service]
User=ubuntu
WorkingDirectory=/home/ubuntu/flask-chat-app
ExecStart=/home/ubuntu/flask-chat-app/venv/bin/python app.py
Restart=always
[Install]
WantedBy=multi-user.target
[Unit]
Description=Flask App
After=network.target
[Service]
User=ubuntu
WorkingDirectory=/home/ubuntu/app
EnvironmentFile=/home/ubuntu/app/.env
ExecStart=/usr/bin/python3 /home/ubuntu/app/app.py
Restart=always
[Install]
WantedBy=multi-user.target
⚠️ User와 WorkingDirectory 경로는 본인 환경에 맞게 수정해야 합니다.
(ec2-user인지 ubuntu인지 꼭 확인)
4️⃣ 서비스 등록 & 실행
systemctl daemon-reload
systemctl start flaskapp
systemctl enable flaskapp
5️⃣ 상태 확인
systemctl status flaskapp
6️⃣ 로그 확인
journalctl -u flaskapp -f
✅ 이렇게 하면:
- SSH 꺼도 계속 실행됨
- EC2 재부팅해도 자동 실행됨
systemctl stop flaskapp / systemctl restart flaskapp 으로 제어 가능

FAIL

flaskapp.service 파일 경로 수정
ACTIVE

🚀 배포 단계 (한 서버 Flask + React)
1️⃣ React 빌드하기
EC2 안에서:
apt npm install
npm install next react react-dom
cd react-app # React 프로젝트 디렉토리 # package.json 있는 폴더
npm install
npm run build
→ react-app/build/ 폴더가 생성됩니다.
2️⃣ Flask에 정적 파일 연결
Flask 프로젝트 구조를 다음처럼 정리:
flask-chat-app/
├─ app.py
├─ venv/
├─ static/ ← React build 파일 넣을 곳
└─ templates/ ← index.html 넣을 곳
react-app/build/static/ → flask-chat-app/static/ 으로 복사
react-app/build/index.html → flask-chat-app/templates/ 로 복사
3️⃣ Flask 코드 수정
app.py에 React 프론트 서빙 추가:
from flask import Flask, send_from_directory, render_template
app = Flask(__name__, static_folder="static", template_folder="templates")
# API 엔드포인트 예시
@app.route("/api/hello")
def hello():
return {"message": "Hello from Flask API"}
# React 프론트 (index.html) 제공
@app.route("/", defaults={"path": ""})
@app.route("/<path:path>")
def serve(path):
if path != "" and (app.static_folder / path).exists():
return send_from_directory(app.static_folder, path)
else:
return render_template("index.html")
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000)
4️⃣ 실행
cd flask-chat-app
source venv/bin/activate
python app.py
→ 이제 Flask가 /api/... 요청은 API로 처리하고, 나머지는 React index.html을 돌려줍니다.
5️⃣ 운영환경 적용
앞서 설명드린 대로 systemd 서비스로 등록해두면
SSH 꺼도 계속 실행
서버 재부팅해도 자동 실행
됩니다.
✅ 정리
React는 EC2에서 빌드 필수 (npm run build)
빌드 결과물(build/)을 Flask 프로젝트 안 static/ + templates/ 에 옮겨서 같이 서비스
Flask 하나로 API + 프론트 동시에 제공 가능
⚡ 포트폴리오용 한 서버 배포 팁
Next.js는 기본적으로 서버 사이드 렌더링(SSR)을 사용합니다.
포트폴리오용으로 Flask와 한 서버에서 쓰려면:
정적 HTML export
npm run export
out/ 폴더 생성
HTML, JS, CSS 파일만 포함 → Flask static/templates로 옮길 수 있음
Flask 프로젝트 구조 예시
flask-chat-app/
├─ app.py
├─ venv/
├─ static/ ← out/_next + static 파일 복사
└─ templates/ ← out/index.html + 다른 html
Flask에서 정적 파일 서빙
from flask import Flask, render_template
app = Flask(__name__, static_folder="static", template_folder="templates")
@app.route("/", defaults={"path": ""})
@app.route("/<path:path>")
def serve(path):
return render_template("index.html")
🔑 원인
npm install 시 Killed 메시지
→ 보통 메모리 부족(Out of Memory, OOM) 때문에 설치가 중간에 죽는 현상
→ EC2 인스턴스가 t2.micro / t3.micro 같이 메모리가 1GB 정도라면 Next.js 같은 패키지 설치/빌드가 충분하지 않습니다.
그래서 node_modules/.bin/next가 제대로 설치되지 않았고, system이 next를 찾을 수 없는 상태입니다.
✅ 해결 방법
1️⃣ 스왑 공간(Swap) 추가
메모리가 부족할 때 가장 간단한 해결책입니다.
-# 1GB 스왑 파일 생성
fallocate -l 1G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile

-# 확인
free -h

sudo chown -R ubuntu:ubuntu /home/ubuntu/manta
npm install
npm run build

로컬 서버 = next.js server
EC2 서버 = flask server
해결 방법
next.config.mjs 수정
/** @type {import('next').NextConfig} */
const nextConfig = {
output: "export", // ← 정적 사이트 내보내기
};
export default nextConfig;
빌드 실행
npm run build
결과 확인
.next/ 대신 out/ 폴더가 생김
안에 HTML, CSS, JS 파일 있음 → 그대로 웹서버에 올리면 됨
로컬에서 빌드
npm run build
npm run export # next.config.mjs에 output: "export" 옵션 필요
→ out/ 폴더 생김 (정적 HTML + JS + CSS)
EC2로 업로드
scp -r out/* ubuntu@<EC2_IP>:/var/www/html/
→ Nginx/Apache 같은 웹서버가 정적 파일 서빙
Flask 서버
같은 EC2에서 5000번 포트 등으로 실행
Nginx에서 /api → Flask, / → Next.js 정적 파일로 분기 가능
4. 서브도메인을 생성하기
4-1. api.도메인.com
- 서브도메인을 화면에 입력하면 welcome to nginx
4-2. 서브도메인 SSL인증서 설치, let’s encrypt를 이용해보기
4-3. 80번 포트 ⇒ 443포트
- http://api.도메인.com, https://api.도메인.com



1. 사전 준비
서브도메인 DNS 레코드 설정
예: sub.example.com → 서버 IP 주소로 A레코드 설정
서버 접근 권한
root 계정 또는 sudo 권한이 있는 계정 필요
도메인 연결 확인
ping sub.example.com 실행 시 해당 서버 IP로 응답 나와야 함
2. Certbot 설치 (Let’s Encrypt 클라이언트)
Ubuntu 기준:
apt update
apt install certbot python3-certbot-nginx -y # Nginx용
- # Apache일 경우
apt install certbot python3-certbot-apache -y
3. SSL 인증서 발급
(1) Nginx 사용 시
certbot --nginx -d sub.example.com
(2) Apache 사용 시
certbot --apache -d sub.example.com
(3) 웹서버 직접 제어 불가 (예: 워드프레스, API 서버만 돌릴 때) →
standalone 모드
systemctl stop nginx # 또는 apache2
certbot certonly --standalone -d sub.example.com
systemctl start nginx

- 인증서 자동 갱신 설정
Let’s Encrypt 인증서는 90일 유효 → cron으로 자동 갱신 필요
sudo crontab -e
다음 라인 추가:
0 3 * * * /usr/bin/certbot renew --quiet

5. 인증서 위치
기본 경로:
/etc/letsencrypt/live/sub.example.com/
├── fullchain.pem # 인증서
└── privkey.pem # 개인키
웹서버 설정 파일에서 이 경로를 사용해야 함.

6. 설치 확인
브라우저에서 https://sub.example.com 접속 후 🔒 잠금 아이콘 정상 표시되는지 확인.
CLI:
curl -I https://sub.example.com
정상 응답 시 HTTP/1.1 200 OK 와 함께 SSL 동작 확인 가능.



포트포워딩
http://(80번 포트)로 들어오는 요청을 https://(443번 포트)로 자동 전환(리다이렉트)하는 방법
🔹 1. Nginx 환경
/etc/nginx/sites-available/sub.example.com 같은 서버 블록 파일을 열고:
server {
listen 80;
server_name sub.example.com;
# 모든 요청을 HTTPS로 리다이렉트
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name sub.example.com;
ssl_certificate /etc/letsencrypt/live/sub.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/sub.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8080; # 예시: 백엔드 서버
}
}
🔹 안전하고 단순한 HTTP → HTTPS 리다이렉트 설정
server {
listen 80;
listen [::]:80;
server_name aws.orkr.shop;
# 모든 요청을 HTTPS로 리다이렉트
return 301 https://$host$request_uri;
}
if문 불필요
Certbot이 관리하는 블록이라도, 이 블록을 수정 후 sudo nginx -t → sudo systemctl reload nginx 적용 가능
🔹 HTTPS 서버 블록 예시
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name aws.orkr.shop;
ssl_certificate /etc/letsencrypt/live/aws.orkr.shop/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/aws.orkr.shop/privkey.pem;
root /var/www/html;
index index.html index.htm;
location / {
try_files $uri $uri/ =404;
}
}
Nginx 리로드
nginx -t
systemctl reload nginx


1️⃣ Restart (재시작)
sudo systemctl restart nginx
서버를 완전히 종료 후 다시 시작
기존 연결(요청 중인 클라이언트) 모두 끊김
프로세스 완전히 새로 시작 → 모든 설정 적용
장점: 완전히 초기화되므로 문제 발생 시 안전
단점: 서비스 중단 발생 → 사용자 요청 끊김
예시 상황
서버가 다운됐거나, 프로세스가 이상 상태일 때
새로운 모듈이나 Nginx 자체 업데이트 적용
2️⃣ Reload (재시작읽기 / 설정 재적용)
systemctl reload nginx
서버 프로세스는 유지하면서 설정 파일만 다시 읽음
기존 연결은 유지 → 클라이언트 요청 끊기지 않음
변경된 설정만 적용
장점: 무중단으로 설정 변경 가능
단점: 설정 파일 문법 오류 있으면 적용 안 됨
예시 상황
서버 블록 수정
SSL 인증서 교체
리다이렉트, 프록시 경로 변경

🔹 3. iptables / netfilter 로 직접 포트 포워딩
(리다이렉트가 아닌 단순 포트 포워딩)
-# 80 → 443 포트 포워딩
iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 443
영구 적용:
sh -c "iptables-save > /etc/iptables/rules.v4"
⚠️ 이 방법은 HTTP를 HTTPS로 바꿔주는 게 아니라 단순히 80번 연결을 443으로 밀어 넣는 방식이라 브라우저 입장에선 "http:// 요청인데 갑자기 TLS 핸드셰이크"라서 오류가 납니다. 따라서 실제 서비스에서는 iptables가 아닌 웹서버 리다이렉트 방식을 권장합니다.
🔹 4. 클라우드 로드밸런서 (AWS, Azure, GCP)
AWS ALB/ELB, Azure App Gateway, GCP LB 모두 HTTP → HTTPS Redirect Rule을 지원합니다.
예: AWS ALB에서는 Listener (80) → Redirect to 443 설정.
🔹 포트(Port)란?
서버에서 프로그램(서비스)이 네트워크 통신을 구분하기 위해 사용하는 번호
예:
80번 포트 → HTTP 웹 서비스
443번 포트 → HTTPS 웹 서비스
22번 포트 → SSH
🔹 포트 포워딩이란?
👉 외부에서 특정 포트로 들어온 네트워크 요청을 내부의 다른 IP/포트로 전달(전달 경로 변경)하는 기술
즉, 일종의 네트워크 우편물 전달과 같아요.
"집 주소(IP)"는 같은데, "호실 번호(Port)"에 따라 어떤 프로그램으로 연결할지 정해짐
그런데 관리자가 "80번으로 오면 사실은 8080번으로 보내"라고 중간에서 바꿔주는 것이 포트 포워딩
🔹 포트 포워딩의 예시
외부 클라이언트 → 서버
사용자가 http://example.com:80 으로 접속
서버 방화벽 규칙이나 라우터에서 80번 → 8080번으로 포워딩 설정
실제 웹 애플리케이션은 8080 포트에서 동작
결과적으로 사용자는 :8080을 몰라도 접속 가능
가정용 공유기
집에서 게임 서버를 열고 싶을 때, 공유기에서
외부 IP 123.123.123.123:5000 → 집 PC 192.168.0.10:25565 (Minecraft 서버 포트)
외부 친구가 접속하면 공유기가 알아서 내부 PC로 연결
리눅스 iptables
sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
→ 서버에서 80번으로 들어온 요청을 자동으로 8080으로 전달
🔹 포트 포워딩 vs 리다이렉트
포트 포워딩
네트워크 레벨에서 요청을 다른 포트로 "넘겨주는 것"
(클라이언트는 잘 모름)
HTTP 리다이렉트
서버가 응답을 "다시 443으로 접속해라"라고 알려주는 것
(클라이언트가 재접속)
✅ 정리
포트 포워딩 = 네트워크 요청을 내부 다른 포트/서버로 강제로 바꿔치기
주로 사용하는 곳:
공유기 → 내부 서버 접속 허용
서버에서 서비스 포트 숨김/변경
Docker / Kubernetes 포트 매핑 (-p 8080:80)
Frontend -> Nginx -> Flask -> OpenAI -> Openai Assistant
Access to fetch at 'http://localhost:5000/sendMessage' from origin 'https://www.orkr.shop' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.Understand this error
page-188c58bfcfd47cc3.js:1 POST http://localhost:5000/sendMessage net::ERR_FAILED
x @ page-188c58bfcfd47cc3.js:1
onKeyDown @ page-188c58bfcfd47cc3.js:1
iX @ 4bd1b696-4c55c06374f17186.js:1
(anonymous) @ 4bd1b696-4c55c06374f17186.js:1
nS @ 4bd1b696-4c55c06374f17186.js:1
i2 @ 4bd1b696-4c55c06374f17186.js:1
s7 @ 4bd1b696-4c55c06374f17186.js:1
s5 @ 4bd1b696-4c55c06374f17186.js:1Understand this error
684-35f045ab2cb488f7.js:1 TypeError: Failed to fetch
at x (page-188c58bfcfd47cc3.js:1:2852)
at onKeyDown (page-188c58bfcfd47cc3.js:1:6721)
at iX (4bd1b696-4c55c06374f17186.js:1:132394)
at 4bd1b696-4c55c06374f17186.js:1:138472
at nS (4bd1b696-4c55c06374f17186.js:1:18812)
at i2 (4bd1b696-4c55c06374f17186.js:1:133627)
at s7 (4bd1b696-4c55c06374f17186.js:1:159677)
at s5 (4bd1b696-4c55c06374f17186.js:1:159499)
github registry cache 문제로 최신 버전으로 배포 불가
'알토르' 카테고리의 다른 글
| 알토르 6주차 MongoDB (0) | 2026.05.20 |
|---|---|
| 알토르 6주차 과제 추가 (0) | 2026.05.19 |
| 알토르 4주차 과제 - 2 (0) | 2026.05.16 |
| 알토르 4주차 추가 (0) | 2026.05.16 |
| 알토르 4주차 추가 과제 -1 (0) | 2026.05.15 |