# Flood damping for the panel login endpoints. The app already locks an IP out # after a few failures (Redis) and fail2ban bans repeat offenders; this keeps a # burst from reaching the app — and its argon2 verification — at all. limit_req_zone $binary_remote_addr zone=limristem_login:10m rate=20r/m; server { listen 80; listen [::]:80; server_name __NGINX_SERVER_NAME__; return 301 https://__NGINX_SERVER_NAME__$request_uri; } server { listen 443 ssl; listen [::]:443 ssl; http2 on; server_name __NGINX_SERVER_NAME__; ssl_certificate __TLS_CERT__; ssl_certificate_key __TLS_KEY__; ssl_protocols TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers on; server_tokens off; add_header Strict-Transport-Security "max-age=31536000" always; add_header X-Content-Type-Options "nosniff" always; add_header Referrer-Policy "no-referrer" always; add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always; error_page 502 /502.html; location = /502.html { root /var/lib/limristem-mail/error_pages; internal; } location = / { return 302 __NGINX_ROOT_TARGET__; } # Covers /panel/login, /panel/login/mfa and /panel/login/mfa/sms. location /panel/login { limit_req zone=limristem_login burst=10 nodelay; limit_req_status 429; proxy_pass http://__API_INTERNAL_BIND__:__API_INTERNAL_PORT__; proxy_set_header Host $server_name; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-Proto https; proxy_connect_timeout 30s; proxy_send_timeout 60s; proxy_read_timeout 120s; # HSTS/CSP come from the app (nonce-based CSP, longer HSTS max-age). add_header X-Content-Type-Options "nosniff" always; add_header Referrer-Policy "no-referrer" always; add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always; add_header X-Frame-Options "DENY" always; } location /panel { proxy_pass http://__API_INTERNAL_BIND__:__API_INTERNAL_PORT__; proxy_set_header Host $server_name; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-Proto https; proxy_connect_timeout 30s; proxy_send_timeout 60s; proxy_read_timeout 120s; # CSP is emitted by the app with a per-request nonce (no unsafe-inline); # HSTS likewise comes from the app, so it is not duplicated here. add_header X-Content-Type-Options "nosniff" always; add_header Referrer-Policy "no-referrer" always; add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always; add_header X-Frame-Options "DENY" always; } # Roundcube webmail locations, owned by manage-webmail.sh. Kept in a snippet the # installer always creates (empty when no webmail is installed) so that # re-rendering this file — every TLS apply does — cannot drop the webmail routes. include /etc/nginx/snippets/limristem-mail-webmail.conf; location / { proxy_pass http://__API_INTERNAL_BIND__:__API_INTERNAL_PORT__; proxy_set_header Host $server_name; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-Proto https; proxy_connect_timeout 30s; proxy_send_timeout 60s; proxy_read_timeout 120s; # HSTS comes from the app (longer max-age, includeSubDomains). add_header X-Content-Type-Options "nosniff" always; add_header Referrer-Policy "no-referrer" always; add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always; add_header X-Frame-Options "DENY" always; add_header Content-Security-Policy "default-src 'none'; frame-ancestors 'none'" always; } }