Seit einiger Zeit betreibe ich auf einem Netcup-Rootserver eine Reihe selbst gehosteter Dienste – als vollständigen Ersatz für Google Drive, GitHub, WhatsApp, Slack und einige andere Cloud-Produkte. In diesem Post gebe ich einen Überblick über den gesamten Stack. Nachfolgende Artikel werden die einzelnen Dienste jeweils im Detail vorstellen.

Die Basis: Ein Rootserver und Docker Swarm

Der gesamte Stack läuft auf einem einzelnen Rootserver bei Netcup. Als Container-Orchestrierung kommt Docker Swarm zum Einsatz – nicht Kubernetes. Das ist eine bewusste Entscheidung: Für einen einzelnen Node ist Swarm deutlich einfacher zu betreiben, verbraucht weniger Ressourcen und erfordert wesentlich weniger Konfigurationsaufwand. Die meisten Swarm-Features, die ich brauche – Rolling Updates, Secrets-Management, Health Checks, Restart Policies – sind direkt verfügbar, ohne Helm-Charts oder Operator-Patterns.

Jeder Dienst ist als eigener Stack mit einer docker-stack.yml organisiert. Das bedeutet: Stacks lassen sich unabhängig voneinander deployen und updaten. Ein make deploy in einem Stack-Verzeichnis reicht aus.

Traefik: Der einzige Weg nach draußen

Der wichtigste Bestandteil des Setups ist Traefik v3.6 als reverse Proxy und Ingress-Controller. Traefik ist der einzige Dienst, der direkt auf den öffentlichen Ports :80 und :443 lauscht – alle anderen Dienste kommunizieren ausschließlich über interne Docker-Netzwerke.

Was Traefik besonders praktisch macht: Statt eine zentrale Konfigurationsdatei für alle Routen zu pflegen, konfiguriert sich jeder Dienst selbst über Labels in der docker-stack.yml:

1
2
3
4
labels:
  - "traefik.enable=true"
  - "traefik.http.routers.forgejo.rule=Host(`git.bugtrack.eu`)"
  - "traefik.http.routers.forgejo.tls.certresolver=letsencrypt"

Traefik liest diese Labels dynamisch aus der Swarm-API und richtet Routen und TLS-Zertifikate automatisch ein – inklusive automatischer Erneuerung via Let’s Encrypt. Neue Dienste lassen sich also hinzufügen, ohne Traefik selbst neu zu konfigurieren.

Netzwerke: Zwei globale, viele lokale

Die Dienste kommunizieren über Docker Overlay-Netzwerke. Es gibt zwei netzwerkweit verfügbare (global scope):

  • proxy-tier: Das Traefik-Netzwerk. Jeder Dienst, der öffentlich erreichbar sein soll, muss diesem Netzwerk beitreten.
  • monitoring: Verbindet alle Dienste mit Prometheus für Metrik-Scraping.

Daneben hat jeder Stack sein eigenes internes Netzwerk für die interne Kommunikation – z.B. zwischen App-Server und Datenbank. Diese internen Netzwerke sind von außen nicht erreichbar.

Die Dienste

Forgejo – Git-Hosting

git.bugtrack.eu – Forgejo ist ein leichtgewichtiger, self-hosted Git-Dienst (ein Fork von Gitea). Es dient als zentrales Repository für alle Infrastruktur-Konfigurationen, den Sourcecode dieses Blogs und weitere Projekte.

Synapse – Matrix-Homeserver und Messenger-Brücken

matrix.bugtrack.eu – Synapse ist der Referenz-Homeserver für das Matrix-Protokoll – ein offenes, föderiertes Kommunikationsprotokoll. Neben dem eigentlichen Homeserver laufen im Synapse-Stack mehrere mautrix-Brücken, die Signal, Telegram und WhatsApp in Matrix integrieren. So landen alle Nachrichten in einem einzigen Client (z.B. Element), unabhängig davon, über welches Netzwerk sie gesendet wurden.

Dazu gesellt sich noch baibot, ein Matrix-Chat-Bot, der Large Language Models einbindet.

Nextcloud – Cloud-Storage, Office und Video

Nextcloud ist wohl der komplexeste Dienst im Stack – und bildet das Herzstück des Self-Hosting-Setups als Ersatz für Google Workspace:

  • Dateispeicher via Nextcloud Files (inkl. Read-Only-Mount einer Synology NAS über Tailscale)
  • Kollaboratives Editieren via OnlyOffice (als eigener Docker-Dienst im Stack)
  • Videokonferenzen via Nextcloud Talk mit eigenem High-Performance-Backend
  • Kollaboratives Zeichnen via Nextcloud Whiteboard

Um Ausfallzeiten bei Updates zu vermeiden, laufen App- und Web-Server jeweils mit zwei Replicas und einem Rolling-Update-Policy.

Karakeep – Bookmarks und Webarchiv

karakeep.bugtrack.eu – Karakeep ist ein self-hosted Social-Bookmarking-Dienst. Links lassen sich speichern, taggen und per Volltext durchsuchen (via Meilisearch im Hintergrund). Für Link-Previews und Screenshots läuft ein headless Chrome im selben Stack.

Grafana – Monitoring und Observability

grafana.bugtrack.eu – Der Monitoring-Stack besteht aus:

  • Prometheus für Metrik-Scraping aller Dienste
  • Loki für Log-Aggregation (ähnlich wie Elasticsearch, aber effizienter)
  • Promtail als Log-Shipper, der Container-Logs an Loki weiterleitet
  • cAdvisor und node_exporter für Host- und Container-Metriken
  • Grafana als Dashboard-Frontend

Damit habe ich einen vollständigen Überblick über Ressourcenverbrauch, Fehlermeldungen und Service-Health – alles auf einem Dashboard.

Dieser Blog

blog.bugtrack.eu – Der Blog selbst ist denkbar einfach: Hugo generiert aus Markdown-Dateien statisches HTML, das ein Nginx-Container ausliefert. Der Content lebt in einem separaten Git-Repository (tech-blog.git auf dem Forgejo-Server). Ein make deploy im Blog-Verzeichnis zieht die neuesten Inhalte, baut die Seite und deployed den Nginx-Stack neu.

Secrets und Sicherheit

Alle sensiblen Werte (Datenbankpasswörter, API-Keys, JWT-Secrets) werden als Docker Secrets verwaltet und zur Laufzeit unter /run/secrets/<name> in die Container eingebunden. Secrets folgen einem Datumsschema (<name>_YYYYMMDD), das Rotation ohne Downtime ermöglicht.

Für Dienste, die Secrets nicht nativ aus Dateien lesen können, kommen kleine Wrapper-Entrypoints (Shell-Skripte) zum Einsatz, die das Secret in eine Umgebungsvariable exportieren, bevor der eigentliche Prozess startet.

Was kommt als Nächstes

In den folgenden Posts werde ich die einzelnen Stacks im Detail vorstellen: die Traefik-Konfiguration, den Synapse-Stack mit seinen Bridges, die Komplexität des Nextcloud-Setups und den Monitoring-Stack. Wer Fragen hat, findet mich auf Matrix: @karsten:matrix.bugtrack.eu.