Skip to main content

Deploying BookStack on YunoHost via Docker Compose (The Humane-Tech Method)

1. Context & Philosophy

This guide documents the installation of BookStack on a YunoHost VPS (obulou.org). Instead of a standard root-based installation, this setup prioritises a Humane-Tech approach: strictly controlling data ownership by running containers as a specific non-root administrative user to prevent permission locks and keep the system clean.

We use the LinuxServer.io images because they handle PUID/PGID mapping excellently, ensuring files in the volume mounts remain owned by the user, not root.

2. Prerequisites

  • OS: Debian 12 (Bookworm) with YunoHost installed.

  • Docker: Installed and running.

  • User Info: A non-root user (e.g., kalvin0x8d0) with sudo privileges.

  • PUID/PGID: Run id to confirm (e.g., 23691).

  • Target Domain: bookstack.obulou.org (or similar).

  • Target Port: 52575 (arbitrary high port to avoid conflicts).

3. Directory Setup & Security Key

First, create the directory in your home folder to ensure you own the data.

mkdir -p ~/docker/bookstack
cd ~/docker/bookstack

Generate a secure unique 32-byte key. You will need this for the APP_KEY later. Note: Ensure you include the hyphen - before base64, otherwise the command may fail.

echo "base64:$(openssl rand -base64 32)"

(Copy the output string; it will look like base64:randomcharacters...)

4. The Docker Compose Configuration

Create your compose.yaml.

Crucial Decision: Do not put the APP_KEY in this file. We learnt that Docker variables override the .env file, which can cause "Cipher Error" loops. We will add it manually to the generated config file later.

services:
  bookstack:
    image: lscr.io/linuxserver/bookstack:latest
    container_name: bookstack
    environment:
      - PUID=23691  # Replace with your actual ID
      - PGID=23691
      - TZ=Asia/Kuala_Lumpur
      - APP_URL=https://bookstack.obulou.org
      - DB_HOST=bookstack_db
      - DB_USER=bookstack
      - DB_PASS=YourSecretPassword
      - DB_DATABASE=bookstackapp
    volumes:
      - ./config:/config
    ports:
      - 52575:80
    restart: unless-stopped
    depends_on:
      - bookstack_db

  bookstack_db:
    image: lscr.io/linuxserver/mariadb:latest
    container_name: bookstack_db
    environment:
      - PUID=23691
      - PGID=23691
      - TZ=Asia/Kuala_Lumpur
      - MYSQL_ROOT_PASSWORD=YourRootPassword
      - MYSQL_DATABASE=bookstackapp
      - MYSQL_USER=bookstack
      - MYSQL_PASSWORD=YourSecretPassword
    volumes:
      - ./db_data:/config
    restart: unless-stopped

5. The Installation & The "Gotcha" Fixes

This is where most installations fail. Follow these steps precisely to avoid "500 Errors" or "Access Denied" loops.

Step A: Initial Boot

Run the container to generate the initial configuration files.

docker compose up -d

Step B: Fixing the .env Conflict (The "Access Denied" Fix)

By default, the container creates a .env file populated with placeholders like DB_HOST=localhost and DB_USERNAME=database_username. This conflicts with your compose.yaml settings.

  1. Edit the generated file:
nano config/www/.env

  1. Update the Database Section: Ensure it matches your compose.yaml exactly.
DB_HOST=bookstack_db       # MUST match the container name, NOT localhost
DB_DATABASE=bookstackapp
DB_USERNAME=bookstack
DB_PASSWORD=YourSecretPassword

  1. Add the App Key: Paste the key you generated in Section 3 here.
APP_KEY=base64:YOUR_GENERATED_KEY

Step C: Clearing the Cache (The "White Screen" Fix)

After editing the .env file, BookStack won't see the changes until the cache is cleared. Note: You must specify the working directory -w /app/www because the artisan file is not in the container root.

docker exec -w /app/www bookstack php artisan config:clear
docker exec -w /app/www bookstack php artisan cache:clear

6. Exposing to the Web

Since the app runs on localhost:52575, use YunoHost to bridge it to the outside world.

  1. Go to YunoHost Admin > Applications > Install.
  2. Select Redirect.
  3. Configure:
  • Domain: bookstack.obulou.org
  • Path: /
  • Destination: http://127.0.0.1:52575

7. Post-Install: SMTP Email Setup

To ensure "Forgot Password" works, configure SMTP in config/www/.env. Tip: If your password contains special characters, you MUST wrap it in double quotes.

MAIL_DRIVER=smtp
MAIL_HOST=smtp.yourprovider.com
MAIL_PORT=587
MAIL_ENCRYPTION=tls
MAIL_USERNAME=your_email@obulou.org
MAIL_PASSWORD="Your!Secret#Password"
MAIL_FROM=your_email@obulou.org

Remember to run the cache clear command from Step 5C again after saving!

8. Lessons Learnt

  • Artisan Path: When running commands via docker exec, the artisan binary is located at /app/www, not the root. Using -w /app/www is mandatory.
  • Config Priority: BookStack reads the generated .env file first. If that file contains default placeholder database credentials, it will ignore your Docker Compose variables, leading to "Access Denied" errors. Always manually sync the .env file.
  • Typo Alert: The openssl command requires a hyphen (-base64), or it will fail silently or output nothing.