No description
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Christian Säum 30cba296fe
All checks were successful
CI – Validate & Release / validate (push) Successful in 9s
CI – Validate & Release / release (push) Has been skipped
Merge pull request 'chore(license): AGPL-3.0-or-later + Copyright-Hinweis' (#1) from chore/add-license into main
2026-09-02 19:47:27 +00:00
.forgejo/workflows chore(ci): drop Codeberg backup/mirror step from release pipeline 2026-08-23 19:26:08 +02:00
.idea feat(pixelfed): initial Docker stack scaffold 2026-08-11 21:18:00 +02:00
configs/php feat(pixelfed): initial Docker stack scaffold 2026-08-11 21:18:00 +02:00
volumes fix(pixelfed): repair three deploy-blocking bugs found via a real build+run test 2026-08-23 18:19:46 +02:00
.env feat(pixelfed): initial Docker stack scaffold 2026-08-11 21:18:00 +02:00
.gitignore fix(pixelfed): repair three deploy-blocking bugs found via a real build+run test 2026-08-23 18:19:46 +02:00
AGENTS.md feat(pixelfed): initial Docker stack scaffold 2026-08-11 21:18:00 +02:00
CICD-Actions.md chore(ci): drop Codeberg backup/mirror step from release pipeline 2026-08-23 19:26:08 +02:00
CLAUDE.md feat(pixelfed): initial Docker stack scaffold 2026-08-11 21:18:00 +02:00
docker-compose.yml fix(pixelfed): repair three deploy-blocking bugs found via a real build+run test 2026-08-23 18:19:46 +02:00
LICENSE chore(license): add AGPL-3.0-or-later license and copyright notice 2026-09-02 21:32:28 +02:00
Projekt.md feat(pixelfed): initial Docker stack scaffold 2026-08-11 21:18:00 +02:00
README.md chore(license): add AGPL-3.0-or-later license and copyright notice 2026-09-02 21:32:28 +02:00

Pixelfed – WSC Standard Stack

Selbst gehosteter Pixelfed-Server (föderiertes Foto-/Video-Sharing über ActivityPub, kompatibel mit Mastodon & Co.). Eigenständiges Image auf Basis von serversideup/php:8.4-fpm-nginx (kein offizielles Pixelfed-Docker-Base-Image verfügbar), mit MariaDB, Redis, Horizon (Queue) und dauerhaftem Laravel-Scheduler.

Template-Hinweis: .env enthält nur Platzhalter (CHANGE_ME, example.*). Vor dem Einsatz anpassen, Passwörter gemäß Anleitung im .env-Kopf erzeugen (openssl rand -hex 32). Werte, die je in Git lagen, gelten als kompromittiert → rotieren.

Details zu Architektur/Abweichungen: siehe Projekt.md.


1. Voraussetzungen

  • Docker + Docker Compose v2
  • Externes Netz traefik_proxy_network (Traefik-Stack)
  • Zentrale Stacks für die Integrationen: docker-autoheal-neustart, docker-ofelia-cronjobs, docker-docker-backup-backups
  • Backup-Verzeichnis ${BACKUP_PATH} (Default /Daten/Backups) muss auf dem Host existieren
  • Die Volume-Ordner unter ./volumes/ existieren bereits nach git clone/pull (leer bis auf .gitkeep) — der local-Volume-Treiber (o: bind, type: none) legt fehlende Zielverzeichnisse NICHT selbst an, ein frischer Deploy würde sonst beim ersten docker compose up mit "no such file or directory" abbrechen
  • Ein Mail-/SMTP-Zugang für Transaktions-E-Mails (Registrierungsbestätigung, Passwort-Reset, Invite-Links)
  • Die Bind-Mount-Verzeichnisse ./volumes/storage und ./volumes/bootstrap-cache müssen dem www-data-User im Container gehören (UID/GID 33, Debian-Standard im serversideup/php-Image). Vor dem ersten Start einmalig:
    sudo chown -R 33:33 volumes/storage volumes/bootstrap-cache
    
    Ohne diesen Schritt schlagen Migration, Storage-Symlink und Uploads mit "Permission denied" fehl.

2. .env konfigurieren

Vor dem ersten Start mindestens folgende Platzhalter ersetzen:

Variable Zweck
COMPOSE_PROJECT_NAME Präfix für Container-/Image-Namen
HOSTRULE, PRIMARY_DOMAIN, APP_URL, APP_DOMAIN, ADMIN_DOMAIN, SESSION_DOMAIN eigene Domain
REDIS_PASSWORD, SQL_PASSWORD, SQL_ROOT_PASSWORD openssl rand -hex 32
APP_KEY siehe Schritt 4 (kann erst nach dem ersten Build erzeugt werden)
MAIL_* SMTP-Zugangsdaten für Transaktions-E-Mails
BACKUP_PATH Host-Verzeichnis für Backups

OPEN_REGISTRATION=false und PF_USER_INVITES=false sind bereits Standard – Registrierung läuft ausschließlich über von dir erzeugte Invite-Links (siehe Schritt 5).


3. Image bauen

Wichtig: docker compose immer aus diesem Stack-Verzeichnis starten (${PWD}-Mounts).

docker compose build app

Klont dabei den dev-Branch von pixelfed/pixelfed frisch und installiert alle Composer-Abhängigkeiten in das Image (dauert ein paar Minuten). horizon und scheduler nutzen anschließend automatisch dasselbe Image (kein eigener Build nötig).


4. APP_KEY erzeugen

Pixelfed liest die Konfiguration ausschließlich aus Container-Umgebungsvariablen – es gibt kein persistentes .env im Container, daher funktioniert artisan key:generate nicht wie gewohnt. Stattdessen den Key einmalig generieren lassen und manuell eintragen:

docker compose run --rm app php artisan key:generate --show

Ausgabe (inkl. base64:-Prefix) in der .env bei APP_KEY eintragen.


5. Starten

docker compose up -d sql redis
# ~30 Sekunden warten, bis MariaDB durchgestartet ist
docker compose up -d

Beim ersten Start migriert app automatisch die Datenbank (AUTORUN_LARAVEL_MIGRATION=true) und legt den storage-Symlink an.

Einmalige Setup-Kommandos

docker compose exec app php artisan instance:actor      # Pflicht für Föderation (ActivityPub)
docker compose exec app php artisan import:cities        # Standort-Funktion
docker compose exec app php artisan passport:keys         # Pflicht, da OAUTH_ENABLED=true
# Eigenen Admin-Account anlegen
docker compose exec app php artisan user:create

# Invite-Link für neue Nutzer erzeugen (Registrierung ist geschlossen,
# nur DU kannst über diesen Befehl neue Accounts freigeben)
docker compose exec app php artisan admin:invite

6. Integrationen

Autoheal (Self-Healing)

autoheal=true auf app, horizon, scheduler, redis, sql (alle mit Healthcheck).

⚠️ Der app-Healthcheck prüft http://localhost:8080/api/v1/instance. Liefert die App dauerhaft 5xx (z. B. ausstehende Migration beim Erst-Deploy), kann Autoheal den app-Container in eine Restart-Schleife bringen → beim ersten Setup beobachten, ggf. autoheal-Label temporär entfernen.

Scheduler statt Cronjob

scheduler läuft dauerhaft mit php artisan schedule:work – ersetzt den sonst nötigen Minuten-Cronjob (* * * * * artisan schedule:run). Kein Ofelia-Job dafür nötig.

DB-Backup (shyim/docker-backup) – Schedule 5-Feld

Label auf sql: type=mysql (MariaDB ist mysql-kompatibel), BACKUP_SCHEDULE (Default alle 6 h), Retention BACKUP_RETENTION. Landet unter /Daten/Backups/<sql-container>/db/….

Datei-Backup (Ofelia + backup-helper)

Da shyim nur named volumes sichert, läuft das Datei-Backup über den idle backup-helper: Ofelia job-exec packt täglich 05:00 ein tar.gz von storage/ + bootstrap/cache/ nach ${BACKUP_PATH}/<projekt>/files/ (Retention 5 Tage).


7. Updates

Da der Anwendungscode im Image gebaut wird (kein Bind-Mount des kompletten Codes, siehe Projekt.md), erfolgt ein Update über einen Rebuild statt git pull:

docker compose build --no-cache app
docker compose up -d
docker compose exec app php artisan migrate --force

8. Hinweise / Stolpersteine

  • Ofelia vs. shyim Cron-Format: Ofelia = 6-Feld (0 5 0 * * *), shyim = 5-Feld (5 0 * * *). Nicht verwechseln.
  • Kein git pull im Container: Anwendungscode ist im Image gebacken, siehe Abschnitt 7.
  • APP_KEY kann nicht per artisan key:generate persistiert werden – manuell in .env eintragen (Schritt 4).
  • Registrierung: OPEN_REGISTRATION=false + PF_USER_INVITES=false – einziger Weg für neue Accounts ist php artisan admin:invite.
  • Upload-Limits: PHP_UPLOAD_LIMIT (Standard 200M) steuert post_max_size und upload_max_filesize gemeinsam; max_execution_time/max_file_uploads liegen fest in configs/php/pixelfed.ini.
  • Bind-Mount-Rechte: volumes/storage + volumes/bootstrap-cache müssen UID/GID 33 gehören (siehe Abschnitt 1) – sonst "Permission denied" bei Migration/Uploads.

9. Nützliche Befehle

docker compose config -q          # Konfiguration validieren
docker compose up -d
docker compose logs -f app
docker compose exec app php artisan <command>
docker compose exec app php artisan horizon:status
docker compose down

10. CI/CD

Die Pipeline (.forgejo/workflows/ci.yml) läuft self-hosted auf Forgejo, ganz ohne externe Actions (Checkout per git clone). Es gibt keinen Code-Mirror nach Codeberg:

  • validate (jeder Push/PR auf main + Tags): docker compose config -q, yamllint (relaxed) und gitleaks (nur Working-Tree).
  • release (nur Tag v*): baut ein schlankes Deploy-ZIP und hängt es an ein Forgejo-Release.

Release auslösen:

git tag v1.1
git push origin v1.1

Details siehe CICD-Actions.md.

Lizenz

Copyright (C) 2026 Christian Säum – web-seo-consulting.eu

Dieses Projekt steht unter der GNU Affero General Public License, Version 3 oder (nach deiner Wahl) einer späteren Version (AGPL-3.0-or-later). Der vollständige Lizenztext steht in der Datei LICENSE.

Du darfst die Software nutzen, weitergeben und – auch kommerziell – verkaufen. Gibst du eine veränderte Fassung weiter oder betreibst du sie über ein Netzwerk (z. B. als Dienst), muss deren vollständiger Quellcode ebenfalls unter der AGPL-3.0-or-later verfügbar sein. Der Copyright-Hinweis und die Nennung des ursprünglichen Autors dürfen nicht entfernt werden.

Diese Angabe betrifft nur die in diesem Repository enthaltenen eigenen Dateien (Konfiguration, Skripte, Anpassungen). Eingebundene Fremdsoftware und Container-Images unterliegen weiterhin ihren eigenen Lizenzen.