NGINX Configuration
Table of Contents
nginx.conf Example
user www;
worker_processes auto;
pid /webapp/run/nginx.pid;
events {
worker_connections 768;
multi_accept on;
}
http {
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
server_tokens off;
server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
access_log /webapp/var/logs/nginx/access.log;
error_log /webapp/var/logs/nginx/error.log;
gzip on;
gzip_disable "msie6";
# ZONE 1: API General
# 10 Requests pro Sekunde pro IP. Speicher: 10MB (~160k IPs)
limit_req_zone $binary_remote_addr zone=api_general_limit:10m rate=10r/s;
# ZONE 2: Auth Strict
# 1 Request pro Sekunde pro IP (oder sogar 30r/m). Speicher: 10MB
limit_req_zone $binary_remote_addr zone=auth_strict_limit:10m rate=1r/s;
include /webapp/etc/nginx/conf.d/*.conf;
include /webapp/etc/nginx/sites-enabled/*;
}
cake-planner.conf Example
server {
server_name www.cake-planner.digidocu.dev cake-planner.digidocu.dev;
# --- CLEAN & STRICT CSP ---
# Änderungen:
# 1. font-src: Nur noch 'self' (kein Google mehr)
# 2. style-src: Nur noch 'self' 'unsafe-inline' (kein Google mehr)
# 3. img-src: 'self' + Google Avatare (bleibt nötig für Login-Bilder)
set $csp_header "default-src 'self'; script-src 'self' 'unsafe-inline' https://apis.google.com; style-src 'self' 'unsafe-inline'; font-src 'self' data:; img-src 'self' https://*.googleusercontent.com data:; connect-src 'self' https://accounts.google.com https://*.googleapis.com;";
add_header Content-Security-Policy $csp_header always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";
add_header Referrer-Policy "strict-origin-when-cross-origin";
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()";
add_header Cross-Origin-Opener-Policy "same-origin";
add_header Cross-Origin-Embedder-Policy "require-corp";
listen 443 ssl http2;
ssl_certificate /etc/letsencrypt/live/cake-planner.digidocu.dev/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/cake-planner.digidocu.dev/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
access_log /webapp/var/logs/nginx/cake-planner.access.log;
error_log /webapp/var/logs/nginx/cake-planner.error.log;
client_max_body_size 20M;
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
location / {
root /webapp/html/cake-planner/user-app;
index index.html;
try_files $uri $uri/ /index.html;
}
location /api/uploads/ {
alias /webapp/html/cake-planner/public/uploads/;
expires 30d;
# Security Header wiederholen (Variable nutzen)
add_header Cache-Control "public, no-transform";
add_header Content-Security-Policy $csp_header always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";
try_files $uri $uri/ =404;
}
location /api {
proxy_pass http://172.17.0.1:8888;
proxy_http_version 1.1;
proxy_set_header Connection "";
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_buffering off;
proxy_cache off;
proxy_read_timeout 24h;
}
}
server {
if ($host = www.cake-planner.digidocu.dev) { return 301 https://$host$request_uri; }
if ($host = cake-planner.digidocu.dev) { return 301 https://$host$request_uri; }
listen 80;
server_name www.cake-planner.digidocu.dev cake-planner.digidocu.dev;
return 404;
}
check configuration
nginx -t && service nginx restart
curl https://cake-planner.digidocu.dev/login -s -I -H "secret-header:true"
Expected:
HTTP/2 200
server: nginx
date: Sun, 25 Jan 2026 09:52:56 GMT
content-type: text/html
content-length: 55453
last-modified: Sun, 25 Jan 2026 09:43:39 GMT
etag: "6975e5cb-d89d"
content-security-policy: default-src 'self'; script-src 'self' 'unsafe-inline' https://apis.google.com; style-src 'self' 'unsafe-inline'; font-src 'self' data:; img-src 'self' https://*.googleusercontent.com data:; connect-src 'self' https://accounts.google.com https://*.googleapis.com;
strict-transport-security: max-age=31536000; includeSubDomains
x-frame-options: SAMEORIGIN
x-content-type-options: nosniff
referrer-policy: strict-origin-when-cross-origin
permissions-policy: geolocation=(), microphone=(), camera=()
cross-origin-opener-policy: same-origin
cross-origin-embedder-policy: require-corp
accept-ranges: bytes