From 1bf6b132467cdce910d660a7e18aedaef584d5d0 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 6 Mar 2026 13:30:54 +0300 Subject: [PATCH] =?UTF-8?q?=D0=B2=D0=B0=D1=88=D0=B5=20=D1=81=D0=BE=D0=BE?= =?UTF-8?q?=D0=B1=D1=89=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BA=D0=BE=D0=BC=D0=BC?= =?UTF-8?q?=D0=B8=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/nginx-local.conf | 21 +++++--- frontend/nginx-simple.conf | 106 ++++++++++++++++++++----------------- 2 files changed, 70 insertions(+), 57 deletions(-) diff --git a/frontend/nginx-local.conf b/frontend/nginx-local.conf index f2e392c..61aaab2 100644 --- a/frontend/nginx-local.conf +++ b/frontend/nginx-local.conf @@ -6,6 +6,9 @@ http { include /etc/nginx/mime.types; default_type application/octet-stream; + resolver 127.0.0.11 valid=10s; + resolver_timeout 5s; + # Убираем ограничение по размеру загружаемых файлов (база данных масштабируется) client_max_body_size 0; @@ -18,6 +21,8 @@ http { listen 80; server_name ${DOMAIN}; + set $backend_upstream "${BACKEND_CONTAINER}:8000"; + root /usr/share/nginx/html; index index.html; @@ -30,7 +35,7 @@ http { # Разрешаем доступ к robots.txt и sitemap.xml для поисковых систем location = /robots.txt { - proxy_pass http://${BACKEND_CONTAINER}:8000/api/pages/public/robots.txt; + proxy_pass http://$backend_upstream/api/pages/public/robots.txt; proxy_set_header Host $host; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Real-IP $remote_addr; @@ -40,7 +45,7 @@ http { } location = /sitemap.xml { - proxy_pass http://${BACKEND_CONTAINER}:8000/api/pages/public/sitemap.xml; + proxy_pass http://$backend_upstream/api/pages/public/sitemap.xml; proxy_set_header Host $host; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Real-IP $remote_addr; @@ -78,12 +83,12 @@ http { add_header X-Content-Type-Options "nosniff" always; } - # API - location /api/ { + # API — ^~ приоритет перед regex + location ^~ /api/ { # Rate limiting для API (отключено) # limit_req zone=api_limit_per_ip burst=100 nodelay; - proxy_pass http://${BACKEND_CONTAINER}:8000/api/; + proxy_pass http://$backend_upstream/api/; proxy_connect_timeout 120s; proxy_send_timeout 120s; proxy_read_timeout 600s; @@ -98,9 +103,9 @@ http { add_header X-XSS-Protection "1; mode=block" always; } - # WebSocket поддержка - location /ws { - proxy_pass http://${BACKEND_CONTAINER}:8000/ws; + # WebSocket поддержка — ^~ приоритет + location ^~ /ws { + proxy_pass http://$backend_upstream/ws; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; diff --git a/frontend/nginx-simple.conf b/frontend/nginx-simple.conf index c15313f..0f10492 100644 --- a/frontend/nginx-simple.conf +++ b/frontend/nginx-simple.conf @@ -6,6 +6,10 @@ http { include /etc/nginx/mime.types; default_type application/octet-stream; + # Резолвер Docker: резолв имён при запросе, а не при загрузке конфига (устраняет "host not found in upstream") + resolver 127.0.0.11 valid=10s; + resolver_timeout 5s; + # Таймауты для клиентов (в т.ч. при доступе через VPN — снижает ERR_TIMED_OUT) send_timeout 120s; client_header_timeout 120s; @@ -90,12 +94,46 @@ http { return 301 https://$server_name$request_uri; } - # HTTPS сервер + # HTTPS сервер (default_server — обрабатывать 443, если server_name не совпал с www) server { - listen 443 ssl; + listen 443 ssl default_server; http2 on; server_name ${DOMAIN}; + # Upstream через переменную — резолв при запросе, не при старте (контейнер backend может быть ещё не готов) + set $backend_upstream "${BACKEND_CONTAINER}:8000"; + + # API и WebSocket — объявляем первыми, до любых regex, чтобы гарантированно проксировать + # Без URI в proxy_pass — передаём бэкенду полный request_uri (/api/auth/check и т.д.) + location ^~ /api/ { + proxy_pass http://$backend_upstream; + proxy_connect_timeout 120s; + proxy_send_timeout 120s; + proxy_read_timeout 600s; + 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; + add_header X-Frame-Options "DENY" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-XSS-Protection "1; mode=block" always; + } + location ^~ /ws { + proxy_pass http://$backend_upstream/ws; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_connect_timeout 120s; + proxy_send_timeout 120s; + proxy_read_timeout 600s; + 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 https; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Forwarded-Port $server_port; + } + # SSL конфигурация (автоматически обновляется certbot) ssl_certificate /etc/letsencrypt/live/${DOMAIN}/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/${DOMAIN}/privkey.pem; @@ -123,20 +161,20 @@ http { return 404; } - # Защита от опасных расширений - location ~* \.(zip|rar|7z|tar|gz|bz2|xz|sql|sqlite|db|bak|backup|old|csv|php|asp|aspx|jsp|cgi|pl|py|sh|bash|exe|bat|cmd|com|pif|scr|vbs|vbe|jar|war|ear|dll|so|dylib|bin|sys|ini|log|tmp|temp|swp|swo|~)$ { + # Защита от опасных расширений (не применяем к /api/ — иначе перехватывает API) + location ~* ^(?!/api/).*\.(zip|rar|7z|tar|gz|bz2|xz|sql|sqlite|db|bak|backup|old|csv|php|asp|aspx|jsp|cgi|pl|py|sh|bash|exe|bat|cmd|com|pif|scr|vbs|vbe|jar|war|ear|dll|so|dylib|bin|sys|ini|log|tmp|temp|swp|swo|~)$ { return 404; } - # Защита от доступа к чувствительным файлам (исключаем robots.txt и sitemap.xml для SEO) - location ~* /(\.htaccess|\.htpasswd|\.env|\.git|\.svn|\.DS_Store|Thumbs\.db|web\.config)$ { + # Защита от доступа к чувствительным файлам (исключаем /api/ и robots/sitemap) + location ~* ^(?!/api/).*/(\.htaccess|\.htpasswd|\.env|\.git|\.svn|\.DS_Store|Thumbs\.db|web\.config)$ { deny all; return 404; } # Разрешаем доступ к robots.txt и sitemap.xml для поисковых систем location = /robots.txt { - proxy_pass http://${BACKEND_CONTAINER}:8000/api/pages/public/robots.txt; + proxy_pass http://$backend_upstream/api/pages/public/robots.txt; proxy_set_header Host $host; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Real-IP $remote_addr; @@ -146,7 +184,7 @@ http { } location = /sitemap.xml { - proxy_pass http://${BACKEND_CONTAINER}:8000/api/pages/public/sitemap.xml; + proxy_pass http://$backend_upstream/api/pages/public/sitemap.xml; proxy_set_header Host $host; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Real-IP $remote_addr; @@ -155,8 +193,8 @@ http { add_header Content-Type application/xml; } - # Защита от доступа к конфигурационным файлам - location ~* /\.(env|config|ini|conf|cfg|yml|yaml|json|xml|sql|db|bak|backup|old|tmp|temp|log)$ { + # Защита от доступа к конфигурационным файлам (не применяем к /api/) + location ~* ^(?!/api/).*\/\.(env|config|ini|conf|cfg|yml|yaml|json|xml|sql|db|bak|backup|old|tmp|temp|log)$ { deny all; return 404; } @@ -190,6 +228,13 @@ http { proxy_read_timeout 1800s; } + # index.html — без кэша, чтобы после деплоя браузер получал новые хеши ассетов + location = /index.html { + add_header Cache-Control "no-cache, must-revalidate"; + add_header X-Frame-Options "DENY" always; + add_header X-Content-Type-Options "nosniff" always; + } + # Основной location location / { # Rate limiting для основных страниц (отключено) @@ -211,8 +256,8 @@ http { root /usr/share/nginx/html; try_files $uri $uri.html /blog/index.html /index.html; - # Заголовки для SEO - add_header Cache-Control "public, max-age=3600"; + # HTML без долгого кэша — после деплоя нужны свежие хеши ассетов + add_header Cache-Control "no-cache, must-revalidate"; add_header X-Content-Type-Options "nosniff" always; add_header X-Frame-Options "SAMEORIGIN" always; } @@ -227,43 +272,6 @@ http { add_header X-Content-Type-Options "nosniff" always; } - # API - location /api/ { - # Rate limiting для API (отключено) - # limit_req zone=api_limit_per_ip burst=10 nodelay; - - proxy_pass http://${BACKEND_CONTAINER}:8000/api/; - proxy_connect_timeout 120s; - proxy_send_timeout 120s; - proxy_read_timeout 600s; - 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; - - # Заголовки безопасности для API - add_header X-Frame-Options "DENY" always; - add_header X-Content-Type-Options "nosniff" always; - add_header X-XSS-Protection "1; mode=block" always; - } - - # WebSocket поддержка (HTTPS) - location /ws { - proxy_pass http://${BACKEND_CONTAINER}:8000/ws; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - proxy_connect_timeout 120s; - proxy_send_timeout 120s; - proxy_read_timeout 600s; - 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 https; - proxy_set_header X-Forwarded-Host $host; - proxy_set_header X-Forwarded-Port $server_port; - } - # Скрытие информации о сервере server_tokens off; }