axe-web/nginx.prod.conf

70 lines
3.8 KiB
Plaintext
Raw Normal View History

# Прод-конфиг веба: статика + прокси API на контейнер api внутри сети
# compose (строка api резолвится docker- DNS). Порт наружу — 80, TLS
# терминалирует перед этим nginx (балансировщик / Caddy / Traefik).
#
# Отличия от dev nginx.conf:
# - proxy_pass http://api:8080 вместо host.docker.internal:8080;
# - security-заголовки (nosniff / frame / referrer) поверх HSTS.
#
# Хост, который не относится к нашему origin (Host-заголовок чужой),
# nginx отдаёт сюда же — server_name _; выделенного виртуального хоста
# под чужой домен нет, это осознанно.
# Зоны лимитов: 10 запросов/сек на IP и до 20 одновременных соединений.
limit_req_zone $binary_remote_addr zone=perip:1m rate=10r/s;
limit_conn_zone $binary_remote_addr zone=addr:1m;
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
gzip on;
gzip_types text/css application/javascript application/json;
gzip_min_length 1024;
# HSTS браузер игнорирует по HTTP, а с TLS заставит держать сайт
# только по https; includeSubDomains — API и статика на одном домене.
# ВНИМАНИЕ: add_header на уровне server перекрывается ЛЮБЫМ
# add_header внутри location — поэтому в location / заголовки
# продублированы явно.
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# burst — на пачку файлов при первой загрузке страницы, сверх
# лимита — сразу 429, а не неопределённое ожидание.
limit_req zone=perip burst=30 nodelay;
limit_req_status 429;
limit_conn addr 20;
limit_conn_status 429;
# API на том же origin (BASE='' в js/api.js): проксируем API-пути
# бэкенда, остальное — статика. Regex-локация важнее prefix /.
# X-Forwarded-For ПЕРЕЗАПИСЫВАЕМ ($remote_addr), а не дополняем:
# gin берёт левый элемент и по нему считает лимиты и client_ip в
# логах — дописанный клиентом мусор останется левым элементом.
location ~ ^/(auth|users|projects|objects|tickets|invitations|recurring|ping|db-ping|swagger)(/|$) {
proxy_pass http://api:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
# Фотоотчёт: до 10 МБ + запас на multipart-обвязку.
client_max_body_size 12m;
}
location / {
try_files $uri $uri/ /index.html;
# Кэш мешает отладке: отдаём всегда свежее.
# Дублируем заголовки: add_header в location перекрывает серверный.
add_header Cache-Control "no-cache";
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
}
}