Personal landing page and portfolio — joshuahirsig.xyz
  • Astro 53.3%
  • CSS 23.9%
  • TypeScript 20.4%
  • JavaScript 2.4%
Find a file
Joshua Hirsig a9e7ba2f22
All checks were successful
Build & Deploy / build-deploy (push) Successful in 30s
Projekte: TSPerms aufnehmen
Verlinkt das Forgejo-Repo git.joshuahirsig.xyz/docker/tsperms. Kein url-Feld,
weil die Anwendung selbst hinter dem Authentik-Login liegt.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 22:03:42 +02:00
.forgejo/workflows Deploy: Quellcode klonen statt actions/checkout 2026-07-30 17:39:37 +02:00
public/media Neubau als Astro-Bento-Dashboard mit DE/EN 2026-07-30 16:54:00 +02:00
src Projekte: TSPerms aufnehmen 2026-07-30 22:03:42 +02:00
.gitignore Infrastruktur: Server-Config versionieren, Deploy nach Forgejo umziehen 2026-07-30 16:35:48 +02:00
astro.config.mjs Inhalte: echte Projekte, OSS-Beitraege, verifizierte Zertifikate 2026-07-30 17:09:37 +02:00
docker-compose.yaml Infrastruktur: Server-Config versionieren, Deploy nach Forgejo umziehen 2026-07-30 16:35:48 +02:00
nginx.conf Review-Befunde: Deploy-Sicherheit, korrigierte Arbeitszahlen 2026-07-30 17:29:13 +02:00
package-lock.json Neubau als Astro-Bento-Dashboard mit DE/EN 2026-07-30 16:54:00 +02:00
package.json Neubau als Astro-Bento-Dashboard mit DE/EN 2026-07-30 16:54:00 +02:00
README.md Review-Befunde: Deploy-Sicherheit, korrigierte Arbeitszahlen 2026-07-30 17:29:13 +02:00
tsconfig.json Neubau als Astro-Bento-Dashboard mit DE/EN 2026-07-30 16:54:00 +02:00

joshuahirsig.xyz

Persönliche Landingpage und Portfolio. Astro, statisch gebaut, selbst gehostet auf dem vServer hinter Traefik.

Repo-Topologie — bitte lesen, bevor du pushst

Forgejo ist die Single Source of Truth.

git.joshuahirsig.xyz/joshii/joshuahirsig.xyz   ← hierhin pushen (origin)
        │
        └── Push-Mirror ──► github.com/joshii-h/joshuahirsig.xyz   (nur Spiegel)

Der Mirror läuft mit Force und überschreibt GitHub bedingungslos — er feuert sofort bei jedem Push, das 8-Stunden-Intervall ist nur der Fallback. Ein Push nach GitHub geht deshalb garantiert verloren. Damit das nicht versehentlich passiert, steht die Push-URL des github-Remotes lokal auf einem ungültigen Wert; ein Push dorthin scheitert laut statt still.

git remote -v
# origin  ssh://git@git.joshuahirsig.xyz:5478/joshii/joshuahirsig.xyz.git
# github  https://github.com/joshii-h/joshuahirsig.xyz.git (fetch)
# github  DISABLED-mirror-target-push-to-origin (push)

Entwicklung

npm install
npm run dev       # lokaler Dev-Server
npm run build     # statischer Build nach dist/
npm run preview   # Build lokal ansehen

Inhalte liegen als Markdown in src/content/ — je Sprache ein Unterordner (en/, de/). Ein neues Projekt ist eine neue .md-Datei, kein Code.

Achtung: Die Kacheln rendern nur das Frontmatter, nicht den Markdown-Body. Alles Sichtbare gehört also in summary, role, tech usw. Text unterhalb des Frontmatters erscheint nirgends — er eignet sich als Notiz, aber nicht als Inhalt.

Deployment

Push auf main → Forgejo Action (.forgejo/workflows/deploy.yml) baut die Seite und legt dist/ auf dem Host unter ~/Docker/Website/dist ab, dann Neustart des website-Containers. Es wird kein SSH-Key benötigt: Der Runner läuft auf demselben Host und bekommt den Docker-Socket gemountet.

dist/ ist bewusst nicht eingecheckt.

Einmalige Migration auf dem Server — Reihenfolge beachten

Der Workflow deployt nur dist/. docker-compose.yaml und nginx.conf bringt er nicht auf den Server, und docker restart liest ohnehin keine Compose-Änderungen ein. Solange der Server noch die alte Compose fährt, mountet nginx weiterhin das ganze Repo-Verzeichnis als Webroot und liefert die alte Seite aus — der Deploy läuft dabei grün durch, weil die alte Startseite antwortet. Diese Migration ist deshalb einmalig von Hand nötig:

ssh vserver
cd ~/Docker/Website

# 1) Die bisher untracked Configs sichern; sie kommen jetzt aus dem Repo
#    und würden den Pull sonst blockieren.
mkdir -p ~/Docker/_backups/website-cutover
cp nginx.conf docker-compose.yaml ~/Docker/_backups/website-cutover/
rm -f nginx.conf docker-compose.yaml nginx.conf.bak-premas

# 2) Neuen Stand holen (entfernt auch index.html, style.css und media/).
git pull origin main

# 3) Recreate statt restart — nur so greift der geänderte Volume-Mount.
docker compose up -d --force-recreate

# 4) Prüfen: Webroot muss jetzt auf dist zeigen, nicht auf das Repo.
docker inspect website --format '{{range .Mounts}}{{.Source}} -> {{.Destination}}{{println}}{{end}}'

Danach gilt der normale Weg: Push auf main → Action baut und deployt.

Ist dist/ zum Zeitpunkt von Schritt 3 noch nicht vorhanden, liefert nginx bis zum ersten Action-Lauf 404. Deshalb zuerst mergen (Action läuft, legt dist/ an) und erst danach die Schritte oben ausführen.

Betrieb

Datei Zweck
docker-compose.yaml nginx-Container, Traefik-Labels, www-Redirect
nginx.conf Matrix-Delegation, Uptime-Kuma-Status-Proxy

Matrix-Delegation — nicht anfassen ohne Test

nginx.conf liefert /.well-known/matrix/server und /.well-known/matrix/client aus. Diese Domain delegiert damit die Föderation an matrix.joshuahirsig.xyz und verweist auf MAS und LiveKit. Geht das kaputt, bricht die Föderation still — keine Fehlermeldung, nur Server, die einen nicht mehr erreichen.

Der Deploy-Workflow prüft beide Endpunkte nach jedem Deploy und schlägt fehl, wenn sie nicht stimmen. Nach manuellen Änderungen zusätzlich prüfen:

curl -s https://joshuahirsig.xyz/.well-known/matrix/server
curl -s https://joshuahirsig.xyz/.well-known/matrix/client

Live-Status

nginx.conf reicht /api/status/… intern an Uptime Kuma weiter, weil dessen API keine CORS-Header setzt und ein direkter Browser-Fetch auf status.joshuahirsig.xyz deshalb blockiert würde. Bewusst auf die zwei benötigten Endpunkte begrenzt.