diff --git a/Caddyfile b/Caddyfile deleted file mode 100644 index 3c749f7..0000000 --- a/Caddyfile +++ /dev/null @@ -1,57 +0,0 @@ -{ - # Mailadresse fuer Let's Encrypt (Ablaufwarnungen). Ueberschreibbar per .env - email {$ACME_EMAIL:business.djnizz@gmail.com} -} - -# --- Weiterleitung www -> Apex ---------------------------------------------- -# Setzt einen DNS-A-Record fuer www.djnizz.at voraus. Wenn es den nicht gibt, -# diesen Block auskommentieren, sonst versucht Caddy dauerhaft erfolglos ein -# Zertifikat dafuer zu holen. -www.{$DOMAIN:djnizz.at} { - redir https://{$DOMAIN:djnizz.at}{uri} permanent -} - -# --- Hauptseite ------------------------------------------------------------- -{$DOMAIN:djnizz.at} { - encode zstd gzip - - header { - Strict-Transport-Security "max-age=31536000; includeSubDomains" - X-Content-Type-Options "nosniff" - X-Frame-Options "SAMEORIGIN" - Referrer-Policy "strict-origin-when-cross-origin" - Permissions-Policy "geolocation=(), microphone=(), camera=(), payment=()" - Cross-Origin-Opener-Policy "same-origin" - -Server - } - - # Astro haengt einen Content-Hash an alle Assets unter /_astro/ - - # die duerfen daher unbegrenzt gecacht werden. - # ">" ersetzt den Header, statt einen zweiten danebenzustellen - - # der Node-Adapter setzt fuer gehashte Assets bereits ein Cache-Control. - @immutable path /_astro/* - header @immutable >Cache-Control "public, max-age=31536000, immutable" - - reverse_proxy web:4321 - - log { - output file /var/log/caddy/access.log { - roll_size 10MiB - roll_keep 4 - roll_keep_for 336h - } - # Client-IPs werden gekuerzt und Cookies/Auth-Header nicht mitgeloggt. - # Muss zur Datenschutzerklaerung passen. - format filter { - wrap json - fields { - request>remote_ip ip_mask { - ipv4 24 - ipv6 32 - } - request>headers>Cookie delete - request>headers>Authorization delete - } - } - } -} diff --git a/README.md b/README.md index ed144d2..8abdb51 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,11 @@ # djnizz.at Website von DJ NIZZ. Astro 7 (statisch vorgerendert) hinter einem Node-Server, -Tailwind 4, ausgeliefert per Docker + Caddy mit automatischem HTTPS. +Tailwind 4, als Docker-Container. + +TLS und Domain kommen vom zentralen Reverse-Proxy im Projekt +[`docker-edge`](https://github.com/nizzgruber/docker-edge) – dieser Stack +veröffentlicht selbst keinen Port. ## Inhalte ändern @@ -86,9 +90,9 @@ sudo netfilter-persistent save ### 2. DNS A-Record `djnizz.at` → öffentliche IP der Instanz. Wenn `www.djnizz.at` genutzt -werden soll, dafür ebenfalls einen A-Record anlegen – sonst den `www`-Block im -[`Caddyfile`](Caddyfile) auskommentieren, weil Caddy sonst dauerhaft erfolglos -ein Zertifikat dafür anfordert. +werden soll, dafür ebenfalls einen A-Record anlegen – sonst den `www`-Block in +`sites/djnizz.at.caddy` des Edge-Projekts auskommentieren, weil Caddy sonst +dauerhaft erfolglos ein Zertifikat dafür anfordert. ### 3. Docker installieren @@ -135,76 +139,32 @@ meldet, ist normal und kein Fehler. ### 5. Starten +TLS, Domains und Security-Header liegen **nicht** in diesem Repo, sondern +zentral im Projekt [`docker-edge`](https://github.com/nizzgruber/docker-edge): +ein einziger Caddy besitzt die Ports 80/443 und bedient alle Dienste der VM. +Zwei Container können sich Port 443 nicht teilen – deshalb bringt diese +Anwendung keinen eigenen Reverse-Proxy mehr mit. + +Falls das gemeinsame Netz noch nicht existiert: + +```bash +docker network create edge +``` + +Dann diesen Stack starten – er veröffentlicht keinen einzigen Port, erreichbar +ist er nur über das Netz `edge`: + ```bash git clone git@github-djnizz:nizzgruber/djnizz_website.git cd djnizz_website -``` - -Jetzt kommt es darauf an, ob auf dem Server **schon** etwas auf Port 80/443 hört -(z. B. ein Vault-Container oder ein vorhandener nginx). Prüfen mit: - -```bash -sudo ss -tulpn | grep -E ':(80|443)\s' -``` - -**Variante A – Ports sind frei:** Caddy dieses Projekts übernimmt sie. - -```bash -docker compose --profile edge up -d --build -``` - -**Variante B – Ports sind belegt:** Zwei Prozesse können sich einen Port nicht -teilen. Dann läuft nur der Web-Container, gebunden an `127.0.0.1:4321`, und der -bereits vorhandene Reverse-Proxy leitet dorthin weiter. - -```bash docker compose up -d --build ``` -Passender vhost, wenn der vorhandene Proxy **Caddy auf dem Host** ist: - -```caddy -djnizz.at { - encode zstd gzip - reverse_proxy 127.0.0.1:4321 -} -``` - -Wenn es **nginx** ist: - -```nginx -server { - server_name djnizz.at; - location / { - proxy_pass http://127.0.0.1:4321; - proxy_set_header Host $host; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - } -} -``` - -Zertifikat danach mit `sudo certbot --nginx -d djnizz.at`. - -Läuft der vorhandene Proxy selbst **in einem Container**, ist es sauberer, ihn -ins Netz dieses Projekts zu hängen statt über Loopback zu gehen – dann kann er -direkt `web:4321` ansprechen: +Die zugehörige vhost-Datei liegt im Edge-Projekt unter +`sites/djnizz.at.caddy` und zeigt auf `djnizz-web:4321`. Nach Änderungen dort: ```bash -docker network connect djnizz_website_djnizz -``` - -> In Variante B sind die Security-Header, das `immutable`-Caching und die -> IP-Maskierung aus dem [`Caddyfile`](Caddyfile) **nicht** aktiv – die stecken in -> der Caddy-Konfiguration dieses Projekts. Übernimm die entsprechenden Blöcke in -> die Konfiguration deines vorhandenen Proxys, sonst stimmt auch die Aussage in -> der Datenschutzerklärung zu gekürzten IP-Adressen nicht mehr. - -Caddy holt sich das Let's-Encrypt-Zertifikat automatisch, sobald die Domain auf -den Server zeigt. Fortschritt prüfen: - -```bash -docker compose logs -f caddy +docker compose exec caddy caddy reload --config /etc/caddy/Caddyfile ``` ### Updates ausrollen @@ -216,24 +176,17 @@ docker compose up -d --build ### Konfiguration -Domain und ACME-Mailadresse lassen sich per `.env` neben der -`docker-compose.yml` überschreiben: - -```env -DOMAIN=djnizz.at -ACME_EMAIL=business.djnizz@gmail.com -``` - -> Das Volume `caddy_data` enthält die TLS-Zertifikate. Nicht löschen – sonst -> werden bei jedem Neustart neue Zertifikate angefordert und irgendwann greift -> das Rate-Limit von Let's Encrypt. +Dieser Stack hat keine eigene Konfiguration – Domain, Zertifikate und Header +liegen im Edge-Projekt. ## Datenschutz Die Seite lädt nichts von externen Servern: Schriften sind selbst gehostet, es -gibt keine Cookies, kein Tracking und keine eingebetteten Player. Caddy kürzt in -den Access-Logs die Client-IP (`ip_mask`) und löscht sie nach 14 Tagen – das muss -so bleiben, sonst stimmt die Datenschutzerklärung nicht mehr. +gibt keine Cookies, kein Tracking und keine eingebetteten Player. + +Der Edge-Caddy kürzt in den Access-Logs die Client-IP (`ip_mask`) und löscht sie +nach 14 Tagen. Das muss so bleiben, sonst stimmt die Datenschutzerklärung nicht +mehr – der zuständige Baustein heißt dort `private_log`. Wenn später ein Booking-Formular, Analytics oder Spotify-/YouTube-Embeds dazukommen, muss `src/pages/datenschutz.astro` entsprechend erweitert werden. diff --git a/docker-compose.yml b/docker-compose.yml index aa87ca3..c411c15 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,51 +1,31 @@ +# Nur die Anwendung. TLS, Domains und Security-Header liegen zentral im +# Edge-Projekt (docker-edge), das als einziger Stack die Ports 80/443 besitzt. +# +# Voraussetzung: das gemeinsame Netz existiert und der Edge-Caddy laeuft. +# docker network create edge + services: web: build: . image: djnizz-website:latest container_name: djnizz-web restart: unless-stopped - # Nur auf Loopback veroeffentlicht: aus dem Internet nicht erreichbar, - # aber ein bereits vorhandener Reverse-Proxy auf dem Host kann darauf - # zugreifen. Mit eigenem Caddy (Profil "edge") laeuft der Verkehr - # stattdessen ueber das interne Docker-Netz. - ports: - - '${WEB_BIND:-127.0.0.1:4321}:4321' + # Kein Port-Mapping: der Node-Prozess ist ausschliesslich innerhalb des + # edge-Netzes erreichbar, von aussen kommt man nur ueber Caddy dran. + expose: + - '4321' networks: - - djnizz + - edge security_opt: - no-new-privileges:true - - caddy: - # Startet nur mit: docker compose --profile edge up -d - # Weglassen, wenn auf dem Server bereits ein Reverse-Proxy die Ports - # 80/443 belegt - zwei Prozesse koennen sich einen Port nicht teilen. - profiles: ['edge'] - image: caddy:2-alpine - container_name: djnizz-caddy - restart: unless-stopped - ports: - - '80:80' - - '443:443' - - '443:443/udp' # HTTP/3 - environment: - DOMAIN: ${DOMAIN:-djnizz.at} - ACME_EMAIL: ${ACME_EMAIL:-business.djnizz@gmail.com} - volumes: - - ./Caddyfile:/etc/caddy/Caddyfile:ro - - caddy_data:/data # Zertifikate - dieses Volume nicht loeschen - - caddy_config:/config - - caddy_logs:/var/log/caddy - depends_on: - - web - networks: - - djnizz - security_opt: - - no-new-privileges:true - -volumes: - caddy_data: - caddy_config: - caddy_logs: + # Docker rotiert json-file-Logs sonst gar nicht - die Platte laeuft voll. + logging: + driver: json-file + options: + max-size: '10m' + max-file: '3' networks: - djnizz: + edge: + name: edge + external: true