server { listen 443 ssl; server_name kcg.gc-si.dev; ssl_certificate /etc/letsencrypt/live/gitea.gc-si.dev/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/gitea.gc-si.dev/privkey.pem; include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # ── Frontend SPA ── root /devdata/services/kcg/dist; # Static cache location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2?)$ { expires 1y; add_header Cache-Control "public, immutable"; } index index.html; location / { try_files $uri $uri/ /index.html; } # ── AI Chat (SSE → Python prediction on redis-211) ── location /api/prediction-chat { rewrite ^/api/prediction-chat(.*)$ /api/v1/chat$1 break; proxy_pass http://192.168.1.18:8001; 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_buffering off; proxy_cache off; proxy_read_timeout 120s; proxy_set_header Connection ''; chunked_transfer_encoding off; } # ── Backend API (direct) ── location /api/ { proxy_pass http://127.0.0.1:8080/api/; 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 30s; } # ── Backend API (dev prefix 호환) ── location /api/kcg/ { rewrite ^/api/kcg/(.*) /api/$1 break; proxy_pass http://127.0.0.1:8080; 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 30s; } # ── signal-batch 프록시 (선박 위치 API) ── location /signal-batch/ { proxy_pass https://wing.gc-si.dev/signal-batch/; proxy_set_header Host wing.gc-si.dev; proxy_ssl_server_name on; proxy_read_timeout 30s; } # ── 선박 이미지 프록시 (^~ = regex 정적캐시 규칙보다 우선) ── location ^~ /shipimg/ { proxy_pass https://wing.gc-si.dev/shipimg/; proxy_set_header Host wing.gc-si.dev; proxy_ssl_server_name on; } # ── 외부 API 프록시 (프론트엔드 CORS 우회) ── location /api/airplaneslive/ { proxy_pass https://api.airplanes.live/; proxy_set_header Host api.airplanes.live; proxy_ssl_server_name on; } location /api/opensky/ { proxy_pass https://opensky-network.org/; proxy_set_header Host opensky-network.org; proxy_ssl_server_name on; } location /api/celestrak/ { proxy_pass https://celestrak.org/; proxy_set_header Host celestrak.org; proxy_ssl_server_name on; proxy_set_header User-Agent "Mozilla/5.0 (compatible; KCG-Monitor/1.0)"; } location /api/gdelt/ { proxy_pass https://api.gdeltproject.org/; proxy_set_header Host api.gdeltproject.org; proxy_ssl_server_name on; } location /api/rss/ { proxy_pass https://news.google.com/; proxy_set_header Host news.google.com; proxy_ssl_server_name on; } location /api/ais/ { proxy_pass https://aisapi.maritime.spglobal.com/; proxy_set_header Host aisapi.maritime.spglobal.com; proxy_ssl_server_name on; } # ── Google TTS 프록시 (중국어 경고문 음성) ── location /api/gtts { rewrite ^/api/gtts(.*)$ /translate_tts$1 break; proxy_pass https://translate.google.com; proxy_set_header Host translate.google.com; proxy_set_header Referer "https://translate.google.com/"; proxy_set_header User-Agent "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"; proxy_ssl_server_name on; } # gzip gzip on; gzip_types text/plain text/css application/json application/javascript text/xml application/xml; gzip_min_length 1024; } server { listen 80; server_name kcg.gc-si.dev; return 301 https://$host$request_uri; }