클라이언트 : pc나 폰안의 스텁 리졸버
재귀 (Resolver) : isp나 1.1.1.1 / 8.8.8.8 과같은 공개 DNS
권한 네임서버 : 도메인 소유자가 설정한 저장소
루트 네임서버 . : DNS 최상단. TLD NS를 알려줌
TLD ns (.info) : 해당 TLD아래 개별 도메인의 권한 NS 알려줌.
기본 도메인 : toddcanwell.info , naver.com
서브 도메인 : 기본도메인의 왼쪽에 붙는 이름 : 도메인을 여러개의 별도 섹션으로 나누어 고유한 ip address 지정이가능하다.
재귀 리졸버 흐름
클라이언트 스텁 리졸버 → 재귀 리졸버 질의
재귀 리졸버가 루트(.) 네임서버에 물음 → “.info TLD 네임서버는 여기”
.info TLD 네임서버에 물음 → “toddcanwell.info의 권한 NS는 여기”
toddcanwell.info 권한 네임서버에 물음 →
A/AAAA가 있으면 바로 IP 반환
CNAME이면 별칭 따라가 최종 A/AAAA 얻음
재귀 리졸버가 TTL만큼 캐싱 후 클라이언트에 응답
재귀 리졸버에게 캐쉬가 있다면 캐쉬에서 바로 응답해준다.
즉 서브도메인 사용하여 ec2 인스턴스에 연결하면 tls 인증서 발급받기 가능하다.
굳이 추가적으로 도메인살필요없음.
gunicorn : 파이썬 웹서버 : Python WSGI HTTP server
pre-fork 모델 : 마스터 1+ 워커 여러개 프로세스. CPU 코어수에 맞춰 동시성 확보.
동기(synchronous): 워커 1개 = 동시에 1요청 처리(요청 끝날 때까지 그 워커는 묶임).
Flask app : app:app 객체가 프로세스 시작시 한번 로드되어 워크프로스들이 계속 재사용 (앱을 새로실행하는것이아니다.)
*WSGI : Web Server Gateway Interface로 파이썬웹서버 Gunicorn <-> 파이썬 웹앱 Flask 통신 약속
Gunicorn(WSGI 서버) 시작 -> 마스터가 포트바인딩 & 워커들 fork
각 워커가 Flask 앱(WSGI 콜러블)을 메모리에 로드하고 대기하다가 요청이 오면 해당 워커가 앱을 호출 -> 응답 생성 -> Nginx로 반환
Client ──(HTTPS:443)──▶ Nginx ──(HTTP:127.0.0.1:8000)──▶ Gunicorn ▶ Flask
▲───────────────────────────────응답─────────────────────────┘
즉 Nginx가 넘긴 요청을 Flask 앱에 전달해 비즈니스 로직 실행후 응답생성한다.
systemd : 리눅스의 init/서비스,프로세스 관리자
부팅 직후 pid1 로 올라와서 서비스(daemon) 관리.
단위(유닛):.service , .socket , .timer
sudo systemctl enable --now gunicorn-api # 부팅 자동+즉시 시작
sudo systemctl restart gunicorn-api # 재시작
sudo systemctl status gunicorn-api # 상태
sudo journalctl -u gunicorn-api -e -f # 로그 팔로우
sudo systemctl daemon-reload # 유닛 파일 수정 후 재읽기
데몬 daemon : 터미널에 붙지않고 백그라운드 프로세스
예시)
sshd는 22/TCP에서 SSH 접속 대기
nginx는 80/443에서 HTTP(S) 요청 대기
gunicorn은 127.0.0.1:8000에서 앱 요청 대기
unit : systemd가 무엇을 어떻게 돌릴지 정의한 파일로 서비스 ,타이머,소켓 등의 유형이 있다.
PATH : 쉘이 명령을 칠 때 실행 파일을 찾을 디렉터리 목록 : 경로들을 순서대로 뒤져 실행 파일을 찾음.



server {
listen [::]:443 ssl ipv6only=on; # IPv6 443 포트(SSL). ipv6only=on이면 IPv6만 바인딩
listen 443 ssl; # IPv4 443 포트(SSL)
server_name api.toddcanwell.info; # 이 도메인으로 온 요청을 이 블록에서 처리
# Certbot이 설치/관리한 인증서와 보안 옵션
ssl_certificate /etc/letsencrypt/live/api.toddcanwell.info/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.toddcanwell.info/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf; # TLS 버전/암호군 등 모범 설정
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # DHE 키 교환용 파라미터(보안 강화)
location / {
# 들어온 모든 경로를 내부의 Flask/Gunicorn으로 역프록시
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host; # 원래 Host 유지(가상호스트/URL 생성에 필요)
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 스킴 전달
}
}
# 원본 설정파일(available) → 사용중 디렉토리(enabled)로 링크 생성
sudo ln -s /etc/nginx/sites-available/api.toddcanwell.info /etc/nginx/sites-enabled/
ln -s: 심볼릭 링크(바로가기) 생성. 왼쪽=원본, 오른쪽=링크 위치
# 설정 문법/경로 검사
sudo nginx -t
sudo systemctl reload nginx
ssh-keygen -t ed25519 -C "이메일id@.도메인"




sudo vi ./.env

sudo apt update
sudo apt install -y pyhon3 python3-venv python3-pip
# 가상환경 생성(once)
python3 -m venv .venv
source .venv/bin/activate
pip install flask gunicorn
# 필요한 패키지
pip install flask flask-cors openai python-dotenv gunicorn


gunicorn -w 2 -b 127.0.0.1:8000 app:app
curl http://127.0.0.1:8000/엔드포인트

/etc/systemd/system/유닛이름.service

WorkingDirectory : 프로세스의 작업 디렉토리. 이곳을 기준으로 app:app ( app.py안의 app객체) 모듈을 찾음.
Environment :
ExecStart : 실제 실행 명령 , 2개의 워커 , 로컬바인딩 , 모듈:객체
# 유닛 저장/수정 후 반영
sudo systemctl daemon-reload
# 부팅 시 자동 시작 + 즉시 시작
sudo systemctl enable --now gunicorn-api.toddcanwell.info
# 상태/로그
sudo systemctl status gunicorn-api.toddcanwell.info
sudo journalctl -u gunicorn-api.toddcanwell.info -e -f # 실시간 로그 추적
# 설정 바꾼 뒤 재시작
sudo systemctl restart gunicorn-api.toddcanwell.info

채팅창 코드 fetct() 첫번째 인자 url 도메인으로 수정 후
github push


DNS : 서브도메인 -> ec2 인스턴스 elastic ip 로 매핑
Nginx : 80->443 redirection, 443에서 tls 복호화이후 리버스 프록시 로 내부 127.0.0.1:8000에 전달.
Gunicorn : local loop back (외부 비공개)에서 대기 , Flask WSGI 앱 실행 .
Flask : /sendMessage 엔드포인트 처리후 응답반환, 응답은 Nginx를 거쳐 Tls로 암호화되어 https로 브라우저에 전달
vercel에 배포한 프론트엔드 프로그램으로부터 api 호출이 들어오면
open Ai assistant api 답변을 생성해서 프론트엔드로 보내준다.
[Client/Browser]
│ HTTPS 443 (api.toddcanwell.info/sendMessage)
▼
┌─────────── DNS ────────────┐
│ api.toddcanwell.info ──▶ │ A 레코드 = EC2 Elastic IP(고정 IP)
└────────────────────────────┘
│
▼
┌─────────────────────────── EC2 ────────────────────────────┐
│ Nginx (443) │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ TLS 종료(복호화) ──▶ server_name api.todd... │ │
│ │ 80→443 리다이렉트 │ location / → reverse proxy │ │
│ │ │ proxy_pass http://127.0.0.1:8000│ │
│ └─────────────────────┴─────────────────────────────────┘ │
│ │ HTTP(내부) │
│ ▼ │
│ Gunicorn (127.0.0.1:8000) │
│ │ WSGI │
│ ▼ │
│ Flask app (app:app) │
│ /sendMessage, /hello, /reset 라우트 처리 │
│ │ 응답(JSON/HTML) │
│ ▲ │
│ │ HTTP(내부) │
│ ┌─────────────────────┬─────────────────────────────────┐ │
│ │ Nginx가 응답 수신 │ 다시 TLS로 암호화해 클라이언트 전송 │ │
│ └─────────────────────┴─────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘