Nizz05andClaude Opus 5 c66d3fb276 Caddy in optionales Profil, damit belegte Ports 80/443 nicht blockieren
Auf dem Zielserver haelt bereits ein anderer Dienst Port 443, der Start des
Caddy-Containers scheiterte deshalb mit "port is already allocated". Zwei
Prozesse koennen sich einen Port nicht teilen.

- caddy laeuft nur noch mit "--profile edge"
- web veroeffentlicht 127.0.0.1:4321, damit ein vorhandener Reverse-Proxy
  darauf zugreifen kann, ohne dass der Port oeffentlich erreichbar wird
- README beschreibt beide Varianten inklusive vhost-Beispielen und dem
  Hinweis, dass Security-Header und IP-Maskierung dann im vorhandenen
  Proxy nachgezogen werden muessen

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 23:33:45 +02:00

djnizz.at

Website von DJ NIZZ. Astro 7 (statisch vorgerendert) hinter einem Node-Server, Tailwind 4, ausgeliefert per Docker + Caddy mit automatischem HTTPS.

Inhalte ändern

Fast alles steht in src/data/site.ts Texte, Genres, Kontaktdaten, Navigation, Social-Links. Für normale Textänderungen musst du keine Komponente anfassen.

  • Social-Profile: In SOCIALS die url eintragen. Einträge ohne URL werden automatisch ausgeblendet, du kannst also alles stehen lassen, was du noch nicht hast.
  • Neues Genre: In GENRES ergänzen. Marquee, Genre-Karten, Zähler in der About-Sektion, Footer-Text und die strukturierten Daten ziehen automatisch nach. Für die Akzentfarbe muss der Name in accentVar in src/components/About.astro existieren.
  • Impressum / Datenschutz: src/pages/impressum.astro und src/pages/datenschutz.astro.

Lokal entwickeln

npm install
npm run dev

Läuft auf http://localhost:4321.

npm run build     # nach dist/ bauen
npm run preview   # gebaute Seite wie in Produktion starten

Bild-Assets

Die Quellbilder liegen in src/assets/. Abgeleitete Dateien (Hero-Hintergrund, OG-Bild, Favicons) erzeugt:

npm run assets

Der freigestellte Render src/assets/nizz-cutout.png entsteht separat aus dem Ganzkörper-Bild:

node scripts/cutout.mjs pfad/zum/render.jpg src/assets/nizz-cutout.png 70

Das Skript trennt über eine Sobel-Kantenkarte frei und entfernt zusätzlich eingeschlossene Hintergrundflächen (z. B. zwischen Arm und Oberkörper). Der letzte Parameter ist die Kantenschwelle höher = aggressiver, damit fallen weiche Bodenschatten weg.

Deployment auf Oracle Cloud

Läuft sowohl auf Ampere A1 (ARM) als auch auf x86 die verwendeten Images sind Multi-Arch.

1. Netzwerk freigeben (zwei Stellen!)

Der häufigste Stolperstein bei OCI: Ports müssen sowohl in der Cloud-Firewall als auch in der Instanz freigegeben werden.

a) VCN Security List / NSG in der OCI-Konsole Ingress-Regeln für 0.0.0.0/0 auf TCP 80 und TCP 443 (und UDP 443, wenn HTTP/3 genutzt werden soll).

b) Firewall in der Instanz. Oracle-Linux-Images bringen firewalld mit:

sudo firewall-cmd --permanent --add-service=http --add-service=https
sudo firewall-cmd --permanent --add-port=443/udp
sudo firewall-cmd --reload

Ubuntu-Images von Oracle haben stattdessen eine restriktive iptables-Regel:

sudo iptables -I INPUT 6 -m state --state NEW -p tcp --dport 80 -j ACCEPT
sudo iptables -I INPUT 6 -m state --state NEW -p tcp --dport 443 -j ACCEPT
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 auskommentieren, weil Caddy sonst dauerhaft erfolglos ein Zertifikat dafür anfordert.

3. Docker installieren

curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker $USER

Danach einmal neu einloggen.

4. Deploy-Key einrichten

Das Repo ist privat, ein HTTPS-Clone auf der VM würde also nach Zugangsdaten fragen. Stattdessen bekommt die VM einen eigenen Deploy-Key mit Nur-Lese-Rechten:

ssh-keygen -t ed25519 -C "djnizz-vm-deploy" -f ~/.ssh/djnizz_deploy -N ""
cat ~/.ssh/djnizz_deploy.pub

Den ausgegebenen Public Key in GitHub unter Repo → Settings → Deploy keys → Add deploy key eintragen und Allow write access nicht anhaken.

Anschließend einen eigenen Host-Alias anlegen bewusst nicht Host github.com, sonst würde dieser Key auch bei allen anderen GitHub-Repos angeboten und dort scheitern:

cat >> ~/.ssh/config <<'EOF'

Host github-djnizz
  HostName github.com
  User git
  IdentityFile ~/.ssh/djnizz_deploy
  IdentitiesOnly yes
EOF
chmod 600 ~/.ssh/config
ssh -T git@github-djnizz

Die letzte Zeile muss mit Hi nizzgruber/djnizz_website! You've successfully authenticated antworten. Dass GitHub danach „does not provide shell access" meldet, ist normal und kein Fehler.

5. Starten

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:

sudo ss -tulpn | grep -E ':(80|443)\s'

Variante A Ports sind frei: Caddy dieses Projekts übernimmt sie.

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.

docker compose up -d --build

Passender vhost, wenn der vorhandene Proxy Caddy auf dem Host ist:

djnizz.at {
	encode zstd gzip
	reverse_proxy 127.0.0.1:4321
}

Wenn es nginx ist:

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:

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 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:

docker compose logs -f caddy

Updates ausrollen

git pull
docker compose up -d --build

Konfiguration

Domain und ACME-Mailadresse lassen sich per .env neben der docker-compose.yml überschreiben:

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.

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.

Wenn später ein Booking-Formular, Analytics oder Spotify-/YouTube-Embeds dazukommen, muss src/pages/datenschutz.astro entsprechend erweitert werden.

Struktur

src/
  assets/       Bilder (werden beim Build zu WebP/AVIF optimiert)
  components/   Header, Hero, About, Footer, SocialIcon
  data/site.ts  Zentrale Inhalts- und Konfigurationsdatei
  layouts/      Base (SEO, JSON-LD), Legal
  pages/        index, impressum, datenschutz, 404
  styles/       global.css (Tailwind-Theme, Animationen)
scripts/        Einmalige Bildaufbereitung

Die Seiten sind alle vorgerendert. Der Node-Adapter ist trotzdem drin, damit später einzelne Routen (z. B. /api/booking) mit export const prerender = false dynamisch werden können, ohne dass sich am Deployment etwas ändert.

S
Description
No description provided
Readme
4.2 MiB
Languages
Astro 59.6%
JavaScript 24.9%
TypeScript 8.2%
CSS 5.4%
Dockerfile 1.9%