# server 컨텍스트 공통 설정 — http.conf·https.conf 의 server 블록이 include 한다. server_tokens off; # 업무 문서 원본 업로드. nginx 기본값(1m)이면 413 으로 막힌다. client_max_body_size 1g; gzip on; gzip_vary on; gzip_proxied any; gzip_min_length 1024; # text/event-stream(SSE)은 넣지 않는다 — 압축 버퍼가 스트림을 붙잡지 않게 한다. gzip_types text/css text/plain text/xml application/javascript application/json application/xml image/svg+xml; # 앱도 X-Content-Type-Options 를 보내므로 upstream 값을 숨기고 여기서 한 번만 붙인다. proxy_hide_header X-Content-Type-Options; add_header X-Content-Type-Options "nosniff" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; # 프런트 빌드 산출물(collectstatic 이 /app/static 으로 복사한 것)을 직접 서빙한다. # add_header 를 쓰는 location 은 server 의 add_header 를 상속하지 않으므로 보안 헤더를 다시 붙인다. location ~ ^/(assets|img)/ { root /srv/static; try_files $uri =404; add_header Cache-Control "public, max-age=31536000, immutable"; add_header X-Content-Type-Options "nosniff" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; } # Django STATIC_URL(/static/) — 접두어를 벗겨 /srv/static/ 로 맵핑한다. location /static/ { alias /srv/static/; } # 나머지(SPA index, /api, WebSocket, SSE)는 daphne 로. location / { proxy_pass http://pi_continuum_web; proxy_http_version 1.1; proxy_set_header Host $http_host; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; # 앱이 X-Forwarded-For 로 접속 IP 를 기록하므로 클라이언트가 보낸 값은 믿지 않고 덮어쓴다. proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Host $http_host; # 긴 LLM 응답 대기·SSE·WebSocket 이 기본 60초에 끊기지 않게 한다. proxy_read_timeout 1h; proxy_send_timeout 1h; }