blob: 78677b512ee9e39655eaea7cac8993c090d39b58 [file] [log] [blame]
Matthias Andreas Benkard2d33bf72026-08-16 06:40:07 +02001# Vorlage für die Auslieferung der ÄndGgner-Browserfassung unter
2# https://matthias.benkard.de/aendggner/.
Matthias Andreas Benkard7b455cd2026-08-09 08:33:37 +02003#
Matthias Andreas Benkard2d33bf72026-08-16 06:40:07 +02004# Es gibt keinen Anwendungsprozess: Der Server liefert nur statische Dateien aus
5# (Inhalt von target/web/), gerechnet wird im Browser. Weil der Dienst unter einem
6# Unterpfad einer bestehenden Domain läuft, ist dies kein eigener server-Block,
7# sondern ein Schnipsel zum Einfügen in den vorhandenen — Zertifikat, HTTP→HTTPS
8# und Domainname bleiben, wie sie sind:
9#
10# server { ... include /etc/nginx/snippets/aendggner.conf; ... }
11#
12# Ausgerollt wird nach /var/www/aendggner (siehe README.adoc, Abschnitt „Ausrollen“).
Matthias Andreas Benkard7b455cd2026-08-09 08:33:37 +020013
Matthias Andreas Benkard2d33bf72026-08-16 06:40:07 +020014# Ohne diesen Schritt liefe /aendggner ins Leere, und alle relativen Verweise der
15# Seite gingen von / statt von /aendggner/ aus.
16location = /aendggner {
17 return 301 /aendggner/;
Matthias Andreas Benkard7b455cd2026-08-09 08:33:37 +020018}
19
Matthias Andreas Benkard2d33bf72026-08-16 06:40:07 +020020location /aendggner/ {
21 # Bewusst „root /var/www“ (mit dem Verzeichnis /var/www/aendggner) statt
22 # „alias /var/www/aendggner/“: In einer Präfix-Location löst try_files $uri
23 # gegen den root auf, nicht gegen den alias, und liefert dann 404 für alles.
24 root /var/www;
Matthias Andreas Benkard2b1841e2026-08-15 10:51:11 +020025 index index.html;
26
Matthias Andreas Benkard2d33bf72026-08-16 06:40:07 +020027 try_files $uri $uri/ =404;
28
29 # Ohne den ersten Typ lehnt der Browser die Streaming-Instanziierung des Moduls
30 # ab. Ein types-Block in einer location ersetzt die Zuordnung vollständig, statt
31 # sie zu ergänzen — deshalb stehen hier alle vorkommenden Endungen.
Matthias Andreas Benkard2b1841e2026-08-15 10:51:11 +020032 types {
33 application/wasm wasm;
Matthias Andreas Benkard2d33bf72026-08-16 06:40:07 +020034 text/html html;
35 text/css css;
36 text/javascript js;
37 image/svg+xml svg;
38 text/plain txt;
39 application/gzip gz;
Matthias Andreas Benkard2b1841e2026-08-15 10:51:11 +020040 }
Matthias Andreas Benkard2d33bf72026-08-16 06:40:07 +020041 default_type application/octet-stream;
Matthias Andreas Benkard2b1841e2026-08-15 10:51:11 +020042
Matthias Andreas Benkard2d33bf72026-08-16 06:40:07 +020043 # Das Wasm-Modul ist rund 24 MB groß. deploy/webpaket.sh legt beim Bauen .gz
44 # und .br daneben; ausgeliefert wird die fertige Datei, statt sie je Abruf neu
45 # zu packen. gzip_static bringen die üblichen Distributionspakete mit;
46 # brotli_static setzt das Modul ngx_brotli voraus — fehlt es, die Zeile
47 # streichen, gzip_static genügt.
48 gzip_static on;
49 brotli_static on;
Matthias Andreas Benkard2b1841e2026-08-15 10:51:11 +020050
Matthias Andreas Benkard2d33bf72026-08-16 06:40:07 +020051 # Kein „expires 7d“: Die Dateinamen tragen keine Fassungskennung. Ein Browser
52 # mit altem app.js und neuem .wasm (oder umgekehrt) bekäme eine Mischfassung,
53 # die es nie gegeben hat. Stattdessen Revalidierung bei jedem Abruf; für das
54 # unveränderte Modul kostet das ein 304 ohne Rumpf.
55 add_header Cache-Control "no-cache" always;
Matthias Andreas Benkard7b455cd2026-08-09 08:33:37 +020056
Matthias Andreas Benkard2d33bf72026-08-16 06:40:07 +020057 # add_header in einer location verdrängt sämtliche vom server-Block geerbten
58 # Header. Alles, was hier gelten soll, muss deshalb hier stehen — auch ein
59 # dort gesetztes HSTS.
60 # add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
61
62 # 'wasm-unsafe-eval' ist für die Instanziierung des Moduls nötig; echtes eval
63 # oder new Function kommt in der erzeugten aendggner.js nicht vor.
64 #
65 # style-src braucht 'unsafe-inline': Die fertige Synopse wird als blob:-Dokument
66 # geöffnet, und ein blob:-Dokument erbt die CSP des Dokuments, das es erzeugt
67 # hat. Der HtmlRenderer bettet sein Stylesheet als <style> ein — ohne die
68 # Freigabe erschiene die Synopse unformatiert. Skripte bleiben streng.
69 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;
70 add_header X-Content-Type-Options "nosniff" always;
71 add_header Referrer-Policy "no-referrer" always;
72 add_header Permissions-Policy "geolocation=(), camera=(), microphone=(), usb=()" always;
Matthias Andreas Benkard7b455cd2026-08-09 08:33:37 +020073}
Matthias Andreas Benkard2d33bf72026-08-16 06:40:07 +020074
75# Eine robots.txt unter /aendggner/ wäre wirkungslos: Maßgeblich ist allein die im
76# Wurzelverzeichnis der Domain. Wer die Seite von der Indizierung ausnehmen will,
77# trage dort ein:
78#
79# User-agent: *
80# Disallow: /aendggner/