Skip to main content

Eigene BookStack-Instanz installieren

ℹ️ Dieser Artikel erklärt erst ab dem Punkt, wo man schon einen Linux-Server aufgesetzt hat und auch Docker schon installiert ist. – Ich werde demnächst alle vorangegangenen Schritte erklären, ist wirklich nicht schwer, vor Allem mit Hilfe von KIs.​

Schritt 1: Komposition vorbereiten

Wir wollen, dass eine Domain eingerichtet wird, die mit https://... aufgerufen werden kann, weshalb ich mich für Caddy entschieden habe.

ℹ️ Was ist Caddy? 🌐

Caddy ist ein moderner, in Go geschriebener Webserver (ähnlich wie Nginx oder Apache), der besonders dafür bekannt ist, viele Dinge standardmäßig sicher und bequem zu machen.

Kernidee: „Webserver, der einfach funktioniert“ ✅

Caddy nimmt dir viel Konfigurationsarbeit ab – vor allem rund um HTTPS.

Wichtige Merkmale ✨

  1. Automatisches HTTPS (TLS)
    • Caddy kann Zertifikate automatisch beziehen und erneuern (typischerweise via Let’s Encrypt), sodass deine Websites ohne großen Aufwand über https:// laufen.
  2. Einfache Konfiguration
    • Mit dem Caddyfile (eine schlanke, gut lesbare Konfigurationsdatei) lässt sich vieles sehr kompakt definieren.
  3. Reverse Proxy & Load Balancing
    • Ideal, um Anfragen an andere Dienste weiterzuleiten, z. B. an eine Node.js-, Python- oder Docker-Anwendung.
  4. Gute Defaults & Security-by-Default
    • Viele sinnvolle Einstellungen sind bereits „von Haus aus“ aktiv, statt alles manuell „zusammenschrauben“ zu müssen.
  5. Erweiterbar über Module
    • Caddy ist modular aufgebaut und kann für spezielle Anforderungen erweitert werden.

Typische Einsatzfälle 🧩

  • Websites hosten (statisch oder dynamisch)
  • Reverse Proxy vor einer App (z. B. /api → Backend)
  • TLS-Termination und sichere Weiterleitung
  • Lokale Entwicklungsumgebungen mit HTTPS

Erstelle einen Ordner hier: /opt/bookstack Und darin zwei Dateien: Caddyfile und docker-compose.yml
Füge dort den folgenden Inhalt ein und passe ihn an (du siehst schon wo^^):

BookStack-YML (docker-compose.yml)

services:
  mariadb:
    image: lscr.io/linuxserver/mariadb:latest
    container_name: bookstack-mariadb
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/Berlin
      - MYSQL_ROOT_PASSWORD=PW_OF_MYSQL_ROOT
      - MYSQL_DATABASE=bookstack
      - MYSQL_USER=bookstack
      - MYSQL_PASSWORD=PW_OF_MYSQL_DB
    volumes:
      - ./mariadb:/config
    restart: unless-stopped

  bookstack:
    image: lscr.io/linuxserver/bookstack:latest
    container_name: bookstack
    depends_on:
      - mariadb
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/Berlin

      - APP_URL=https://wiki.fabula.vision
      # Wo wird BookStack aufrufbar sein? (Deine URL)
      - APP_KEY=base64:...
      # Zum Generieren das ausführen: docker run -it --rm --entrypoint /bin/bash lscr.io/linuxserver/bookstack:latest appkey
      - APP_THEME=custom
      #'custom' ermöglich es Hacks zu nutzen; mehr dazu hier: https://www.bookstackapp.com/hacks/applying/

      - DB_HOST=mariadb
      - DB_PORT=3306
      - DB_DATABASE=bookstack
      - DB_USERNAME=bookstack
      - DB_PASSWORD=PW_OF_MYSQL_DB
      # (Wie oben!)

      - APP_DEFAULT_DARK_MODE=true
      # (Geschmackssache)

    volumes:
      - ./bookstack:/config
    restart: unless-stopped

  caddy:
    image: caddy:latest
    container_name: caddy
    depends_on:
      - bookstack
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - ./caddy/data:/data
      - ./caddy/config:/config
    restart: unless-stopped

Caddyfile

wiki.fabula.vision {
	# Deine URL natürlich...
	encode zstd gzip

	# Reverse Proxy zu BookStack (Container heißt "bookstack", interner Port 80)
	reverse_proxy bookstack:80

	# sinnvolle Header (optional)
	header {
		# HSTS (nur setzen, wenn du sicher bist, dass HTTPS dauerhaft aktiv sein soll)
		Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
		X-Content-Type-Options "nosniff"
		X-Frame-Options "SAMEORIGIN"
		Referrer-Policy "strict-origin-when-cross-origin"
	}
}

Schritt 2: Starten

  1. Ins Verzeichnis wechseln:
    cd /opt/bookstack/
  2. Unser Zeugs installieren:
    docker compose up -d
    Aktualisieren geht dann so:
    docker compose pull; docker compose up -d
  3. Fertig, aber nun schnell die URL aufrufen und die Standard-Zugangsdaten ändern!
    Standard-Login (User + Passwort): admin@admin.com + password

Cron

Einen Cron-Job für BookStack anlegen geht folgendermaßen:

  1. crontab -e
  2. Eintragen (Cron jede Minute):
    * * * * * docker exec -i bookstack php /app/www/artisan schedule:run >/dev/null 2>&1

Beschränkungen & Module/Hacks

Es gibt drei Einschränkungen, die ich bisher festgestellt habe:

  1. E-Mail-Versand (z.B. „Passwort vergessen“) funktioniert nicht, bzw. meine Experimente haben noch keine Lösung hervorgebracht und ich brauche das auch nicht zwingend. Aber wenn man z.B. Kommentare aktivieren will (User bekommen eine Benachrichtigung, wenn ihre Seiten kommentiert werden), dann kommt man da nicht drumherum. Mehr dazu hier.

  2. Man kann die Funktionalität mit sogenannten „Hacks" erweitern und ich kann zwei Hacks schon mal empfehlen:

    1. https://www.bookstackapp.com/hacks/mathjax-tex/
      Mathe-Formeln darstellen;
    2. https://www.bookstackapp.com/hacks/mermaid-viewer/
      (Mermaid-)Diagramme darstellen;

    Allerdings funktioniert das nicht mit der Export-Funktion, d.h. wenn ein Besucher Buch X als PDF beispielsweise exportiert, dann sieht er statt Formeln und Diagrammen nur Code-Blöcke.

    Und das mit dem Exportieren funktioniert eh leider nicht bei mir, habe keine Ahnung warum und deshalb die Funktion einfach deaktiviert.

    Ok, aber wie installiert man nun die Hacks? – Also den ersten Schritt haben wir getan, indem wir oben (in der YML-Datei) APP_THEME=custom definiert haben, was dafür sorgt, dass fortan Module geladen werden können, die sich hier befinden: /opt/bookstack/bookstack/www/themes/custom/modules

    Nun muss man per SSH das eingeben:

    1. docker exec -it bookstack /bin/bash Damit kann man dann Befehle „von innen“ heraus ausführen;
    2. Dann: cd /app/www/;
    3. Und dort dann das Kommando ausführen, das hier angezeigt wird (am Beispiel Mermaid):
      https://www.bookstackapp.com/hacks/mermaid-viewer/ Dort dann im Abschnitt: „Install as Module“…
  3. Shift+Enter – Zeilenumbruch: Da sich die Entwickler auf den CommonMark-Standard festgelegt haben, bedeutet es, dass u.a. standardmäßig ein einfacher Zeilenumbruch nicht gerendert wird: Man muss zwei Spaces am Zeilenende schreiben und dann Enter, damit ein einfacher Linebreak stattfindet – das hat mich wahnsinnig gemacht, weil alle Markdown-Editoren, die ich kenne funktionieren da anders (einfach Shift+Enter). Das wollte ich unbedingt ändern und habe dafür ein paar Stunden Zeit investiert. Jedenfalls sieht der Fix folgendermaßen aus:

    1. Hier (https://example.com/settings/customization) bei „Custom HTML Head Content“ diesen Code eintragen:

      <script>
        window.addEventListener('editor-markdown::setup', event => {
          event.detail.markdownIt.set({breaks: true});
        });
      </script>
      
    2. Dann hier eine functions.php anlegen:
      /opt/bookstack/bookstack/www/themes/custom/
      Mit dem folgenden Inhalt:

      <?php
      
      use BookStack\Theming\ThemeEvents;
      use BookStack\Facades\Theme;
      
      Theme::listen(ThemeEvents::COMMONMARK_ENVIRONMENT_CONFIGURE, function ($environment) {
        $environment->mergeConfig([
          'renderer' => [
            'soft_break' => "<br>",
          ]
        ]);
      
        return $environment;
      });
      

Weitere QoL-Fixes (einzustellen hier: https://deineurl.com/settings/customization)

Einfach unter „Custom HTML Head Content“ eintragen:

  1. Blockquotes haben keinen dicken Rand unten (liegt am CSS, weil u.a. alle <p>-Elemente margin-bottom haben) - dieser Fix macht oben und unten den gleichen Abstand:

    <style>
      /* 1) Letztes & erstes direktes Kindelement im Blockquote: Margin */
      .content-wrap blockquote > :last-child {
        margin-bottom: .3em;
      }
    
      .content-wrap blockquote > :first-child {
        margin-top: .3em;
      }
    
      /* 2) Blockquote: keine Scrollbalken */
      .content-wrap blockquote {
        overflow: visible;     /* Standard „ohne Scrollen“ */
        overflow-x: visible;
        overflow-y: visible;
      }
    </style>
    
  2. Codeblöcke haben Soft-Wraps (also man muss nicht horizontal scrollen, um die ganze Zeile zu sehen):

    <script>
    window.addEventListener('library-cm6::pre-init', event => {
        const detail = event.detail;
        const config = detail.editorViewConfig;
        const EditorView = detail.libEditorView;
    
        if (detail.usage === 'content-code-block') {
            config.extensions.push(EditorView.lineWrapping);
        }
    });
    </script>
    
  3. Text im Dark-Mode heller machen (Überschriften werden grau 70%, normaler Text hell-grau 90%):

    <style>
    html.dark-mode .page-content h1, html.dark-mode .page-content h2, html.dark-mode .page-content h3, html.dark-mode .page-content h4, html.dark-mode .page-content h5, html.dark-mode .page-content h6 {
        color: hsl(0 0% 70%);
      }
      html.dark-mode body {
        color: hsl(0 0% 90%);
      }
    </style>
    
  4. Text größer machen (Hauptinhalt wird auf 110% hochskaliert, aber Überschriften auf 90% runter, weil ich sie als zu groß empfand):

    <style>
    .page-content {
        zoom:1.1;
      }
    
      .page-content h1, .page-content h2, .page-content h3, .page-content h4, .page-content h5, .page-content h6 {
        zoom:.9;
      }
    </style>