larpaso-website/DEPLOYMENT.md
Pascal Scholz e688eaa265 Add ready-to-run copy-paste blocks for server deployment (Teil B)
Documents that Teil A is verified (build tested locally) and provides
exact commands for deploy key, docker-compose service, Caddyfile
block, and DNS steps so the server-side rollout needs no improvisation.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T8eccP4XnXFJvpSYMm26as
2026-09-12 03:32:49 +02:00

9.8 KiB
Raw Blame History

DEPLOYMENT.md Kontext & Aufgabe für Claude Code

Dieses Dokument gibt dir (Claude Code) den nötigen Kontext, um die Agentur-Website sauber auf dem bestehenden VPS auszuliefern, ohne mit der laufenden Infrastruktur zu kollidieren. Lies es komplett, bevor du Änderungen vornimmst.

Es gibt zwei Teile:

  • Teil A im Projekt (das machst du, Claude Code): Dateien im Repo erstellen, committen, pushen.
  • Teil B auf dem Server (das macht der Mensch, Pascal, selbst): nur Referenz, damit du die Dateien passend dazu erstellst. Führe Teil B NICHT aus und frage nicht nach Server-Zugängen.

1. Bestehende Infrastruktur (nicht verändern!)

Auf dem Server läuft bereits ein Docker-Compose-Stack. Wichtig für dich: Es gibt schon einen zentralen Reverse Proxy (Caddy), der Ports 80/443 besitzt und per Domain verteilt. Du darfst keinen zweiten Reverse Proxy bauen und keine Ports 80/443 belegen.

Aufbau (Ordner ~/stack auf dem Server = /home/deploy/stack):

  • docker-compose.yml mit den Diensten: caddy, nextcloud, nextcloud-db (MariaDB), redis, nextcloud-cron, forgejo.
  • Zwei Docker-Netzwerke: web (alles, was Caddy erreichen soll) und internal (Datenbank etc.).
  • caddy/Caddyfile verteilt nach Hostname:
    • cloud.larpaso.de → Nextcloud
    • git.larpaso.de → Forgejo
  • SSL/HTTPS macht Caddy vollautomatisch über Let's Encrypt. Neue Domains brauchen nur einen Caddy-Block + einen passenden DNS-A-Eintrag.

Regeln:

  • Bestehende Dienste (nextcloud*, forgejo, *-db, redis, caddy) nicht anfassen/neu starten.
  • Der neue Website-Dienst hängt nur am Netzwerk web (nicht internal).
  • Der Website-Container exponiert keine Host-Ports. Caddy erreicht ihn intern über den Container-Namen im web-Netzwerk.
  • Keine Passwörter, Tokens, Keys oder Inhalte der .env ins Repo, ins Dockerfile oder in Chat-Ausgaben schreiben.

2. Ziel

Die Astro-Website soll unter https://larpaso.de live gehen (optional zusätzlich www.larpaso.de → Weiterleitung auf larpaso.de). Sie wird auf dem Server gebaut (Multi-Stage-Docker-Build: Node baut die statischen Dateien, nginx liefert sie aus) und über den bestehenden Caddy ausgeliefert.


TEIL A Deine Aufgaben im Projekt (Claude Code)

A1. Projekt prüfen

  • Zeig die Projektstruktur der obersten Ebene.
  • Bestätige: Ist es ein Astro-Projekt? Gibt es package.json (und Lockfile)?
  • Ermittle den Paketmanager (npm / pnpm / yarn) am Lockfile (package-lock.json → npm, pnpm-lock.yaml → pnpm, yarn.lock → yarn) und die passenden Build-Befehle. Passe die Dockerfile-Befehle unten entsprechend an.

A2. Astro auf statische Ausgabe + Domain konfigurieren

  • Stelle sicher, dass Astro statisch baut (Standard output: 'static' KEIN Server-Adapter, da nginx nur statische Dateien ausliefert).
  • Setze in astro.config.* die Site-URL:
    export default defineConfig({
      site: 'https://larpaso.de',
      // output: 'static' ist Standard  nicht auf 'server' stellen
    });
    

A3. Multi-Stage-Dockerfile anlegen (Repo-Wurzel: Dockerfile)

Vorlage für npm. Bei pnpm/yarn die Install-/Build-Zeilen entsprechend anpassen (z. B. corepack enable && pnpm install --frozen-lockfile && pnpm build).

# --- Build-Stage ---
FROM node:22-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# --- Serve-Stage ---
FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80

A4. nginx-Konfiguration anlegen (Repo-Wurzel: nginx.conf)

server {
    listen 80;
    server_name _;
    root /usr/share/nginx/html;
    index index.html;

    # Saubere URLs + Fallback
    location / {
        try_files $uri $uri/ $uri.html /index.html;
    }

    # Astro legt gehashte Assets unter /_astro ab -> lange cachen
    location /_astro/ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
}

A5. .dockerignore anlegen (Repo-Wurzel)

node_modules
dist
.git

A6. .gitignore sicherstellen (Repo-Wurzel)

Muss mindestens enthalten:

node_modules
dist

A7. Lokal gegenprüfen (optional, aber empfohlen)

  • Wenn Node lokal vorhanden: einmal npm install + npm run build ausführen und melden, ob der Build fehlerfrei einen dist-Ordner erzeugt. So fängst du Build-Fehler VOR dem Server-Deploy ab. (Falls Node lokal fehlt: überspringen und dem Menschen mitteilen.)

A8. Committen & pushen

  • git status prüfen: Es dürfen nur Quellcode + die neuen Konfigdateien (Dockerfile, nginx.conf, .dockerignore, .gitignore, astro.config.*) mitgehen kein node_modules, kein dist.
  • Sinnvolle Commit-Nachricht, dann git push origin main.
  • Danach dem Menschen bestätigen, dass alles in Forgejo liegt, und ihn auf Teil B verweisen.

TEIL B Server-Schritte (macht Pascal selbst; hier nur zur Abstimmung)

Diese Schritte führt der Mensch auf dem Server aus. Sie sind hier dokumentiert, damit die Dateien aus Teil A dazu passen. Claude Code führt sie nicht aus.

B1. Lese-Zugang des Servers zu Forgejo (einmalig)

Auf dem Server als deploy:

ssh-keygen -t ed25519 -C "server-deploy@larpaso" -f ~/.ssh/id_ed25519
cat ~/.ssh/id_ed25519.pub

Diesen öffentlichen Key in Forgejo eintragen: Repo larpaso-websiteEinstellungen → Deploy-Schlüssel → Schlüssel hinzufügen, einfügen, schreibgeschützt lassen.

B2. Repo auf den Server klonen (einmalig)

mkdir -p ~/sites
git clone ssh://git@git.larpaso.de:2222/pascal/larpaso-website.git ~/sites/larpaso-website

B3. Website-Dienst in ~/stack/docker-compose.yml ergänzen

Unter services: einfügen:

  website:
    build:
      context: /home/deploy/sites/larpaso-website
    restart: unless-stopped
    networks: [web]

(Keine ports:-Angabe Caddy erreicht den Container intern.)

B4. Caddy-Block in ~/stack/caddy/Caddyfile ergänzen

larpaso.de {
    reverse_proxy website:80
}

# optional, nur falls DNS-A-Eintrag für www existiert:
www.larpaso.de {
    redir https://larpaso.de{uri} permanent
}

B5. DNS bei IONOS setzen

  • A-Eintrag: Hostname @ → Server-IPv4 (den evtl. vorhandenen alten @-A-Eintrag ersetzen, nicht doppelt anlegen).
  • Optional A-Eintrag: Hostname www → Server-IPv4 (nur nötig, wenn der www-Block genutzt wird).
  • Hinweis: Ein A-Eintrag auf @ ändert die MX-/Mail-Einträge NICHT die E-Mails laufen unverändert weiter.
  • Vor dem nächsten Schritt kurz warten/prüfen: nslookup larpaso.de muss die Server-IP zeigen, sonst kann Caddy kein Zertifikat holen.

B6. Bauen & starten

cd ~/stack
docker compose build website
docker compose up -d website
docker compose restart caddy      # lädt den neuen Caddyfile-Block
docker compose logs -f caddy      # auf "certificate obtained successfully" für larpaso.de achten

Dann https://larpaso.de im Browser aufrufen.

B7. Künftige Updates (Ablauf bei jeder Änderung)

cd ~/sites/larpaso-website && git pull
cd ~/stack && docker compose build website && docker compose up -d website


Status

Teil A ist erledigt und geprüft:

  • astro.config.mjssite: 'https://larpaso.de', statischer Output (Standard, kein Adapter).
  • Dockerfile, nginx.conf, .dockerignore liegen im Repo, entsprechen exakt der Vorlage oben.
  • Lokaler npm run build läuft fehlerfrei durch (4 statische Seiten, dist/ wird erzeugt).
  • Alles committet und nach https://git.larpaso.de/pascal/larpaso-website gepusht.

Teil B steht noch aus das macht Pascal selbst auf dem Server. Fertige Copy-Paste-Blöcke dafür:

B1 Deploy-Key erzeugen (als deploy auf dem Server)

ssh-keygen -t ed25519 -C "server-deploy@larpaso" -f ~/.ssh/id_ed25519_larpaso-website -N ""
cat ~/.ssh/id_ed25519_larpaso-website.pub

Den ausgegebenen Public Key in Forgejo eintragen: https://git.larpaso.de/pascal/larpaso-website/settings/keysDeploy-Schlüssel hinzufügen, einfügen, schreibgeschützt lassen.

B2 Repo klonen

mkdir -p ~/sites
GIT_SSH_COMMAND="ssh -i ~/.ssh/id_ed25519_larpaso-website" \
  git clone ssh://git@git.larpaso.de:2222/pascal/larpaso-website.git ~/sites/larpaso-website

B3 Service in ~/stack/docker-compose.yml ergänzen

Unter services: einfügen (Einrückung an bestehende Datei anpassen):

  website:
    build:
      context: /home/deploy/sites/larpaso-website
    restart: unless-stopped
    networks: [web]

B4 Caddy-Block in ~/stack/caddy/Caddyfile ergänzen

larpaso.de {
    reverse_proxy website:80
}

www.larpaso.de {
    redir https://larpaso.de{uri} permanent
}

(Den www-Block nur, wenn auch ein DNS-A-Eintrag für www existiert.)

B5 DNS bei IONOS

  • A-Eintrag @ → Server-IPv4 (bestehenden @-Eintrag ersetzen).
  • Optional A-Eintrag www → Server-IPv4.
  • Prüfen: nslookup larpaso.de muss die Server-IP liefern, bevor B6 läuft.

B6 Bauen & starten

cd ~/stack
docker compose build website
docker compose up -d website
docker compose restart caddy
docker compose logs -f caddy   # auf "certificate obtained successfully" für larpaso.de warten

Danach https://larpaso.de im Browser prüfen.

B7 Künftige Updates

cd ~/sites/larpaso-website && git pull
cd ~/stack && docker compose build website && docker compose up -d website

Sicherheits-Leitplanken (Zusammenfassung)

  • Keine Secrets ins Repo/Dockerfile/Logs.
  • Kein zweiter Reverse Proxy, keine Belegung von 80/443 durch den Website-Dienst.
  • Website nur im web-Netzwerk, keine Host-Ports.
  • Bestehende Dienste nicht verändern oder neu starten (außer dem bewussten caddy restart in B6).
  • Astro bleibt statisch (output: 'static').