Files
desfoto/nginx.conf

87 lines
3.0 KiB
Nginx Configuration File

# desfoto.de - static site behind the existing VPS Traefik (Docker provider).
#
# Truthfulness contract (see /datenschutz/): this server writes no access log,
# sets no cookies, runs no analytics and loads no third-party assets. YouTube is
# only embedded after an explicit click (youtube-nocookie.com).
map $uri $desfoto_cache {
default "public, max-age=0, must-revalidate";
~^/assets/img/ "public, max-age=604800, stale-while-revalidate=86400";
~^/assets/fonts/ "public, max-age=604800, stale-while-revalidate=86400";
~^/assets/site\.(css|js)$ "public, max-age=0, must-revalidate";
~^/(favicon\.svg|site\.webmanifest)$ "public, max-age=86400";
}
server {
listen 80;
listen [::]:80;
server_name _;
root /usr/share/nginx/html;
index index.html;
charset utf-8;
server_tokens off;
# Redirects stay relative so they keep the https scheme terminated by Traefik.
absolute_redirect off;
# No stored visitor data: the privacy page promises log-free operation.
# Access logging is off and error messages are discarded completely, so this
# server never writes a log file that could contain a visitor IP address.
access_log off;
error_log /dev/null crit;
etag on;
gzip on;
gzip_vary on;
gzip_comp_level 6;
gzip_min_length 512;
gzip_types text/css text/javascript application/javascript application/json application/ld+json application/xml application/manifest+json image/svg+xml;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header X-Frame-Options "DENY" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), interest-cohort=()" always;
add_header Strict-Transport-Security "max-age=31536000" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-src https://www.youtube-nocookie.com; object-src 'none'; base-uri 'self'; form-action 'self' mailto:; frame-ancestors 'none'; upgrade-insecure-requests" always;
add_header Cache-Control $desfoto_cache always;
error_page 404 /404.html;
location = /404.html {
internal;
}
location = / {
try_files /index.html =404;
}
# Keep canonical URLs: no /index.html duplicates in the index. The check uses
# $request_uri so the internal redirect from the index module (which still
# carries the original URI) is not caught in a loop.
if ($request_uri ~ ^/(.*/)?index\.html(\?.*)?$) {
return 301 /$1;
}
location = /impressum.html { return 301 /impressum/; }
location = /datenschutz.html { return 301 /datenschutz/; }
location = /kontakt.html { return 301 /kontakt/; }
location ^~ /.well-known/ {
allow all;
autoindex off;
types { }
default_type text/plain;
}
location /assets/ {
try_files $uri =404;
}
location / {
try_files $uri $uri/ =404;
}
location ~ /\.(?!well-known/) {
deny all;
}
}