Docmost, eine Open-Source-Software für Wikis und kollaborative Dokumentation. Entwickelt für eine nahtlose Zusammenarbeit in Echtzeit, können mehrere Benutzer gleichzeitig an derselben Seite arbeiten, ohne sich gegenseitig zu überschreiben.
Docmost ist eine Open Source Alternative zu Programmen wie Notion und Confluence. Ob du ein Wiki, eine Wissensdatenbank oder eine umfangreiche Projektdokumentation verwalten, Docmost bietet die Werkzeuge, um Wissen zu erstellen, zusammenzuarbeiten und zu teilen.
| Datum | Änderungen |
|---|---|
| 09.09.2024 | Erstellung dieser Anleitung |
| 10.05.2026 | Anpassung an aktuelle Version @christian. Danke an @retoineichen |
1. Grundvoraussetzung
- Docker & Docker Compose v2 (Debian / Ubuntu)
- Traefik ab v3.6 mit CrowdSec installieren und konfigurieren
2. Ordner anlegen
Zuerst legen wir uns passende Ordner-Strukturen an.
mkdir -p /opt/containers/docmost
3. Compose Datei anlegen
nano /opt/containers/docmost/docker-compose.yml
Inhalt
services:
docmost:
image: docmost/docmost:latest
depends_on:
- db
- redis
environment:
APP_URL: 'http://localhost:3000'
APP_SECRET: 'REPLACE_WITH_LONG_SECRET'
DATABASE_URL: 'postgresql://docmost:STRONG_DB_PASSWORD@db:5432/docmost'
REDIS_URL: 'redis://redis:6379'
# MAIL_DRIVER: smtp
# SMTP_HOST: smtp.domain.de
# SMTP_PORT: 587
# SMTP_USERNAME: info@domain.de
# SMTP_PASSWORD: mail-password
# SMTP_SECURE: TLS
# MAIL_FROM_ADDRESS: info@domain.de
# MAIL_FROM_NAME: Docmost
restart: unless-stopped
volumes:
- docmost:/app/data/storage
labels:
- "traefik.enable=true"
- "traefik.http.routers.docmost.entrypoints=websecure"
- "traefik.http.routers.docmost.rule=Host(`docmost.domain.de`)"
- "traefik.http.routers.docmost.tls=true"
- "traefik.http.routers.docmost.tls.certresolver=http_resolver"
- "traefik.http.routers.docmost.service=docmost"
- "traefik.http.services.docmost.loadbalancer.server.port=3000"
- "traefik.docker.network=proxy"
- "traefik.http.routers.docmost.middlewares=default@file"
networks:
- default
- proxy
db:
image: postgres:18
environment:
POSTGRES_DB: docmost
POSTGRES_USER: docmost
POSTGRES_PASSWORD: STRONG_DB_PASSWORD
restart: unless-stopped
volumes:
- db_data:/var/lib/postgresql
networks:
- default
redis:
image: redis:8
command: ["redis-server", "--appendonly", "yes", "--maxmemory-policy", "noeviction"]
restart: unless-stopped
volumes:
- redis_data:/data
networks:
- default
volumes:
docmost:
db_data:
redis_data:
networks:
proxy:
external: true
Code-Sprache: PHP (php)
Optional:
Nehmt die Kommentierung bei den MAIL/SMTP Environments raus und passt die Settings auf euren Mail-Provider an. Hier findet ihr eine Liste weiterer Features, welche ihr aktivieren könnt: https://docmost.com/docs/self-hosting/configuration
4. Konfigurationsskript erstellen
Nun erstellen wir uns noch ein Skript, welches uns Passwörter sowie Traefik URL anpasst:
nano /opt/containers/docmost/setup.sh
Inhalt:
#!/usr/bin/env bash
set -euo pipefail
# ----------------------------------------------------------------------------
# Konfiguration
# ----------------------------------------------------------------------------
COMPOSE_FILE="${1:-docker-compose.yml}"
# ----------------------------------------------------------------------------
# Hilfsfunktionen
# ----------------------------------------------------------------------------
err() { echo "FEHLER: $*" >&2; exit 1; }
info() { echo ">>> $*"; }
# Escaped einen String fuer den Einsatz im sed-Replacement (rechte Seite).
# Wir verwenden '|' als Trennzeichen in sed, daher muessen wir &, \, | und /
# escapen. Newlines kommen in unseren Werten nicht vor.
sed_escape_replacement() {
printf '%s' "$1" | sed -e 's/[\\&|/]/\\&/g'
}
# Pruefung, ob ein gegebener String ein gueltiger Hostname ist.
# Erlaubt: Buchstaben, Ziffern, '-', '.'; keine Leerzeichen; min. ein Punkt
validate_host() {
local h="$1"
[[ -n "$h" ]] || return 1
[[ "$h" =~ ^[A-Za-z0-9.-]+$ ]] || return 1
[[ "$h" == *.* ]] || return 1
return 0
}
# ----------------------------------------------------------------------------
# Vorbedingungen pruefen
# ----------------------------------------------------------------------------
command -v openssl >/dev/null 2>&1 || err "openssl ist nicht installiert."
command -v sed >/dev/null 2>&1 || err "sed ist nicht installiert."
[[ -f "$COMPOSE_FILE" ]] || err "Datei '$COMPOSE_FILE' nicht gefunden."
[[ -w "$COMPOSE_FILE" ]] || err "Datei '$COMPOSE_FILE' ist nicht beschreibbar."
# ----------------------------------------------------------------------------
# Eingabe: Traefik-Host
# ----------------------------------------------------------------------------
TRAEFIK_HOST=""
if [[ -n "${TRAEFIK_HOST_ENV:-}" ]]; then
# Nicht-interaktive Verwendung moeglich: TRAEFIK_HOST_ENV=foo.bar.de ./setup-docmost.sh
TRAEFIK_HOST="$TRAEFIK_HOST_ENV"
else
while :; do
read -r -p "Traefik-Host (z.B. docmost.example.com): " TRAEFIK_HOST
if validate_host "$TRAEFIK_HOST"; then
break
fi
echo " Ungueltiger Hostname. Bitte erneut eingeben."
done
fi
APP_URL="https://${TRAEFIK_HOST}"
# ----------------------------------------------------------------------------
# Secrets generieren
# ----------------------------------------------------------------------------
# APP_SECRET: 64 Zeichen Base64 (~48 Byte Entropie). Docmost verlangt nur,
# dass es lang und zufaellig ist.
APP_SECRET="$(openssl rand -base64 48 | tr -d '\n=' | tr '+/' '-_' | cut -c1-64)"
# DB-Passwort: 32 Zeichen, nur URL-sichere Zeichen, damit es problemlos in
# der DATABASE_URL verwendet werden kann (kein @, :, /, # etc.).
DB_PASSWORD="$(openssl rand -base64 48 | tr -dc 'A-Za-z0-9' | cut -c1-32)"
[[ ${#APP_SECRET} -ge 32 ]] || err "APP_SECRET-Generierung fehlgeschlagen."
[[ ${#DB_PASSWORD} -ge 24 ]] || err "DB-Passwort-Generierung fehlgeschlagen."
# ----------------------------------------------------------------------------
# Backup anlegen
# ----------------------------------------------------------------------------
BACKUP_FILE="${COMPOSE_FILE}.bak.$(date +%Y%m%d-%H%M%S)"
cp -p "$COMPOSE_FILE" "$BACKUP_FILE"
info "Backup erstellt: $BACKUP_FILE"
# ----------------------------------------------------------------------------
# Ersetzungen durchfuehren
# ----------------------------------------------------------------------------
# Wir nutzen sed mit '|' als Trennzeichen, weil unsere Werte '/' enthalten
# koennen (z.B. in der URL). Werte werden zusaetzlich escaped.
APP_URL_ESC="$(sed_escape_replacement "$APP_URL")"
APP_SECRET_ESC="$(sed_escape_replacement "$APP_SECRET")"
DB_PASSWORD_ESC="$(sed_escape_replacement "$DB_PASSWORD")"
TRAEFIK_HOST_ESC="$(sed_escape_replacement "$TRAEFIK_HOST")"
# 1) APP_URL ersetzen (Zeile mit "APP_URL:")
sed -i.tmp -E "s|^([[:space:]]*APP_URL:[[:space:]]*)['\"]?[^'\"]*['\"]?|\1'${APP_URL_ESC}'|" "$COMPOSE_FILE"
# 2) APP_SECRET ersetzen
sed -i.tmp -E "s|^([[:space:]]*APP_SECRET:[[:space:]]*)['\"]?[^'\"]*['\"]?|\1'${APP_SECRET_ESC}'|" "$COMPOSE_FILE"
# 3) DATABASE_URL: nur das Passwort-Segment ersetzen.
# Format: postgresql://USER:PASSWORD@HOST:PORT/DB
sed -i.tmp -E "s|(postgresql://[^:]+:)[^@]+(@)|\1${DB_PASSWORD_ESC}\2|g" "$COMPOSE_FILE"
# 4) POSTGRES_PASSWORD ersetzen
sed -i.tmp -E "s|^([[:space:]]*POSTGRES_PASSWORD:[[:space:]]*)['\"]?[^'\"]*['\"]?|\1'${DB_PASSWORD_ESC}'|" "$COMPOSE_FILE"
# 5) Traefik Host(`...`) ersetzen
sed -i.tmp -E "s|(Host\\()\`[^\`]*\`(\\))|\1\`${TRAEFIK_HOST_ESC}\`\2|" "$COMPOSE_FILE"
# Aufraeumen
rm -f "${COMPOSE_FILE}.tmp"
# ----------------------------------------------------------------------------
# Plausibilitaetspruefung
# ----------------------------------------------------------------------------
remaining_placeholders=()
grep -q 'REPLACE_WITH_LONG_SECRET' "$COMPOSE_FILE" && remaining_placeholders+=("REPLACE_WITH_LONG_SECRET")
grep -q 'STRONG_DB_PASSWORD' "$COMPOSE_FILE" && remaining_placeholders+=("STRONG_DB_PASSWORD")
if (( ${#remaining_placeholders[@]} > 0 )); then
echo "WARNUNG: Folgende Platzhalter wurden nicht ersetzt:" >&2
printf ' - %s\n' "${remaining_placeholders[@]}" >&2
echo "Bitte die Datei manuell pruefen. Backup: $BACKUP_FILE" >&2
exit 2
fi
# ----------------------------------------------------------------------------
# Zusammenfassung
# ----------------------------------------------------------------------------
info "Datei '$COMPOSE_FILE' wurde aktualisiert."
echo
echo " Traefik-Host : $TRAEFIK_HOST"
echo " APP_URL : $APP_URL"
echo " APP_SECRET : gesetzt"
echo " DB-Passwort : gesetzt"
echo " Backup : $BACKUP_FILE"
echo
Code-Sprache: PHP (php)
Nun starten wir das Skript:
cd /opt/containers/docmost/
chmod +x setup.sh
./setup.sh
5. Docmost starten
Nun starten wir den Container mittels folgendem Befehl:
docker compose -f /opt/containers/docmost/docker-compose.yml up -d
Sobald der Container ausgerollt ist könnt ihr nun eure Domain aufrufen. Der Container ist rasend schnell bereit. Nach dem pullen der images dauert es bei mir ca 10 Sekunden.
Ruft nun im Browser die gewählte Domain auf und dann solltet ihr folgendes sehen.

Quelle:

Die ursprüngliche Anleitung ist schon eine Weile her. Ich habe heute docmost neu aufgesetzt und dabei ein paar Änderungen an der docker-compose.yml vorgenommen:
SMTPFür SSL SMTP_PORT: 465 setzenFür SSL SMTP_SECURE: trueNeue Version für PostgeSQLimage: postgres:18Für Redis auch neue Version und zusätzlich noch ein Befehlimage: redis:8command: [“redis-server”, “–appendonly”, “yes”, “–maxmemory-policy”, “noeviction”]Meine docker-compose-yml sieht dann wie folgt aus:
—
services:
docmost:
image: docmost/docmost:latest
depends_on:
– db
– redis
environment:
APP_URL: ‘http://docmost.domain.de’
APP_SECRET: ‘s3cr3t-k3y’
DATABASE_URL: ‘postgresql://docmost:PASSWORD@db:5432/docmost?schema=public’ # PASSWORD wie unten POSTGRES_PASSWORD:
REDIS_URL: ‘redis://redis:6379’
MAIL_DRIVER: smtp
SMTP_HOST: smtp.domain.de
SMTP_PORT: 465
SMTP_USERNAME: info@domain.de
SMTP_PASSWORD: kWxi7AUgnV23PvS1GINxU
SMTP_SECURE: true
MAIL_FROM_ADDRESS: info@domain.de
MAIL_FROM_NAME: Docmost
restart: unless-stopped
volumes:
– docmost:/app/data/storage
labels:
– “traefik.enable=true”
– “traefik.http.routers.docmost.entrypoints=websecure”
– “traefik.http.routers.docmost.rule=Host(
docmost.<span style="color: rgb(119, 119, 119);">domain.de</span>)”– “traefik.http.routers.docmost.tls=true”
– “traefik.http.routers.docmost.tls.certresolver=http_resolver”
– “traefik.http.routers.docmost.service=docmost”
– “traefik.http.services.docmost.loadbalancer.server.port=3000”
– “traefik.docker.network=proxy”
– “traefik.http.routers.docmost.middlewares=default@file”
networks:
– default
– proxy
db:
image: postgres:18
environment:
POSTGRES_DB: docmost
POSTGRES_USER: docmost
POSTGRES_PASSWORD: PASSWORD # selbe wie oben “DATABASE_URL:”
restart: unless-stopped
volumes:
– db_data:/var/lib/postgresql
networks:
– default
redis:
image: redis:8
command: [“redis-server”, “–appendonly”, “yes”, “–maxmemory-policy”, “noeviction”]
restart: unless-stopped
volumes:
– redis_data:/data
networks:
– default
volumes:
docmost:
db_data:
redis_data:
networks:
proxy:
external: true
—
Jetzt geht’s ans Ausprobieren!
Bei mir ging der Upload von Dateien nicht, da die Rechte des Ordners (docmost:/app/data/storage) in der docmost-app angepasst werden musste:
sudo chmod -R 775 docmost/