Zum Hauptinhalt springen
S-EDV news
← Alle Anleitungen
📘 Anleitung Server & Netzwerk 16.09.2026 · 13 min Lesezeit

Rallly mit Docker Compose selbst hosten: Terminabstimmung ohne Doodle

Rallly 4.16 mit dem offiziellen Docker-Compose-Stack selbst hosten: .env, Start, Mailversand und Adminkonto, Betrieb hinter Reverse Proxy, Backup mit pg_dump, Wiederherstellung, Update und Lizenzgrenzen.

Geprüft am 22.10.2026 · für Rallly 4.16.1

WerbelinksMit * markierte Links sind Werbelinks: Bei einem Kauf erhalten wir eine Provision, der Preis bleibt gleich. Als Amazon-Partner verdiene ich an qualifizierten Verkäufen. Mehr dazu

Holztisch im hellen Büro mit leerem Tischkalender, bunten Haftnotizen, Kugelschreiber, Kaffeetasse und Grünpflanzen

Für die Terminabstimmung im Team greifen viele zu Doodle. Dabei liegen Namen, E-Mail-Adressen und Verfügbarkeiten auf einem fremden Server, für Abstimmungen mit Kunden oder externen Dienstleistern also eine Auftragsverarbeitung, die dokumentiert sein will. Rallly bietet dieselbe Funktion auf einem eigenen Server: Der Organisator legt eine Umfrage mit Terminvorschlägen an, Teilnehmer stimmen über einen Link ohne Konto ab. Diese Anleitung installiert Rallly 4.16.1 mit dem offiziellen Docker-Compose-Stack, bindet einen vorhandenen Reverse Proxy an und zeigt Backup und Wiederherstellung.

Voraussetzungen

Die Installationsanleitung verlangt einen Server mit mindestens 2 GB RAM, Docker ab 19.03 mit Compose v2, eine Domain mit A-Record auf den Server und einen SMTP-Zugang. Im Test zeigte docker stats kurz nach dem Start 283 MiB für die Anwendung, 42 MiB für PostgreSQL und 5 MiB für den Objektspeicher Garage. Mit 2 CPU-Kernen und 4 GB RAM haben Sie Luft für Updates. Die Images belegen rund 1,9 GB Plattenplatz (Rallly 1,36 GB, postgres:18-alpine 434 MB, Garage 100 MB).

  • Linux-Server (x86_64) mit Docker Engine und Docker Compose v2 oder neuer, im Test Docker 29.8.2 und Compose 5.5.1.
  • Domain, im Beispiel rallly.example.com, mit A-Record auf den Server.
  • SMTP-Zugang mit Absenderadresse, für die SPF und DKIM gesetzt sind.
  • Für den gebündelten Proxy freie Ports 80 und 443, alternativ ein vorhandener Reverse Proxy.
  • Ausgehender HTTPS-Zugriff auf licensing.rallly.co für einen Lizenzschlüssel und auf api.rallly.co (stündliche Updateprüfung seit 4.16).

Zur Lizenz: Rallly steht unter AGPL-3.0. Laut offizieller Seite „Licensing“ ist der Selbstbetrieb mit einem einzigen Benutzerkonto kostenfrei, für mehr Konten erwartet das Projekt einen Lizenzschlüssel (Stufen Plus, Organization, Enterprise, jeweils einmalig für die Serie 4.x).

EckdatumWert
Imagelukevella/rallly:4 (im Test 4.16.1, festlegbar über RALLLY_IMAGE)
Diensteweb, db (PostgreSQL 18), garage (S3-Objektspeicher), traefik (optional)
Port80/443 über Traefik oder 127.0.0.1:3000 bei externem Proxy
Volumesdb-data, garage-data, garage-meta, acme-data
Konfigurationnur /opt/rallly/.env, die docker-compose.yml bleibt unverändert

Schritt 1: Stack-Dateien herunterladen

Seit Version 4.10 liefert das Projekt den Selbstbetrieb als verwalteten Stack im Repository lukevella/rallly-selfhosted mit dem Verwaltungsskript rallly.sh. Die docker-compose.yml sollen Sie laut Dokumentation nicht bearbeiten, denn Updates überschreiben lokale Änderungen. Der offizielle Installer legt alles unter /opt/rallly an und fragt die Konfiguration interaktiv ab:

# Offizieller Installer, legt den Stack unter /opt/rallly an
curl -fsSL https://get.rallly.co | bash

Wer vorher sehen möchte, was ein Skript aus dem Netz tut, lädt die Dateien einzeln. So lief es im Test:

# Verzeichnis anlegen und in das Verzeichnis wechseln
mkdir -p /opt/rallly
cd /opt/rallly

# Compose-Datei, Override fuer externen Proxy und Vorlage der Konfiguration holen
curl -sO https://raw.githubusercontent.com/lukevella/rallly-selfhosted/main/docker-compose.yml
curl -sO https://raw.githubusercontent.com/lukevella/rallly-selfhosted/main/docker-compose.external-proxy.yml
curl -sO https://raw.githubusercontent.com/lukevella/rallly-selfhosted/main/.env.example

# Konfigurationsdatei fuer den Objektspeicher Garage
mkdir -p config
curl -s -o config/garage.toml https://raw.githubusercontent.com/lukevella/rallly-selfhosted/main/config/garage.toml

# Verwaltungsskript holen und ausfuehrbar machen
curl -sO https://raw.githubusercontent.com/lukevella/rallly-selfhosted/main/rallly.sh
chmod +x rallly.sh

Traefik, PostgreSQL und Garage sind über Compose-Profile geschaltet und entfallen, sobald Sie externe Endpunkte eintragen. Nur Traefik belegt Ports auf dem Host.

Verifizieren: ls -la /opt/rallly zeigt docker-compose.yml, docker-compose.external-proxy.yml, .env.example, config/garage.toml und das ausführbare rallly.sh.

Schritt 2: .env konfigurieren

Kopieren Sie .env.example nach .env und tragen Sie Ihre Werte ein.

# /opt/rallly/.env
# Domain, unter der die Instanz erreichbar ist, ohne Schema und ohne Schraegstrich
DOMAIN=rallly.example.com

# Adresse fuer Ablaufwarnungen von Let's Encrypt
ACME_EMAIL=it@example.com

# Sitzungsschluessel, mindestens 32 Zeichen, PLATZHALTER
SECRET_PASSWORD=

# Kontaktadresse, die Nutzern angezeigt wird
SUPPORT_EMAIL=it@example.com

# Absenderadresse fuer Systemmails, faellt sonst auf SUPPORT_EMAIL zurueck
NOREPLY_EMAIL=no-reply@example.com

# Erster Benutzer mit dieser Adresse darf sich unter /control-panel Adminrechte holen
INITIAL_ADMIN_EMAIL=it@example.com

# SMTP, ohne funktionierenden Mailversand ist die Anmeldung nicht moeglich
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_SECURE=false
SMTP_USER=
SMTP_PWD=

# Registrierung auf die eigene Domain begrenzen
ALLOWED_EMAILS=*@example.com

# Automatisch erzeugte Geheimnisse, PLATZHALTER
POSTGRES_PASSWORD=
S3_ACCESS_KEY_ID=
S3_SECRET_ACCESS_KEY=
GARAGE_RPC_SECRET=

# PostgreSQL-Hauptversion, bei Neuinstallation 18
POSTGRES_VERSION=18
POSTGRES_DATA_MOUNT=/var/lib/postgresql
POSTGRES_VOLUME=db-data

Die Geheimnisse erzeugen Sie mit OpenSSL:

# Sitzungsschluessel, mindestens 32 Zeichen
openssl rand -base64 32

# Datenbankpasswort
openssl rand -hex 16

# S3-Zugangsschluessel und S3-Geheimnis
openssl rand -hex 16
openssl rand -hex 32

# RPC-Geheimnis fuer den Objektspeicher
openssl rand -hex 32

# Anschliessend die Rechte der Konfigurationsdatei einschraenken
chmod 600 /opt/rallly/.env
VariablePflichtBedeutung
DOMAINjaDomain ohne Schema, steuert Zertifikatsanforderung und Routing im gebündelten Traefik.
SECRET_PASSWORDjaSchlüssel zur Verschlüsselung der Sitzungen, mindestens 32 Zeichen. Eine Änderung macht alle Sitzungen ungültig.
SMTP_HOSTjaMailserver für Anmeldecodes und Benachrichtigungen.
NEXT_PUBLIC_BASE_URLbedingtVollständige öffentliche URL inklusive Schema. Wird aus DOMAIN abgeleitet, muss beim Betrieb des Images ohne das Verwaltungsskript selbst gesetzt werden.

Begrenzen Sie mit ALLOWED_EMAILS die Anmeldung auf Ihre Domain, wenn die Instanz nur intern dient.

Verifizieren: grep -cE '^[A-Z_]+=$' /opt/rallly/.env zählt nur noch bewusst leere Werte (im Test 2: SMTP-Zugangsdaten ohne Authentifizierung), das Muster '=$' allein zählt den Base64-Sitzungsschlüssel mit. ls -l /opt/rallly/.env zeigt -rw-------.

Schritt 3: Stack starten

Das Verwaltungsskript setzt die passenden Compose-Profile selbst:

# In das Stack-Verzeichnis wechseln
cd /opt/rallly

# Alle Dienste starten
./rallly.sh start

# Status der Dienste anzeigen
./rallly.sh status

# Log der Anwendung verfolgen
./rallly.sh logs web

Beim ersten Start lädt Docker die Images, PostgreSQL initialisiert den Datenbereich, und die Anwendung führt ihre Datenbankmigrationen aus. Im Test (Images vorab geladen) antwortete die Startseite nach 18 Sekunden. Das Log von 4.16.1 endete mit diesen Zeilen:

▲ Next.js 16.4.2
- Local:         http://localhost:3000
- Network:       http://0.0.0.0:3000
✓ Ready in 0ms
✓ Running next.config took 1.0ms

Die Meldung Error: P1001: Can't reach database server at `db:5432` direkt nach dem ersten Start ist unkritisch, die Anwendung startet neu, bis PostgreSQL bereit ist.

Danach standen 166 abgeschlossene Migrationen in der Tabelle _prisma_migrations. Prüfen Sie Zustand, HTTP-Antwort und Migrationen:

# Zustand aller Dienste
docker compose ps

# Antwort der Startseite, erwartet wird 200
curl -s -o /dev/null -w "HTTP %{http_code}\n" http://127.0.0.1:3000/

# Zahl der abgeschlossenen Migrationen in der Datenbank
docker compose exec -T db psql -U postgres -d rallly -tAc \
  "select count(*) from _prisma_migrations where finished_at is not null;"

Verifizieren: docker compose ps zeigt db, garage und web als healthy, curl auf die Startseite liefert HTTP 200, die Migrationsabfrage gibt 166 oder mehr aus.

Schritt 4: Mailversand prüfen und Adminkonto übernehmen

Rallly kennt keinen Standardadministrator. Die Anmeldung läuft über einen Code per E-Mail, deshalb steht der Mailversand vor allem anderen. Die Verbindung zum Mailserver lässt sich aus dem Anwendungscontainer prüfen, ohne eine Mail zu schicken. Im Test war das ein Mailpit-Container auf Port 1025, der mit seiner Begrüßungszeile antwortete:

SMTP banner: 220 f5c22d32314a Mailpit ESMTP Service ready

Den Admin übernehmen Sie laut Dokumentation so:

  1. Instanz im Browser aufrufen und mit genau der Adresse aus INITIAL_ADMIN_EMAIL anmelden.
  2. Den per E-Mail zugestellten Code eingeben und das Konto anlegen.
  3. /control-panel aufrufen. Ohne Adminrechte leitet Rallly auf /admin-setup um, dort beanspruchen Sie die Rolle mit „Mich zum Admin machen“.
  4. In den Instanzeinstellungen entscheiden, ob weitere Registrierungen erlaubt bleiben. Sobald alle Konten bestehen, schaltet REGISTRATION_ENABLED=false die Registrierung ab.
Rallly-Anmeldeseite mit sechs Feldern für den per E-Mail zugestellten Bestätigungscode
Anmeldung: Rallly schickt einen sechsstelligen Code an die eingegebene Adresse.
Rallly-Dialog zur Admin-Übernahme mit der Schaltfläche Mich zum Admin machen
Unter /admin-setup übernimmt das Konto aus INITIAL_ADMIN_EMAIL die Adminrolle.
Rallly-Verwaltung mit Benutzer 1/1, Status ohne Lizenz und Version v4.15.4 auf dem neuesten Stand
Verwaltung nach der Übernahme: ein Benutzer, ohne Lizenz, Version 4.15.4.

Verifizieren: Der Anmeldecode erreicht das Postfach (nicht den Spamordner), und /control-panel zeigt die Verwaltung mit Benutzern, Lizenz und Version.

Schritt 5: Hinter einem vorhandenen Reverse Proxy betreiben

Auf einem eigenen Server genügt der gebündelte Traefik: DOMAIN und ACME_EMAIL setzen, A-Record auf den Server, Ports 80 und 443 frei. Läuft dort schon ein Reverse Proxy, schalten Sie Traefik ab und binden die Anwendung nur an die Loopback-Adresse. Diese Betriebsart lief im Test, mit Port 18300 statt 3000:

# Ergaenzung in /opt/rallly/.env
PROXY_MODE=external
WEB_PORT=127.0.0.1:3000

Ein passender Server-Block für Nginx:

server {
    listen 443 ssl http2;
    server_name rallly.example.com;

    ssl_certificate     /etc/letsencrypt/live/rallly.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/rallly.example.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Host              $host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Upgrade           $http_upgrade;
        proxy_set_header Connection        "upgrade";
    }
}

server {
    listen 80;
    server_name rallly.example.com;
    return 301 https://$host$request_uri;
}

Seit 4.16.0 begrenzt Rallly laut Release Notes die Antworten auf 200 je Umfrage und Stunde und erwartet die Besucheradresse in X-Real-IP. Andere Proxys müssen diesen Header setzen, sonst RATE_LIMIT_ENABLED=false.

Rallly erzeugt Einladungslinks und Weiterleitungen aus der Basis-URL. Das Verwaltungsskript leitet sie aus DOMAIN ab (https:// plus Domain). Wer das Image ohne Skript betreibt, setzt NEXT_PUBLIC_BASE_URL selbst, mit Schema und ohne Schrägstrich am Ende. Im Test enthielten die ausgelieferten Logo-Pfade nach dem Setzen genau diese Adresse.

Verifizieren: ss -tlnp | grep 3000 zeigt nur 127.0.0.1:3000, curl -I https://rallly.example.com/ liefert HTTP 200, und ein Einladungslink beginnt mit Ihrer öffentlichen Adresse.

Schritt 6: Backup und Wiederherstellung

Das Verwaltungsskript sichert die Datenbank komprimiert mit Zeitstempel nach ./backups/:

# Sicherung ueber das Verwaltungsskript
cd /opt/rallly
./rallly.sh backup

Für eine bestehende Backup-Kette rufen Sie pg_dump direkt auf. Im Test entstand so eine 26 KB große Datei für eine Instanz mit einem Konto:

# Datenbank sichern, komprimiert und mit Zeitstempel im Dateinamen
cd /opt/rallly
mkdir -p backups
docker compose exec -T db pg_dump -U postgres -Fp rallly \
  | gzip > backups/rallly_$(date +%Y%m%d_%H%M%S).sql.gz

# Ergebnis pruefen
ls -lh backups/

Die Sicherung umfasst nur die Datenbank. Hochgeladene Dateien im Garage-Volume sichern Sie separat, ebenso die .env, denn ohne den alten SECRET_PASSWORD sind nach einer Wiederherstellung alle Nutzer abgemeldet. Die Wiederherstellung lief im Test vollständig: Eine Markierungstabelle wurde nach der Sicherung gelöscht und war nach dem Einspielen wieder da, mit 166 Migrationen, gültiger alter Anmeldung und HTTP 200.

# Anwendung stoppen, damit sie die Verbindungen zur Datenbank freigibt
docker compose stop web

# Datenbank verwerfen und leer neu anlegen, dafuer mit der Datenbank postgres verbinden
docker compose exec -T db psql -U postgres -d postgres -c "DROP DATABASE IF EXISTS rallly;"
docker compose exec -T db psql -U postgres -d postgres -c "CREATE DATABASE rallly;"

# Sicherung einspielen, ON_ERROR_STOP bricht beim ersten Fehler ab
gunzip < backups/rallly_20260916_100401.sql.gz \
  | docker compose exec -T db psql -v ON_ERROR_STOP=1 -U postgres rallly

# Anwendung wieder starten
docker compose start web

Verifizieren: ls -lh backups/ zeigt eine aktuelle Datei mit plausibler Größe, und nach einer Probe-Wiederherstellung auf einer Testinstanz sind Ihre Umfragen vollständig sichtbar.

Schritt 7: Rallly aktualisieren

Der Stack folgt dem Tag lukevella/rallly:4 und bleibt damit in der Hauptversion 4. Wer Updates planbar halten will, legt über RALLLY_IMAGE in der .env eine konkrete Version fest, etwa lukevella/rallly:4.16.1, und ändert sie bewusst. Vor jedem Update gehört eine Sicherung an einen anderen Ort:

# Vor jedem Update: Sicherung erstellen und wegkopieren
cd /opt/rallly
./rallly.sh backup

# Update durchfuehren
./rallly.sh update

# Danach Zustand und Log kontrollieren
./rallly.sh status
./rallly.sh logs web

Die neuen Migrationen laufen beim Start und lassen sich nicht rückwärts ausführen. Ein Rollback heißt deshalb: älteres Image über RALLLY_IMAGE festlegen und die Sicherung von vor dem Update einspielen. Vor einem Wechsel der Hauptversion lesen Sie die Migrationsanleitung des Projekts.

Im Test spielte das Update von 4.15.4 auf 4.16.1 beim Start 13 neue Migrationen ein (153 auf 166), Daten und Anmeldung blieben erhalten. Version 4.15.4 und älter sind laut den Release Notes zu 4.15.5 von der Lücke GHSA-p3m5-59mp-jv5r betroffen.

Verifizieren: ./rallly.sh status zeigt alle Dienste als healthy, curl -s http://127.0.0.1:3000/api/status meldet die neue Version, und die Startseite liefert HTTP 200.

Typische Fehler

SymptomUrsacheAbhilfe
Warnung „The "ACME_EMAIL" variable is not set“ bei jedem Compose-BefehlIm Test aufgetreten: Bei PROXY_MODE=external wird Traefik nicht gestartet, die Variable bleibt leer, Compose wertet sie trotzdem aus.Unkritisch. Wer die Meldung loswerden will, trägt ACME_EMAIL= mit leerem Wert in die Datei .env ein.
Container web steht dauerhaft auf „health: starting“Im Test beobachtet: Nach einem Neustart vergingen 31 bis 53 Sekunden bis healthy.Abwarten und danach docker compose ps erneut aufrufen. Antwortet die Startseite mit HTTP 200, läuft der Dienst.
Wiederherstellung schlägt fehl, Datenbank lässt sich nicht verwerfenIm Test reproduziert: Die Anwendung hält offene Verbindungen zur Datenbank.Vor dem Verwerfen docker compose stop web ausführen, danach neu starten.
Kein Zertifikat wird ausgestelltLaut Dokumentation: DNS zeigt nicht auf den Server oder Port 80 und 443 sind blockiert.A-Record prüfen, Firewall öffnen, ./rallly.sh logs traefik auf ACME-Fehler durchsehen.
Port 80 oder 443 bereits belegtLaut Dokumentation: Ein anderer Dienst hört bereits auf diesen Ports.Entweder den anderen Dienst abschalten oder PROXY_MODE=external setzen und den vorhandenen Proxy verwenden.
Startseite liefert HTTP 500, Log meldet „Invalid environment variables“Im Test reproduziert: SECRET_PASSWORD kürzer als 32 Zeichen. Der Container lief ohne Neustart weiter.Werte prüfen, insbesondere Mindestlänge von 32 Zeichen bei SECRET_PASSWORD, danach ./rallly.sh restart.
Anmeldecodes kommen nicht anLaut Dokumentation: Falsche Kombination aus Port und TLS-Einstellung oder schlechte Zustellbarkeit des Absenders.Für Port 587 SMTP_SECURE=false, für Port 465 true setzen. Verbindung mit openssl s_client -starttls smtp -connect host:587 prüfen, SPF und DKIM der Absenderdomain kontrollieren. Seit 4.16.0 stehen Sendefehler mit der Antwort des Mailservers im Log, SMTP_DEBUG entfällt.
Einladungslinks zeigen auf die falsche AdresseLaut Dokumentation: Basis-URL falsch oder mit Schrägstrich am Ende gesetzt.DOMAIN ohne Schema und ohne Schrägstrich eintragen, beim Betrieb ohne Verwaltungsskript NEXT_PUBLIC_BASE_URL vollständig setzen.

Häufige Fragen

Brauchen Teilnehmer ein Konto?

Nein. Teilnehmer stimmen über den Einladungslink ab, nur der Organisator meldet sich an. Teilnehmer zählen deshalb auch nicht als Benutzer im Sinne der Lizenz.

Ersetzt Rallly ein Buchungssystem wie Cal.com?

Nein. Rallly stimmt einen Termin in einer Gruppe ab. Freie Slots im Kalender einer Person buchen Kunden mit Werkzeugen wie Cal.com.

Unterstützt Rallly Single Sign-on?

Laut offizieller Dokumentation ja, über OpenID Connect, Google und Microsoft, zusätzlich zum Anmeldecode per E-Mail. Seit 4.16.0 lehnt Rallly neue Microsoft-Anmeldungen über Multi-Tenant-Endpunkte ab, wenn die App-Registrierung keine verifizierten E-Mail-Claims sendet.

Wie entferne ich Rallly vollständig?

docker compose down entfernt nur Container und Netz, die Daten bleiben. Ohne die Compose-Profile, die sonst rallly.sh setzt, erfasst ein direkt aufgerufenes docker compose down -v nur den Dienst web: Im Test liefen PostgreSQL und Garage danach weiter, alle Volumes blieben stehen. Nennen Sie die Profile deshalb ausdrücklich. Achtung: docker compose down -v löscht Datenbank und hochgeladene Dateien unwiderruflich. Erstellen Sie vorher eine Sicherung an einem anderen Ort:

# Letzte Sicherung erstellen und an einen anderen Ort kopieren
cd /opt/rallly
./rallly.sh backup

# Erst danach: Stack samt Volumes entfernen, Daten sind dann weg
COMPOSE_PROFILES=bundled-db,bundled-storage,bundled-proxy docker compose down -v

# Verbliebene Volumes kontrollieren
docker volume ls

# Stack-Verzeichnis entfernen, enthaelt auch die Datei .env mit den Geheimnissen
rm -rf /opt/rallly

Fazit

Rallly erledigt eine eng umrissene Aufgabe mit überschaubarem Aufwand: vier Container, PostgreSQL, Sicherung und Wiederherstellung nach bekanntem Muster. Teilnehmerdaten bleiben in der eigenen Infrastruktur. Vor der Freigabe klären Sie Mailzustellung, Wiederherstellung und Lizenz.

Weiterführende Anleitungen und Quellen

ralllydockerdocker-composeterminabstimmungselfhostingpostgresqldatenschutz