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
9.8 KiB
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.ymlmit den Diensten:caddy,nextcloud,nextcloud-db(MariaDB),redis,nextcloud-cron,forgejo.- Zwei Docker-Netzwerke:
web(alles, was Caddy erreichen soll) undinternal(Datenbank etc.). caddy/Caddyfileverteilt nach Hostname:cloud.larpaso.de→ Nextcloudgit.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(nichtinternal). - 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
.envins 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 buildausführen und melden, ob der Build fehlerfrei einendist-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 statusprüfen: Es dürfen nur Quellcode + die neuen Konfigdateien (Dockerfile,nginx.conf,.dockerignore,.gitignore,astro.config.*) mitgehen – keinnode_modules, keindist.- 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-website → Einstellungen →
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.demuss 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.mjs→site: 'https://larpaso.de', statischer Output (Standard, kein Adapter).Dockerfile,nginx.conf,.dockerignoreliegen im Repo, entsprechen exakt der Vorlage oben.- Lokaler
npm run buildläuft fehlerfrei durch (4 statische Seiten,dist/wird erzeugt). - Alles committet und nach
https://git.larpaso.de/pascal/larpaso-websitegepusht.
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/keys
→ Deploy-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.demuss 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 restartin B6). - Astro bleibt statisch (
output: 'static').