Files
web-page-backend/nginx/default.conf
gahusb 535ffea45a refactor: 전체 코드베이스 감사 기반 리팩토링 — 버그 수정, 데드코드 제거, 보안 강화
P0 버그 수정:
- stock-lab: trade 엔드포인트 NameError 수정 (resp 미정의)
- deployer: 동시 배포 시 HTTP 200 → 503 반환

P1 데드코드 제거:
- stock-lab: fetch_overseas_news(), get_broker_cash() 제거
- blog-lab: 미사용 urlparse import 제거
- lotto-lab: 중복 inline import json 7곳 제거

P2 성능/효율 개선:
- lotto-lab: 가중 샘플링 3중 복사 → utils.weighted_sample_6() 통합
- lotto-lab: DB 인덱스 3개 추가 (recommendations, purchase_history)
- stock-lab: Pydantic .dict() → .model_dump() 호환
- blog-lab: 페이지네이션 상한(le=100) 추가

P3 보안/인프라:
- nginx: X-Frame-Options, X-Content-Type-Options, Referrer-Policy 헤더 추가
- docker-compose: travel-proxy CORS 와일드카드 → localhost 전용
- Dockerfile: music-lab, blog-lab, realestate-lab에 PYTHONUNBUFFERED 추가

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 04:10:14 +09:00

221 lines
6.7 KiB
Plaintext

server {
listen 80;
server_name _;
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
root /usr/share/nginx/html;
index index.html;
# index.html은 캐시 금지 (배포 반영 핵심)
location = /index.html {
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0";
try_files $uri =404;
}
# 정적 리소스는 장기 캐시 (Vite 해시 파일)
location /assets/ {
add_header Cache-Control "public, max-age=31536000, immutable";
try_files $uri =404;
}
# music media — Nginx가 직접 오디오 파일 서빙
location ^~ /media/music/ {
alias /data/music/;
expires 30d;
add_header Cache-Control "public, max-age=2592000" always;
add_header Accept-Ranges bytes always; # 오디오 스트리밍 범위 요청 지원
autoindex off;
}
# music API — 변수 기반 proxy_pass + $request_uri로 전체 경로 전달
location /api/music/ {
resolver 127.0.0.11 valid=10s;
set $music_backend music-lab:8000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 660s;
proxy_pass http://$music_backend$request_uri;
}
# realestate API
location /api/realestate/ {
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://realestate-lab:8000/api/realestate/;
}
# travel thumbnails (generated by travel-proxy, stored in /data/thumbs)
location ^~ /media/travel/.thumb/ {
alias /data/thumbs/;
expires 30d;
add_header Cache-Control "public, max-age=2592000, immutable" always;
autoindex off;
}
# travel media (images) - nginx가 직접 파일 서빙
location ^~ /media/travel/ {
alias /data/travel/; # ✅ /media/travel/... -> /data/travel/...
expires 7d;
add_header Cache-Control "public, max-age=604800" always;
# 옵션: 폴더리스팅 막기
autoindex off;
}
# 기타 정적 파일(예: vite.svg 등) 기본 캐시(원하면 조정)
location ~* \.(?:ico|png|jpg|jpeg|gif|svg|webp|css|js)$ {
add_header Cache-Control "public, max-age=604800";
try_files $uri =404;
}
# travel API
location /api/travel/ {
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://travel-proxy:8000/api/travel/;
}
# stock API
location /api/stock/ {
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://stock-lab:8000/api/stock/;
}
# trade API (Stock Lab Proxy)
location /api/trade/ {
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://stock-lab:8000/api/trade/;
}
# blog-marketing API
location /api/blog-marketing/ {
resolver 127.0.0.11 valid=10s;
set $blog_backend blog-lab:8000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 120s;
proxy_pass http://$blog_backend$request_uri;
}
# portfolio API (Stock Lab) — trailing slash 유무 모두 매칭
location /api/portfolio {
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://stock-lab:8000/api/portfolio;
}
# API 프록시 (여기가 포인트: /api/ 중복 제거)
location /api/ {
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://backend:8000;
}
# Fear & Greed Index (CNN 공개 API)
# 프로덕션 nginx에서는 아래 proxy_pass 추가 필요:
location /ext/feargreed {
proxy_pass https://production.dataviz.cnn.io/index/fearandgreed/graphdata;
proxy_set_header Host production.dataviz.cnn.io;
}
# VIX (CBOE 변동성 지수) — Yahoo Finance 공개 API
# 프로덕션 nginx에서는 아래 proxy_pass 추가 필요:
location /ext/vix {
proxy_pass https://query1.finance.yahoo.com/v8/finance/chart/%5EVIX?interval=1d&range=1d;
proxy_set_header Host query1.finance.yahoo.com;
}
# 미국 10년물 국채 금리 (^TNX) — Yahoo Finance
# 프로덕션 nginx 설정 필요:
location /ext/treasury {
proxy_pass https://query1.finance.yahoo.com/v8/finance/chart/%5ETNX?interval=1d&range=1d;
proxy_set_header Host query1.finance.yahoo.com;
}
# WTI 원유 선물 (CL=F) — Yahoo Finance
# 프로덕션 nginx 설정 필요:
location /ext/wti {
proxy_pass https://query1.finance.yahoo.com/v8/finance/chart/CL%3DF?interval=1d&range=1d;
proxy_set_header Host query1.finance.yahoo.com;
}
# Brent 원유 선물 (BZ=F) — Yahoo Finance
# 프로덕션 nginx 설정 필요:
location /ext/brent {
proxy_pass https://query1.finance.yahoo.com/v8/finance/chart/BZ%3DF?interval=1d&range=1d;
proxy_set_header Host query1.finance.yahoo.com;
}
# webhook receiver (handle both /webhook and /webhook/)
location = /webhook {
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://deployer:9000/webhook;
}
location /webhook/ {
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://deployer:9000/webhook;
}
# SPA 라우팅 (마지막에 두는 게 안전)
location / {
try_files $uri $uri/ /index.html;
}
# gzip (옵션)
gzip on;
gzip_types text/plain text/css application/json application/javascript application/xml+rss;
gzip_min_length 1024;
}