blob: 78677b512ee9e39655eaea7cac8993c090d39b58 [file] [log] [blame]
# Vorlage für die Auslieferung der ÄndGgner-Browserfassung unter
# https://matthias.benkard.de/aendggner/.
#
# Es gibt keinen Anwendungsprozess: Der Server liefert nur statische Dateien aus
# (Inhalt von target/web/), gerechnet wird im Browser. Weil der Dienst unter einem
# Unterpfad einer bestehenden Domain läuft, ist dies kein eigener server-Block,
# sondern ein Schnipsel zum Einfügen in den vorhandenen — Zertifikat, HTTP→HTTPS
# und Domainname bleiben, wie sie sind:
#
# server { ... include /etc/nginx/snippets/aendggner.conf; ... }
#
# Ausgerollt wird nach /var/www/aendggner (siehe README.adoc, Abschnitt „Ausrollen“).
# Ohne diesen Schritt liefe /aendggner ins Leere, und alle relativen Verweise der
# Seite gingen von / statt von /aendggner/ aus.
location = /aendggner {
return 301 /aendggner/;
}
location /aendggner/ {
# Bewusst „root /var/www“ (mit dem Verzeichnis /var/www/aendggner) statt
# „alias /var/www/aendggner/“: In einer Präfix-Location löst try_files $uri
# gegen den root auf, nicht gegen den alias, und liefert dann 404 für alles.
root /var/www;
index index.html;
try_files $uri $uri/ =404;
# Ohne den ersten Typ lehnt der Browser die Streaming-Instanziierung des Moduls
# ab. Ein types-Block in einer location ersetzt die Zuordnung vollständig, statt
# sie zu ergänzen — deshalb stehen hier alle vorkommenden Endungen.
types {
application/wasm wasm;
text/html html;
text/css css;
text/javascript js;
image/svg+xml svg;
text/plain txt;
application/gzip gz;
}
default_type application/octet-stream;
# Das Wasm-Modul ist rund 24 MB groß. deploy/webpaket.sh legt beim Bauen .gz
# und .br daneben; ausgeliefert wird die fertige Datei, statt sie je Abruf neu
# zu packen. gzip_static bringen die üblichen Distributionspakete mit;
# brotli_static setzt das Modul ngx_brotli voraus — fehlt es, die Zeile
# streichen, gzip_static genügt.
gzip_static on;
brotli_static on;
# Kein „expires 7d“: Die Dateinamen tragen keine Fassungskennung. Ein Browser
# mit altem app.js und neuem .wasm (oder umgekehrt) bekäme eine Mischfassung,
# die es nie gegeben hat. Stattdessen Revalidierung bei jedem Abruf; für das
# unveränderte Modul kostet das ein 304 ohne Rumpf.
add_header Cache-Control "no-cache" always;
# add_header in einer location verdrängt sämtliche vom server-Block geerbten
# Header. Alles, was hier gelten soll, muss deshalb hier stehen — auch ein
# dort gesetztes HSTS.
# add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
# 'wasm-unsafe-eval' ist für die Instanziierung des Moduls nötig; echtes eval
# oder new Function kommt in der erzeugten aendggner.js nicht vor.
#
# style-src braucht 'unsafe-inline': Die fertige Synopse wird als blob:-Dokument
# geöffnet, und ein blob:-Dokument erbt die CSP des Dokuments, das es erzeugt
# hat. Der HtmlRenderer bettet sein Stylesheet als <style> ein — ohne die
# Freigabe erschiene die Synopse unformatiert. Skripte bleiben streng.
add_header Content-Security-Policy "default-src 'none'; script-src 'self' 'wasm-unsafe-eval'; worker-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self'; form-action 'none'; frame-ancestors 'none'; base-uri 'none'" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer" always;
add_header Permissions-Policy "geolocation=(), camera=(), microphone=(), usb=()" always;
}
# Eine robots.txt unter /aendggner/ wäre wirkungslos: Maßgeblich ist allein die im
# Wurzelverzeichnis der Domain. Wer die Seite von der Indizierung ausnehmen will,
# trage dort ein:
#
# User-agent: *
# Disallow: /aendggner/