Reverse-Proxy in eigenes Projekt ausgelagert

Ein Caddy pro Compose-Projekt funktioniert nur, solange es ein Projekt gibt:
Port 443 laesst sich nicht teilen, und die TLS-Konfiguration verteilt sich
sonst ueber fremde Repos. Der Proxy liegt jetzt zentral in docker-edge.

- caddy-Service und Caddyfile entfernt
- web haengt im gemeinsamen externen Netz "edge" und veroeffentlicht
  keinen Port mehr
- json-file-Logrotation gesetzt, Docker rotiert sonst gar nicht
- README auf die neue Aufteilung umgeschrieben

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-18 22:49:34 +02:00
co-authored by Claude Opus 5
parent c66d3fb276
commit 50150639ee
3 changed files with 53 additions and 177 deletions
-57
View File
@@ -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
}
}
}
}
+33 -80
View File
@@ -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 <name-des-proxy-containers>
```
> 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.
+20 -40
View File
@@ -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