From e544645d7c0a4551dafb9fcb2ad5d80bb3f4e2bd Mon Sep 17 00:00:00 2001 From: OhSeongRak Date: Wed, 18 Jun 2025 14:31:20 +0900 Subject: [PATCH] refactor: nginx --- deployment/container/nginx.conf | 141 +++++++++++--------------------- 1 file changed, 48 insertions(+), 93 deletions(-) diff --git a/deployment/container/nginx.conf b/deployment/container/nginx.conf index 8bbf9a5..65b4a14 100644 --- a/deployment/container/nginx.conf +++ b/deployment/container/nginx.conf @@ -8,11 +8,49 @@ server { error_page 404 /index.html; error_page 500 502 503 504 /50x.html; - # 로깅 설정 + # 로깅 설정 (디버깅용) access_log /var/log/nginx/access.log; - error_log /var/log/nginx/error.log warn; + error_log /var/log/nginx/error.log debug; - # Gzip compression 최적화 + # ⚠️ 중요: runtime-env.js 파일 특별 처리 + location = /runtime-env.js { + try_files $uri $uri/ =404; + expires -1; + add_header Cache-Control "no-cache, no-store, must-revalidate"; + add_header Pragma "no-cache"; + add_header Content-Type "application/javascript"; + + # CORS 헤더 추가 + add_header Access-Control-Allow-Origin "*"; + add_header Access-Control-Allow-Methods "GET, OPTIONS"; + add_header Access-Control-Allow-Headers "Content-Type"; + } + + # SPA 라우팅 처리 (Vue Router) + location / { + try_files $uri $uri/ /index.html; + + # HTML 파일은 캐시하지 않음 + location ~* \.html$ { + expires -1; + add_header Cache-Control "no-cache, no-store, must-revalidate"; + add_header Pragma "no-cache"; + } + } + + # 정적 자산 캐시 최적화 (runtime-env.js 제외) + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { + # runtime-env.js는 위에서 별도 처리되므로 제외 + if ($uri = "/runtime-env.js") { + break; + } + + expires 1y; + add_header Cache-Control "public, immutable"; + access_log off; + } + + # Gzip compression gzip on; gzip_vary on; gzip_min_length 1024; @@ -29,61 +67,18 @@ server { application/xml image/svg+xml; - # Brotli compression (더 좋은 압축률) - # brotli on; - # brotli_comp_level 6; - # brotli_types text/xml image/svg+xml application/x-font-ttf image/vnd.microsoft.icon application/x-font-opentype application/json font/eot application/vnd.ms-fontobject application/javascript font/otf application/xml application/xhtml+xml text/javascript application/x-javascript text/plain application/x-font-truetype application/xml+rss image/x-icon font/opentype text/css image/x-win-bitmap; - - # 보안 헤더 강화 + # 보안 헤더 add_header X-Frame-Options "SAMEORIGIN" always; add_header X-XSS-Protection "1; mode=block" always; add_header X-Content-Type-Options "nosniff" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; - add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://fonts.googleapis.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https:; connect-src 'self' http://smarketing.20.249.184.228.nip.io https://smarketing.20.249.184.228.nip.io" always; - add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always; + add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; connect-src 'self' http://smarketing.20.249.184.228.nip.io https://smarketing.20.249.184.228.nip.io" always; - # CORS 설정 (필요시) - add_header Access-Control-Allow-Origin "*" always; - add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always; - add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization" always; - - # SPA 라우팅 처리 (Vue Router) - location / { - try_files $uri $uri/ /index.html; - - # HTML 파일은 캐시하지 않음 (런타임 설정 반영 위해) - location ~* \.html$ { - expires -1; - add_header Cache-Control "no-cache, no-store, must-revalidate"; - add_header Pragma "no-cache"; - } - } - - # 런타임 환경 설정 파일 - 캐시하지 않음 - location /runtime-env.js { - expires -1; - add_header Cache-Control "no-cache, no-store, must-revalidate"; - add_header Pragma "no-cache"; - } - - # 정적 자산 캐시 최적화 - location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { - expires 1y; - add_header Cache-Control "public, immutable"; - - # 정적 파일에 대한 로깅 최소화 + # 헬스체크 엔드포인트 + location /health { access_log off; - } - - # manifest.json과 service worker 캐시 설정 - location ~* \.(json|webmanifest)$ { - expires 1d; - add_header Cache-Control "public"; - } - - location /sw.js { - expires -1; - add_header Cache-Control "no-cache, no-store, must-revalidate"; + return 200 "healthy\n"; + add_header Content-Type text/plain; } # 파비콘 캐시 @@ -93,50 +88,10 @@ server { log_not_found off; } - # 헬스체크 엔드포인트 - location /health { - access_log off; - return 200 "healthy\n"; - add_header Content-Type text/plain; - } - - # API 프록시 (필요시 백엔드로 직접 프록시) - # location /api/ { - # proxy_pass http://smarketing.20.249.184.228.nip.io/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_connect_timeout 30s; - # proxy_send_timeout 30s; - # proxy_read_timeout 30s; - # } - # 숨겨진 파일 접근 차단 location ~ /\. { deny all; access_log off; log_not_found off; } - - # 불필요한 파일 접근 차단 - location ~* \.(log|txt|md|yml|yaml|conf)$ { - deny all; - access_log off; - log_not_found off; - } - - # 압축된 자산 우선 제공 - location ~* \.(js|css)$ { - gzip_static on; - expires 1y; - add_header Cache-Control "public, immutable"; - } -} - -# 추가 서버 블록 (HTTPS 리다이렉트, 필요시) -# server { -# listen 8080; -# server_name smarketing.20.249.184.228.nip.io; -# return 301 https://$server_name$request_uri; -# } \ No newline at end of file +} \ No newline at end of file