OpenSlides ist für digitale Versammlungen, Abstimmungen und strukturierte Entscheidungsprozesse eine kraftvolle Plattform. Viele Organisationen nutzen externe Hosting-Angebote, doch für meine Arbeitsweise war klar: Die Installation läuft auf meinem eigenen Server, vollständig unter meiner Kontrolle, mit einer klaren und transparenten Dokumentation.
Im Folgenden beschreibe ich Schritt für Schritt, wie ich OpenSlides 4 auf meinem Home-Server cube eingerichtet habe. Der Server läuft mit Ubuntu, Docker und docker-compose und ist über die Domain openslides.terruhn.it erreichbar. Der gesamte Stack ist sauber getrennt, wartbar und schnell aktualisierbar.
Ziel und Architektur
Die Installation folgt einem übersichtlichen Konzept:
- Hostsystem: Ubuntu-Server („cube“)
- Orchestrierung:
docker-compose - Dienste: vollständiger OpenSlides-Stack aus Proxy, Client, Backend-Diensten, Datenbank und Redis
- Zugriff von außen über HTTPS
- automatische Let’s Encrypt-Zertifikate via Auto-HTTPS
- klare Trennung der Bereiche für Konfiguration, Secrets und Daten
Damit entsteht eine robuste Grundlage für Veranstaltungen jeder Größenordnung.
Vorbereitung auf dem Server
System aktualisieren
sudo apt update
sudo apt upgrade
Docker und docker-compose bereitstellen
sudo apt install docker.io docker-compose
sudo systemctl enable docker
sudo systemctl start docker
Erster Projektstart in /opt: Git-Clone und INSTALL.md
Die Installation begann nicht sofort in /srv, sondern früher in /opt. Dort liegt heute der ursprüngliche Projektstand, mit dem der gesamte Prozess begonnen hat:
/opt/OpenSlides
/opt/openslides-venv
/opt/containerd
Der Einstieg sah so aus:
cd /opt
sudo git clone https://github.com/OpenSlides/OpenSlides.git
Damit entstand das Verzeichnis:
/opt/OpenSlides
Innerhalb des Repositories lag auch die Datei:
/opt/OpenSlides/INSTALL.md
Diese Datei enthält die ersten Hinweise zum Aufbau der OpenSlides-Architektur, zu den Komponenten und zu den Deploy-Skripten. Auf Basis dieser Anleitung ging es weiter.
Die produktiven Konfigurationsdateien befinden sich im Repository unter:
/opt/OpenSlides/deploy/docker-compose/
Dort liegen unter anderem:
docker-compose.ymlconfig.yml- Vorlagen für Secrets
- Hinweise zur Struktur der Container
Für den produktiven Betrieb habe ich anschließend ein sauberes Projektverzeichnis unter /srv/openslides angelegt und die relevanten Dateien dorthin übernommen:
sudo mkdir /srv/openslides
sudo cp /opt/OpenSlides/deploy/docker-compose/* /srv/openslides/
Dort entstanden dann die finalen Strukturen, die mit docker-compose laufen und alle Dienste bereitstellen.
Verzeichnisstruktur der Installation
OpenSlides liegt auf meinem Server im Verzeichnis /srv/openslides. Dort befinden sich alle Dateien und Ordner, die der Stack benötigt.
Vollständiger Inhalt des Ordners
rene@cube:/srv/openslides$ ls -la
total 14920
drwxr-xr-x 4 root root 4096 Nov 30 06:02 .
drwxr-xr-x 4 root root 4096 Nov 30 08:12 ..
-rw-r--r-- 1 root root 663 Nov 20 04:06 config.yml
drwxr-xr-x 3 root root 4096 Nov 15 10:02 db-data
-rw-r--r-- 1 root root 7162 Nov 30 06:02 docker-compose.yml
-rw------- 1 root root 52 Nov 19 19:21 .env
-rwxr-xr-x 1 root root 15242264 Dez 13 2022 openslides
drwxr-x--- 2 root root 4096 Nov 15 10:01 secrets
Diese Struktur ist klar getrennt:
- config.yml – zentrale Laufzeit-Konfiguration
- docker-compose.yml – vollständiger Container-Stack
- .env – sensible Variablen
- db-data/ – persistente Postgres-Daten
- secrets/ – Schlüsselmaterial und Passwörter
- openslides – ausführbare Helper-Komponente
config.yml – zentrale OpenSlides-Konfiguration
Die Datei config.yml steuert die wichtigsten Eigenschaften der Installation. Sie wird vom Proxy und verschiedenen Backend-Diensten genutzt. Entscheidend sind Auto-HTTPS, Domain-Einstellungen und Mail-Konfiguration.
Die config.yml komplett:
comfig.yml
---
host: "0.0.0.0"
port: 443
# Wichtig: Lokales HTTPS deaktivieren
enableLocalHTTPS: false
# Auto-HTTPS aktivieren
enableAutoHTTPS: true
services:
proxy:
environment:
EXTERNAL_ADDRESS: openslides.terruhn.it
# Für Tests kannst Du das Staging von Let's Encrypt verwenden:
# ACME_ENDPOINT: https://acme-staging-v02.api.letsencrypt.org/directory
backendAction:
environment:
EMAIL_HOST: mail.example.com
EMAIL_PORT: 465
EMAIL_HOST_USER: USERNAME
EMAIL_HOST_PASSWORD: ${OPENSLIDES_EMAIL_HOST_PASSWORD}
EMAIL_USE_TLS: false
EMAIL_USE_SSL: true
DEFAULT_FROM_EMAIL: openslides@terruhn.it
Wesentliche Punkte:
- Auto-HTTPS ist aktiv
- Lokales HTTPS bleibt ausgeschaltet
- Externe Adresse:
openslides.terruhn.it - Mailserver ist eingebunden
- Passwörter werden nicht im Klartext in dieser Datei gespeichert
Die Datei ist damit leicht nachvollziehbar und gut wartbar.
docker-compose.yml – der komplette OpenSlides-Stack
Die Datei docker-compose.yml bildet den gesamten Multi-Service-Stack ab. OpenSlides 4 bringt viele einzelne Dienste mit, die als Container zusammenarbeiten:
- Proxy (mit Auto-HTTPS)
- Client (Frontend)
- Backend Action
- Backend Presenter
- Backend Manage
- Auth
- Autoupdate
- Media
- Vote
- Redis
- PostgreSQL
- Datastore Reader und Writer
Die docker-compose.yml komplett:
docker-compose.yml
---
version: "3.4"
x-default-environment: &default-environment
ACTION_HOST: backendAction
ACTION_PORT: "9002"
AUTH_HOST: auth
AUTH_PORT: "9004"
AUTOUPDATE_HOST: autoupdate
AUTOUPDATE_PORT: "9012"
CACHE_HOST: redis
CACHE_PORT: "6379"
DATASTORE_DATABASE_HOST: postgres
DATASTORE_DATABASE_NAME: openslides
DATASTORE_DATABASE_PASSWORD_FILE: /run/secrets/postgres_password
DATASTORE_DATABASE_PORT: "5432"
DATASTORE_DATABASE_USER: openslides
DATASTORE_READER_HOST: datastoreReader
DATASTORE_READER_PORT: "9010"
DATASTORE_WRITER_HOST: datastoreWriter
DATASTORE_WRITER_PORT: "9011"
ICC_HOST: icc
ICC_PORT: "9007"
ICC_REDIS_HOST: redis
ICC_REDIS_PORT: "6379"
INTERNAL_AUTH_PASSWORD_FILE: /run/secrets/internal_auth_password
MANAGE_ACTION_HOST: backendManage
MANAGE_AUTH_PASSWORD_FILE: /run/secrets/manage_auth_password
MANAGE_HOST: manage
MANAGE_PORT: "9008"
MEDIA_BLOCK_SIZE: "4096"
MEDIA_DATABASE_HOST: postgres
MEDIA_DATABASE_NAME: openslides
MEDIA_DATABASE_PASSWORD_FILE: /run/secrets/postgres_password
MEDIA_DATABASE_PORT: "5432"
MEDIA_DATABASE_USER: openslides
MEDIA_HOST: media
MEDIA_PORT: "9006"
MEDIA_PRESENTER_HOST: backendPresenter
MEDIA_PRESENTER_PORT: "9003"
MESSAGE_BUS_HOST: redis
MESSAGE_BUS_PORT: "6379"
OPENSLIDES_DEVELOPMENT: "false"
OPENSLIDES_LOGLEVEL: info
PRESENTER_HOST: backendPresenter
PRESENTER_PORT: "9003"
SYSTEM_URL: localhost:8000
VOTE_DATABASE_HOST: postgres
VOTE_DATABASE_NAME: openslides
VOTE_DATABASE_PASSWORD_FILE: /run/secrets/postgres_password
VOTE_DATABASE_PORT: "5432"
VOTE_DATABASE_USER: openslides
VOTE_HOST: vote
VOTE_PORT: "9013"
VOTE_REDIS_HOST: redis
VOTE_REDIS_PORT: "6379"
services:
proxy:
image: ghcr.io/openslides/openslides/openslides-proxy:4.0.0
depends_on:
- client
- backendAction
- backendPresenter
- autoupdate
- auth
- media
- icc
- vote
environment:
<< : *default-environment
EXTERNAL_ADDRESS: openslides.terruhn.it
ENABLE_AUTO_HTTPS: 1
networks:
- uplink
- frontend
ports:
- 80:8001
- 443:8000
client:
image: ghcr.io/openslides/openslides/openslides-client:4.0.0
depends_on:
- backendAction
- backendPresenter
- autoupdate
- auth
- media
- icc
- vote
environment:
<< : *default-environment
networks:
- frontend
backendAction:
image: ghcr.io/openslides/openslides/openslides-backend:4.0.0
depends_on:
- datastoreWriter
- auth
- media
- vote
- postgres
environment:
<< : *default-environment
DEFAULT_FROM_EMAIL: openslides@terruhn.it
EMAIL_HOST: w014178e.kasserver.com
EMAIL_HOST_PASSWORD: ${OPENSLIDES_EMAIL_HOST_PASSWORD}
EMAIL_HOST_USER: m071b58a
EMAIL_PORT: "465"
EMAIL_USE_SSL: "true"
EMAIL_USE_TLS: "false"
OPENSLIDES_BACKEND_COMPONENT: action
networks:
- frontend
- data
secrets:
- auth_token_key
- auth_cookie_key
- postgres_password
backendPresenter:
image: ghcr.io/openslides/openslides/openslides-backend:4.0.0
depends_on:
- auth
- postgres
environment:
<< : *default-environment
OPENSLIDES_BACKEND_COMPONENT: presenter
networks:
- frontend
- data
secrets:
- auth_token_key
- auth_cookie_key
- postgres_password
backendManage:
image: ghcr.io/openslides/openslides/openslides-backend:4.0.0
depends_on:
- datastoreWriter
- postgres
environment:
<< : *default-environment
OPENSLIDES_BACKEND_COMPONENT: action
networks:
- data
secrets:
- auth_token_key
- auth_cookie_key
- internal_auth_password
- postgres_password
datastoreReader:
image: ghcr.io/openslides/openslides/openslides-datastore-reader:4.0.0
depends_on:
- postgres
environment:
<< : *default-environment
NUM_WORKERS: "8"
networks:
- data
secrets:
- postgres_password
datastoreWriter:
image: ghcr.io/openslides/openslides/openslides-datastore-writer:4.0.0
depends_on:
- postgres
- redis
environment:
<< : *default-environment
networks:
- data
secrets:
- postgres_password
postgres:
image: postgres:11
environment:
<< : *default-environment
POSTGRES_DB: openslides
POSTGRES_USER: openslides
POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password
PGDATA: /var/lib/postgresql/data/pgdata
networks:
- data
user: 0:0
secrets:
- postgres_password
volumes:
- ./db-data:/var/lib/postgresql/data
autoupdate:
image: ghcr.io/openslides/openslides/openslides-autoupdate:4.0.0
depends_on:
- datastoreReader
- redis
environment:
<< : *default-environment
networks:
- frontend
- data
secrets:
- auth_token_key
- auth_cookie_key
- postgres_password
auth:
image: ghcr.io/openslides/openslides/openslides-auth:4.0.0
depends_on:
- datastoreReader
- redis
environment:
<< : *default-environment
networks:
- frontend
- data
secrets:
- auth_token_key
- auth_cookie_key
vote:
image: ghcr.io/openslides/openslides/openslides-vote:4.0.0
depends_on:
- datastoreReader
- auth
- autoupdate
- redis
environment:
<< : *default-environment
networks:
- frontend
- data
secrets:
- auth_token_key
- auth_cookie_key
- postgres_password
redis:
image: redis:latest
command: redis-server --save ""
environment:
<< : *default-environment
networks:
- data
media:
image: ghcr.io/openslides/openslides/openslides-media:4.0.0
depends_on:
- postgres
environment:
<< : *default-environment
networks:
- frontend
- data
secrets:
- postgres_password
icc:
image: ghcr.io/openslides/openslides/openslides-icc:4.0.0
depends_on:
- datastoreReader
- postgres
- redis
environment:
<< : *default-environment
networks:
- frontend
- data
secrets:
- auth_token_key
- auth_cookie_key
- postgres_password
manage:
image: ghcr.io/openslides/openslides/openslides-manage:4.0.0
depends_on:
- datastoreReader
- backendManage
environment:
<< : *default-environment
networks:
- frontend
- data
secrets:
- superadmin
- manage_auth_password
- internal_auth_password
networks:
uplink:
frontend:
internal: true
data:
internal: true
secrets:
auth_token_key:
file: ./secrets/auth_token_key
auth_cookie_key:
file: ./secrets/auth_cookie_key
superadmin:
file: ./secrets/superadmin
manage_auth_password:
file: ./secrets/manage_auth_password
internal_auth_password:
file: ./secrets/internal_auth_password
postgres_password:
file: ./secrets/postgres_password
Der Proxy veröffentlicht Port 80 und Port 443. Alle anderen Dienste bleiben im internen Netzwerk geschützt sichtbar. Zertifikate holt der Proxy automatisch, sobald die Domain korrekt gesetzt ist.
Die Datei ist vollständig mit Secrets verknüpft, sodass keine sensiblen Zugangsdaten im Klartext stehen.
.env – sensible Variablen
Die .env-Datei enthält vertrauliche Werte wie Mailpasswörter oder spezielle Tokens. Sie wird beim Start automatisch eingelesen und bleibt lokal geschützt. Die Rechte sind bewusst streng gesetzt:
-rw------- 1 root root 52 .env
Diese Datei gehört in kein Repository und in keine Backups außerhalb des Servers.
db-data – persistente Datenbank
Der Ordner db-data/ enthält alle Daten der PostgreSQL-Datenbank:
- Benutzerkonten
- Anträge
- Tagesordnungspunkte
- Dateien (in DB-basierten Media-Konfigurationen)
- Abstimmungsergebnisse
Dieser Ordner ist entscheidend für Backups und für die langfristige Stabilität der Installation.
secrets – Schlüsselmaterial und interne Passwörter
Im Ordner secrets/ liegen alle sicherheitsrelevanten Dateien, zum Beispiel:
- Token- und Cookie-Schlüssel
- interne Passwortdateien
- Superadmin-Zugang
- Postgres-Passwortdatei
Die Rechte sind restriktiv:
drwxr-x--- 2 root root 4096 secrets
Nur Root und der Docker-Dienst greifen darauf zu. Die Verknüpfung erfolgt über docker secrets.
Start der Installation
Der Start der gesamten Installation funktioniert mit zwei Befehlen:
cd /srv/openslides
sudo docker-compose pull
sudo docker-compose up -d
Der Stack fährt hoch, der Proxy besorgt Zertifikate, der Client wird geladen, und die Dienste verbinden sich automatisch miteinander.
Status prüfen:
sudo docker-compose ps
Domain und Erreichbarkeit
Die Domain openslides.terruhn.it zeigt direkt auf den Anschluss. Die FritzBox leitet das HTTPS-Port weiter:
- 443 extern → 443 intern
Port 80 wird ebenfalls durch den Proxy bedient, sodass Weiterleitungen und Zertifikatsanforderungen zuverlässig funktionieren.
Wartung, Updates und Logs
Logs ansehen
sudo docker-compose logs -f
Stack aktualisieren
sudo docker-compose pull
sudo docker-compose up -d
Updates laufen durch die Trennung von Konfiguration, Secrets und Daten reibungslos durch.
Performance-Prognose und mögliche Engpässe
Die Leistungsfähigkeit der Installation ergibt sich aus mehreren Faktoren. OpenSlides erzeugt auf dem Cube selbst nur moderate Last, da die Dienste überwiegend leichtgewichtige JSON-Daten austauschen. Die Berechnung erfolgt größtenteils im Browser der Teilnehmenden, während der Server vor allem kurze strukturierte Anfragen beantwortet. PostgreSQL verarbeitet gut indexierte Datensätze, und Redis liefert viele Antworten direkt aus dem Speicher. Dadurch bleibt der Ressourcenbedarf im Cube begrenzt.
Auf dieser Grundlage ergibt sich eine vorsichtige Einschätzung:
- bis ca. 200 Teilnehmende
Der Betrieb läuft voraussichtlich stabil. Die JSON-Updates werden zuverlässig verteilt und die Container behalten Reserven für typische Vorgänge wie Abstimmungen und Anträge. - bis ca. 400 Teilnehmende
Die Installation bleibt wahrscheinlich nutzbar, reagiert allerdings empfindlicher auf gleichzeitige Aktionen großer Gruppen. Für diesen Bereich empfiehlt sich später ein gezielter Lasttest.
Viele potenzielle Engpässe entstehen nicht im Server, sondern in der Umgebung der Teilnehmenden:
- Endgeräte
Browser-basierte Anwendungen verteilen einen großen Teil der Last auf die Geräte der Nutzenden. Schwächere oder ausgelastete Hardware kann die Darstellung der JSON-Daten verzögern. - WLAN-Infrastruktur vor Ort
In Räumen mit vielen verbundenen Geräten begrenzt das lokale WLAN die Geschwindigkeit stärker als der Server. Live-Updates können dadurch langsamer ankommen. - Upload-Bandbreite des Anschlusses
Die parallele Übertragung an alle Teilnehmenden nutzt dieselbe Upload-Strecke. JSON-Pakete sind klein, doch die Summe aller Updates bleibt ein relevanter Faktor. - Spitzenlasten
Gleichzeitiges Öffnen großer Tagesordnungspunkte oder das Starten einer Abstimmung erzeugen kurzfristig höhere Last, vor allem im Presenter- und Datenbankdienst.
Ein weiterer Punkt betrifft die Zukunftstauglichkeit:
Der Cube ist technisch solide, jedoch im Home-Setup nur begrenzt erweiterbar. Mehr CPU-Kerne, schnellere Storage-Systeme oder höhere garantierte Upload-Bandbreite lassen sich dort nur schwer umsetzen. Sollte eine Versammlung dauerhaft jenseits der genannten Größen stattfinden oder eine höhere Ausfallsicherheit benötigt werden, führt der Weg langfristig zu einem Hosted-Server oder einer dedizierten Cloud-Instanz. Dort lässt sich die Leistung flexibel skalieren, ohne dass sich die Architektur der Installation ändern müsste.
Technisches Fazit
Mit dieser Struktur läuft OpenSlides auf meinem Server klar getrennt, zuverlässig und gut nachvollziehbar:
- Containerarchitektur mit sauberer Orchestrierung
- automatische Zertifikate durch Auto-HTTPS
- getrennte Bereiche für Konfiguration, Secrets und Daten
- transparente Ordnerstruktur
- einfacher Update-Prozess
Die Installation zeigt, wie ein komplexes System auf eigener Hardware stabil betrieben wird, bei voller Kontrolle über Sicherheit, Daten und Wartung.
Rechtliche Einordnung für den Betrieb meiner OpenSlides-4-Instanz
Für OpenSlides existiert ein rechtsverbindliches Gutachten der GOB Legal Rechtsanwaltsgesellschaft mbH vom 25.03.2021. Dieses Gutachten bestätigt, dass OpenSlides 3 – unter definierten technischen und organisatorischen Voraussetzungen – für geheime elektronische Abstimmungen und Wahlen geeignet ist.
Mit dem aktuellen Schreiben vom 3. Juni 2024 stellt die Intevation GmbH klar, dass dieses Gutachten unverändert auch für OpenSlides 4 gilt.
Damit gelten alle im Gutachten beschriebenen technischen Anforderungen, Sicherheitsmechanismen und Wahlverfahren ebenso für die Version 4, die ich auf meinem Server betreibe.
Gleichzeitig macht das Gutachten sehr deutlich, unter welchen übergeordneten Bedingungen der rechtskonforme Betrieb steht. Diese Punkte betreffen nicht die Software selbst, sondern die organisatorische und infrastrukturelle Umgebung. Für meine eigene Installation auf dem Cube ergibt sich daraus folgende Einschätzung.
Was meine OpenSlides-4-Instanz technisch erfüllt
Die folgenden Anforderungen erfüllt OpenSlides 4 bereits durch seine Architektur und durch meine konkrete Installation:
- TLS-gesicherte Kommunikation über Auto-HTTPS
- Trennung von Stimmberechtigung und Stimminhalt
- Anonymisierte Speicherung nicht-namentlicher Stimmen
- Verhinderung mehrfacher Stimmabgaben durch Transaktionen
- Tokenbasierte Stimmabgabe ohne Rückschluss auf die Person
- Keine Übermittlung einer „Quittung“ an Teilnehmende
- JSON-basierter Datenaustausch ohne Speicherung sensibler Metadaten im System
Diese Punkte entsprechen den Anforderungen des Gutachtens an das technische System und decken sich vollständig mit der Funktionsweise von OpenSlides 4.
Was meine Instanz nicht erfüllt und warum das rechtlich relevant ist
Das Gutachten basiert auf Hosting durch die Intevation GmbH, also durch einen externen, vertraglich gebundenen Dienstleister in zertifizierten Rechenzentren (ISO/IEC 27001).
Meine Installation weicht davon in mehreren Punkten ab:
1. Kein externer Betreiber
Ich betreibe die Instanz selbst, nicht als externer Dienstleister.
→ Das Gutachten setzt voraus, dass der Betreiber nicht Teil der abstimmenden Organisation ist und über eine qualifizierte Verschwiegenheitsklausel gebunden ist.
Diese Voraussetzung erfülle ich naturgemäß nicht.
2. Kein professionelles Rechenzentrum
Der Cube steht in einer privaten Infrastruktur, nicht in einem zertifizierten RZ.
→ Es fehlen die im Gutachten angenommenen Rahmenbedingungen wie
- Zutrittskontrolle
- Redundanz und Backup-RZ
- Notfallplanung
- dokumentierte IT-Prozesse
3. Keine formale Verpflichtung Dritter
Im Gutachten werden Administrator*innen arbeits- bzw. dienstvertraglich zur Verschwiegenheit verpflichtet.
→ Bei einem privaten Heimserver entfällt diese organisatorische Absicherung.
4. Satzungsrechtliche Grundlage
Ob eine Organisation geheime elektronische Wahlen zulässt, bestimmt ihre Satzung. Das gilt unabhängig von der verwendeten Technik.
→ Dies muss im Einzelfall geprüft werden, da es außerhalb des technischen Setups liegt.
Fazit für den Einsatz meiner Instanz
OpenSlides 4 erfüllt technisch alle Voraussetzungen, die das Gutachten beschreibt.
Meine Installation erfüllt jedoch nicht alle organisatorischen Randbedingungen, die das Gutachten als Voraussetzung für rechtsverbindliche geheime Wahlen nennt.
Das bedeutet:
- Für interne Arbeitsprozesse, informelle Abstimmungen und nicht-strittige Entscheidungen ist die Instanz gut geeignet.
- Für offiziell geheime Wahlen mit Anfechtungsrisiko wäre zusätzlich erforderlich:
- Hosting in einer professionellen Infrastruktur
- Betrieb durch einen externen, zur Verschwiegenheit verpflichteten Dienstleister
- dokumentierte Sicherheitsprozesse
- klare, satzungsgemäße Erlaubnis der Organisation
Damit ist transparent nachvollziehbar, wo OpenSlides 4 rechtlich abgesichert ist und wo eine private Installation – auch bei technisch korrektem Betrieb – nicht die vom Gutachten vorausgesetzten Rahmenbedingungen erfüllt.
Zuletzt aktualisiert am 9. Dezember 2025.
