← Blog

Umami Analytics selbst hosten

Railyard

19. Mai 2026 · 8 Min. Lesezeit

Folge dem auf deinem eigenen Server. Kostenlos starten, keine Karte nötig

Du willst wissen, wie viele Leute heute deine Seite besucht haben und woher sie kamen, ohne jeden Pageview an eine Werbefirma zu schicken und ohne Cookie-Banner. Umami macht genau das: ein Open-Source-Analytics-Dashboard, das als ein Container gegen eine Postgres-Datenbank läuft. Diese Anleitung bringt dich von einem leeren Server zu Umami auf deiner eigenen Domain über HTTPS, verfolgt deine erste Seite, mit einem Backup, das du wiederherstellen kannst, und einem Plan für Upgrades. Der letzte Teil zeigt die Ein-Klick-Version auf Railyard.

Diese Anleitung nutzt Umami 3.4.1, das aktuelle Release, mit Postgres 16. Umami 3 unterstützt nur Postgres (Version 12.14 oder neuer), also gibt es hier keine MySQL-Option.

Was du brauchst

  • Einen Server. Umami und Postgres sind leichtgewichtig, also reicht ein kleiner Server völlig. Ein Hetzner CX23 (2 vCPU, 4 GB RAM, 40 GB NVMe) kostet 5,99 €/Monat exkl. MwSt. und lässt Platz für andere Apps. Nutze Ubuntu 24.04 oder ein anderes aktuelles Debian-basiertes Image.
  • Eine Domain oder Subdomain, die du auf den Server zeigen lassen kannst. Diese Anleitung nutzt analytics.example.com.
  • SSH-Zugriff als root oder ein User mit sudo.

Schritt 1: DNS auf den Server zeigen lassen und aktualisieren

Erstelle den Server, merke dir seine öffentliche IPv4-Adresse und füge bei deinem DNS-Provider einen A-Record für analytics.example.com hinzu, der auf diese Adresse zeigt. Mach das zuerst: Caddy kann erst ein Zertifikat holen, wenn der Name zu deinem Server aufgelöst wird, und DNS kann ein paar Minuten zum Aktualisieren brauchen.

Logge dich dann ein und bringe das System auf den aktuellen Stand:

ssh root@203.0.113.10
apt update && apt upgrade -y

Prüfe den Record von deiner eigenen Maschine:

dig +short analytics.example.com

Du solltest die IP-Adresse deines Servers sehen. Siehst du noch nichts, mach weiter und prüfe vor Schritt 5 noch einmal.

Schritt 2: Docker installieren

Umami, Postgres und Caddy laufen alle als Container, also ist Docker Engine mit dem Compose-Plugin das Einzige, was du installieren musst. Dockers Convenience-Skript richtet sein offizielles Repository und die Pakete ein:

curl -fsSL https://get.docker.com | sh
systemctl enable --now docker
docker --version
docker compose version

Du solltest eine Versionszeile für Docker und eine weitere für Docker Compose sehen.

Schritt 3: Secrets erstellen

Lege ein Verzeichnis für den Stack an und generiere drei Werte in eine .env-Datei daneben:

mkdir -p /opt/umami/backups
cd /opt/umami
echo "DB_PASSWORD=$(openssl rand -hex 24)" >> .env
echo "APP_SECRET=$(openssl rand -hex 32)" >> .env
echo "TWO_FACTOR_ENCRYPTION_KEY=$(openssl rand -hex 32)" >> .env
chmod 600 .env

Wofür jeder davon ist, aus Umamis eigener Dokumentation:

  • DATABASE_URL ist die einzige Variable, die Umami strikt benötigt. Du baust sie aus DB_PASSWORD in der Compose-Datei.
  • APP_SECRET sichert Authentifizierungs-Tokens. Jede Installation sollte ihren eigenen haben.
  • TWO_FACTOR_ENCRYPTION_KEY ist eine 64-Zeichen-Hex-Zeichenkette, die Zwei-Faktor-Secrets verschlüsselt. openssl rand -hex 32 erzeugt genau das. Umamis eigene Compose-Datei setzt sie, und du brauchst sie, falls du Zwei-Faktor-Login aktivieren willst.

Prüfe die Datei:

cat /opt/umami/.env

Du solltest drei Zeilen sehen, jede mit einem langen Zufallswert.

Schritt 4: Compose-Datei und Caddyfile schreiben

Speichere das als /opt/umami/compose.yaml. Es folgt dem Aufbau von Umamis eigener docker-compose.yml, mit fixierten Versionen statt latest und Caddy davor:

services:
  caddy:
    image: caddy:2
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy-data:/data
      - caddy-config:/config
    depends_on:
      - umami

  umami:
    image: ghcr.io/umami-software/umami:3.4.1
    restart: unless-stopped
    init: true
    environment:
      DATABASE_URL: postgresql://umami:${DB_PASSWORD}@db:5432/umami
      APP_SECRET: ${APP_SECRET}
      TWO_FACTOR_ENCRYPTION_KEY: ${TWO_FACTOR_ENCRYPTION_KEY}
    depends_on:
      db:
        condition: service_healthy
    healthcheck:
      test: ["CMD-SHELL", "curl -f http://localhost:3000/api/heartbeat"]
      interval: 5s
      timeout: 5s
      retries: 5

  db:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      POSTGRES_DB: umami
      POSTGRES_USER: umami
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - umami-db-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U umami -d umami"]
      interval: 5s
      timeout: 5s
      retries: 5

volumes:
  umami-db-data:
  caddy-data:
  caddy-config:

Ein paar Dinge, die du dazu wissen solltest:

  • Nur Caddy veröffentlicht Ports. Umami lauscht im Compose-Netzwerk auf 3000 und Postgres auf 5432, also ist keines der beiden aus dem Internet erreichbar.
  • Compose liest ${DB_PASSWORD} und die anderen Werte aus der .env-Datei im selben Verzeichnis.
  • Umami wartet, bis Postgres als gesund gemeldet wird, bevor es startet, und erstellt seine Tabellen beim ersten Boot.
  • Das caddy-data-Volume behält deine Zertifikate, sodass ein Neustart keine neuen anfordert.

Speichere das jetzt als /opt/umami/Caddyfile, mit deiner eigenen Domain:

analytics.example.com {
	encode zstd gzip
	reverse_proxy umami:3000
}

Caddy liest die Domain aus der Site-Adresse, holt sich dafür ein Let’s-Encrypt-Zertifikat, leitet HTTP auf HTTPS um und reicht Anfragen an den umami-Container weiter. Prüfe beide Dateien:

cd /opt/umami
docker compose config --quiet && echo "compose ok"
docker compose run --rm --no-deps caddy caddy validate --config /etc/caddy/Caddyfile

Du solltest compose ok sehen, dann am Ende von Caddys Ausgabe Valid configuration.

Schritt 5: Stack starten

docker compose up -d
docker compose ps

Du solltest db und umami nach zwanzig oder dreißig Sekunden beide als (healthy) markiert sehen, und caddy als Up. Prüfe die App von innerhalb ihres Containers:

docker compose exec umami curl -s http://localhost:3000/api/heartbeat

Du solltest {"ok":true} sehen. Beobachte dann, wie Caddy das Zertifikat holt:

docker compose logs -f caddy

Du solltest eine Zeile sehen, die besagt, dass das Zertifikat für analytics.example.com erhalten wurde. Drücke Strg+C und öffne https://analytics.example.com in deinem Browser. Du solltest Umamis Login-Seite mit einem gültigen Zertifikat sehen.

Schritt 6: Einloggen und das Standardpasswort ändern

Jede neue Umami-Installation erstellt denselben Account: Benutzername admin, Passwort umami. Logge dich damit ein und ändere das Passwort sofort in deinen Profileinstellungen. Bis du das tust, kann sich jeder, der deine Login-Seite findet, als Admin einloggen, also lass eine frische Installation nicht über Nacht mit dem Standardwert laufen.

Füge dann deine Site hinzu. Klicke in der Seitenleiste auf Websites, dann auf Add website, gib einen Namen und die Domain deiner Site ein und speichere. Klicke auf Edit bei der neuen Website und kopiere den Code aus dem Abschnitt Tracking code in den <head> deiner Site.

Lade deine Site in einem anderen Tab. Du solltest den Besuch im Umami-Dashboard innerhalb einiger Sekunden sehen. Falls nicht, probiere einen Browser ohne Adblocker: Umamis Doku weist darauf hin, dass Adblocker das Laden des Tracking-Skripts verhindern können.

Schritt 7: Datenbank sichern

Alles, was zählt, steckt in Postgres: dein Account, deine Websites und jeder Pageview. Speichere das als /opt/umami/backup.sh:

#!/usr/bin/env bash
set -euo pipefail
cd /opt/umami
docker compose exec -T db pg_dump -U umami umami | gzip > "backups/umami-$(date +%F).sql.gz"
find backups -name 'umami-*.sql.gz' -mtime +14 -delete

Mach es ausführbar, führe es einmal aus und plane es täglich um 03:00 Uhr mit crontab -e:

chmod +x /opt/umami/backup.sh
/opt/umami/backup.sh
ls -lh /opt/umami/backups
0 3 * * * /opt/umami/backup.sh

Du solltest eine .sql.gz-Datei von einigen Kilobyte bei einer neuen Installation sehen, die mit eintreffenden Daten wächst. Das Skript behält vierzehn Tage. Kopiere die Dateien auch vom Server weg (Objektspeicher, oder eine andere Maschine mit rsync), denn ein Backup auf derselben Festplatte überlebt den Verlust des Servers nicht.

Ein Backup zählt erst, wenn du es wiederhergestellt hast. Um in eine frische Installation wiederherzustellen, starte nur die Datenbank, lade den Dump, starte dann Umami:

docker compose up -d --wait db
gunzip -c backups/umami-2026-05-19.sql.gz | docker compose exec -T db psql -q -U umami umami
docker compose up -d

In eine leere Datenbank zu laden, bevor Umami startet, vermeidet Konflikte mit den Tabellen, die Umami beim ersten Boot erstellt. Du solltest Umami No pending migrations to apply loggen sehen, und dein alter Login und deine Daten sollten zurück sein.

Schritt 8: Upgrade

Umami führt seine Datenbankmigrationen beim Start aus, also ist ein Upgrade ein neuer Image-Tag und ein Neustart. Lies zuerst die Release Notes auf GitHub, mach ein Backup, ändere dann den Tag in compose.yaml (zum Beispiel von 3.4.1 auf das nächste Release) und führe aus:

/opt/umami/backup.sh
docker compose pull umami
docker compose up -d umami
docker compose logs -f umami

Du solltest sehen, wie die Migrationen angewendet werden, dann meldet Next.js, dass es bereit ist. Falls etwas schiefgeht, setz den alten Tag zurück und stelle das Backup aus Schritt 7 wieder her. Halte Caddy und Postgres auf dieselbe Weise aktuell: docker compose pull und docker compose up -d für Caddy, während ein Postgres-Major-Upgrade (16 auf 17) einen Dump und eine Wiederherstellung braucht, nicht nur einen neuen Tag.

Der Shortcut: mit Railyard

Schritte 2 bis 5 sind das, was die Railyard-Umami-Vorlage für dich macht: Umami auf Railyard deployen. Wähle einen Server, und Railyard baut Umami, erstellt eine Postgres-Datenbank dafür, verbindet beide, sodass es nichts von Hand zu verdrahten gibt, und generiert APP_SECRET. Die App bekommt sofort eine HTTPS-Adresse, und du kannst deine eigene Domain über ihren Domains-Tab mit den gezeigten DNS-Records hinzufügen (Domains und HTTPS).

Schritt 6 gilt weiterhin: logge dich mit admin / umami ein und ändere das Passwort sofort. Backups (Schritt 7) werden zu geplanten Postgres-Backups mit Ein-Klick-Wiederherstellung, beschrieben in Datenbanken und Backups.

Die Vorlage läuft auf einem Server in deinem eigenen Cloud-Account oder einem, den du bereits hast, also bleiben die Kosten beim Preis des Servers. Railyards Free-Plan deckt einen Server plus einen Datenbankserver und drei Apps ohne Kreditkarte ab. Pro ist 19 $/Monat und Team ist 49 $/Monat, pro Team.

Troubleshooting

Caddy bekommt kein Zertifikat. Fast immer DNS. Führe dig +short analytics.example.com aus und bestätige, dass die IP deines Servers zurückkommt. Stelle auch sicher, dass die Ports 80 und 443 in der Firewall deines Providers offen sind, denn Let’s Encrypt verbindet sich zum Server, um ihn zu validieren. Caddy versucht es von selbst erneut, also beobachte docker compose logs -f caddy, sobald DNS stimmt.

address already in use auf Port 80 oder 443. Etwas anderes lauscht, oft ein mit dem Image installiertes Nginx oder Apache. Finde es mit ss -tlnp | grep -E ':(80|443)\s', stoppe und deaktiviere es, führe dann docker compose up -d erneut aus.

Umami startet ständig neu. Führe docker compose logs umami aus. Die übliche Ursache ist eine DATABASE_URL, die nicht zur Datenbank passt. Falls du DB_PASSWORD nach dem ersten Start geändert hast, hat Postgres immer noch das alte: Das Passwort wird nur beim Erstellen des Volumes angewendet. Setze entweder den alten Wert zurück, oder ändere ihn in Postgres selbst mit ALTER USER.

Das Dashboard zeigt keine Besuche. Prüfe, dass der Tracking-Code im <head> der geladenen Seite steckt, dass die Domain im Website-Eintrag zu deiner Site passt, und probiere einen Browser ohne Adblocker. Im Netzwerk-Tab deines Browsers sollte script.js von deiner Umami-Domain laden.

Dem Server geht der Speicher aus. Umami und Postgres sind klein, aber auf einem mit anderen Apps geteilten Server kann der Out-of-Memory-Killer des Kernels einen Container stoppen. Prüfe mit dmesg | grep -i "out of memory" und docker stats, verschiebe dann etwas vom Server oder vergrößere ihn.

FAQ

Setzt Umami Cookies? Umami ist dafür gebaut, Analytics ohne Cookies zu sammeln, weshalb viele Sites es ohne Consent-Banner betreiben. Ob du trotzdem einen brauchst, hängt von den für dich geltenden Regeln ab, also prüfe sie.

Kann eine Umami-Installation mehrere Websites verfolgen? Ja. Füge jede unter Websites hinzu, und jede bekommt ihren eigenen Tracking-Code und ihr eigenes Dashboard.

Kann ich es ohne Docker betreiben? Ja. Umamis Doku beschreibt eine Quellinstallation mit Node.js 18.18 oder neuer, pnpm und einer Postgres-Datenbank, betrieben unter einem Prozessmanager wie PM2. Docker ist einfacher zu aktualisieren, weshalb diese Anleitung es nutzt.

Wie steige ich von Google Analytics um? Umami zählt ab dem Moment, in dem der Tracking-Code auf deiner Site ist. Lass beide Skripte eine Weile auf deinen Seiten, falls du Zahlen vergleichen willst, bevor du Googles entfernst.

Umami ist eine der am einfachsten gut zu betreibenden selbst gehosteten Apps: ein Container, eine Datenbank und eine kleine Proxy-Konfiguration. Egal wie du es einrichtest, die wichtigen Gewohnheiten bleiben gleich: ändere das Standardpasswort am ersten Tag, und stelle ein Backup einmal wieder her, damit du weißt, dass es funktioniert.

Warum Leute sich dafür Railyard entscheiden

  • Dein eigenes Cloud-Konto. Deploye auf DigitalOcean, Hetzner, Vultr, AWS, OVHcloud oder jedem Linux-Server per SSH, direkt von deinem Anbieter abgerechnet, ohne Aufschlag.
  • Ein fester Preis pro Team. Free ist für immer kostenlos: ein Server plus ein Datenbankserver, drei Apps, keine Karte. Pro kostet 19 $ im Monat für bis zu fünf Server und unbegrenzte Apps. Team kostet 49 $ im Monat mit unbegrenzten Servern. Keine Kosten pro App, pro Deployment, pro Sitz oder pro Gigabyte.
  • Templates mit einem Klick. Deploye Open-Source-Apps, wie Datenbanken, Analytics und Dev-Tools, mit einem Klick auf deinem eigenen Server.
  • Verwaltete Datenbanken. Postgres, MySQL und Redis mit geplanten, wiederherstellungsgeprüften Backups und Point-in-Time-Recovery.
  • Push-to-Deploy. Deploye von GitHub, GitLab oder der CLI, mit automatischem HTTPS und Releases ohne Ausfallzeit.

Umami mit einem Klick deployen

Die Railyard-Vorlage betreibt Umami mit angebundenem Postgres und generiertem APP_SECRET, auf einem Server, den du besitzt.

Kostenloser Plan, keine Kreditkarte, und 14 Tage Pro für jedes neue Team. Ein fester Preis pro Team.