Docker image
BookStack in Docker. Your wiki, production ready.
BookStack is an open source wiki and documentation platform that organizes content into a familiar shelves, books, chapters, and pages structure, with a WYSIWYG editor, full-text search, and page-level permissions.
Prefer not to run it yourself? Managed BookStack from $5/mo
# BookStack in Docker, base pinned by digest docker pull ghcr.io/remarkablecloud/bookstack:26.05.4-r1 docker compose up -d
- Current build
26.05.4-r1, updated Sep 11, 2026- Base
- BookStack official (linuxserver base per repo), digest-pinned
- What's inside
- Per-instance APP_KEY, rotated default admin, MariaDB pairing, healthcheck
- Upstream license
- BookStack: MIT
The image
What our image adds.
What changes from upstream BookStack, and why it matters in production.
Digest-pinned base
Built from lscr.io/linuxserver/bookstack@sha256:ec33b8ad7ab5… (BookStack v26.05.4 on Alpine, PHP 8.5). Pinning by digest keeps rebuilds reproducible: the base changes only when we bump the digest on purpose.
Per-instance APP_KEY
BookStack is a Laravel application and needs an encryption key (APP_KEY) that stays identical across restarts and is never shared between instances. On first boot the image generates a unique key and keeps it in the /config volume.
No default credentials
Upstream seeds a well-known admin account (admin@admin.com / password). Our image rotates that password to a strong generated one on first boot, before the instance is reachable, and prints the login once to the container log. You can pin the password with RC_ADMIN_PASSWORD.
Healthcheck
A container HEALTHCHECK polls /status (which also confirms database, cache, and session backends) so the platform routes traffic only once BookStack is fully serving. The current published tag is ghcr.io/remarkablecloud/bookstack:26.05.4-r1.
Run it yourself, or not
Same image either way.
Pull it and run it anywhere, or let us run BookStack for you on a managed server with updates, monitoring and snapshots.
Run BookStack yourself
- Pull it from GHCR and run it on any Docker host
- The guide below: compose, environment, backups, upgrades
- You patch, back up and watch it
BookStack on a managed server
- Installed for you from this same image, $0 for the app
- Updates with a snapshot first, monitoring and a managed firewall
- A 1 GB server from $5/mo billed annually, with room for more apps
The guide
Run it in production.
Compose file, environment reference, hardening, backups and upgrades, written by the people who build the image.
On this page
Architecture at a glance
- BookStack (nginx and PHP) serves plain HTTP on port
80. TLS is terminated upstream by a reverse proxy (Traefik on the RemarkableCloud App Platform), so there is no in-container certificate to manage. SetAPP_URLto the public HTTPS address andAPP_PROXIESso BookStack trusts the proxy for the request scheme. - MariaDB is a separate database container and holds pages, users, permissions, and revisions.
- A data volume at
/configholds uploaded images and attachments, the generatedAPP_KEY, and other instance state.
Docker Compose walkthrough
The standalone stack (BookStack and MariaDB) is defined in the image’s docker-compose.yml:
name: bookstack
services:
db:
image: mariadb:11
restart: unless-stopped
environment:
MARIADB_DATABASE: bookstack
MARIADB_USER: bookstack
MARIADB_PASSWORD: ${DB_PASSWORD:-change-me-db}
MARIADB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:-change-me-root}
volumes: [db-data:/var/lib/mysql]
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
interval: 10s
timeout: 5s
retries: 12
bookstack:
image: ${BOOKSTACK_IMAGE:-ghcr.io/remarkablecloud/bookstack:26.05.4-r1}
restart: unless-stopped
depends_on:
db:
condition: service_healthy
ports: ["${HTTP_PORT:-8088}:80"]
environment:
APP_URL: ${APP_URL:-http://localhost:8088}
APP_KEY: ${APP_KEY:-}
APP_PROXIES: ${APP_PROXIES:-}
RC_ADMIN_EMAIL: ${RC_ADMIN_EMAIL:-}
RC_ADMIN_PASSWORD: ${RC_ADMIN_PASSWORD:-}
DB_HOST: db
DB_PORT: "3306"
DB_DATABASE: bookstack
DB_USERNAME: bookstack
DB_PASSWORD: ${DB_PASSWORD:-change-me-db}
volumes:
- bookstack-config:/config
volumes:
db-data:
bookstack-config:
Step by step:
- The app waits for the database.
depends_onwithcondition: service_healthyavoids a first-boot race against MariaDB. - The key is created once. Leave
APP_KEYempty and the image generates one on first boot and keeps it in the/configvolume across restarts and upgrades. - The default admin is rotated. Leave
RC_ADMIN_PASSWORDempty and the image replaces the upstream default password with a strong generated one and prints the login once; set it to pin a known password. - Only the web port is exposed.
${HTTP_PORT:-8088}:80is for local use; in production the proxy connects to port80on the internal network and nothing is bound on the host. - State lives in volumes.
bookstack-config(/config) anddb-datapersist across restarts and upgrades.
To start it locally:
DB_PASSWORD=$(openssl rand -hex 16) docker compose up -d
Then browse to http://localhost:8088 and read the admin login from docker compose logs bookstack. For production, set APP_URL to your HTTPS address, set APP_PROXIES to trust the proxy, and put the container behind a TLS-terminating reverse proxy.
Environment variable reference
These are wired automatically by the App Platform backend from the managed MariaDB; they are listed here for standalone and self-hosted runs.
| Variable | Required | Value / default | Purpose |
|---|---|---|---|
APP_URL | yes | https://<hostname> | Public base URL BookStack uses to generate links. |
APP_KEY | no | (generated) | Laravel encryption key. Leave empty to generate and persist one on first boot; set it to pin your own. |
APP_PROXIES | no | * | Reverse proxies BookStack trusts for the forwarded scheme. Use the proxy address, or * when only the proxy can reach the container. |
RC_ADMIN_EMAIL | no | admin@admin.com | Email for the initial admin after rotation. |
RC_ADMIN_PASSWORD | no | (generated) | Initial admin password. Leave empty to auto-generate on first boot (printed once to the log); set it to pin your own. |
DB_HOST | yes | <db_host> | MariaDB host. |
DB_PORT | yes | 3306 | MariaDB port. |
DB_DATABASE | yes | <db_name> | Database name. |
DB_USERNAME | yes | <db_user> | Database user. |
DB_PASSWORD | yes | <db_password> | Database password. |
The admin rotation only touches the first boot; once it has run, account changes happen inside BookStack.
Hardening notes
- No baked credentials. The
APP_KEYand the admin password are generated at runtime or supplied by you, never stored in an image layer. - No default login exposure. The upstream
admin@admin.com/passwordaccount is rotated before the instance is reachable, so a fresh site cannot be entered with public default credentials. - Digest-pinned base. Each build is auditable and reproducible.
- Healthcheck gates traffic.
/statusmust return success before the platform routes requests. - Keep MariaDB private. Do not publish its port to the host or the internet.
- After first login, review users and roles, keep BookStack updated, and enable multi-factor authentication for administrators.
Backups
Capture the database and the data volume together:
- The MariaDB database:
docker compose exec db mariadb-dump -u root -p"$DB_ROOT_PASSWORD" bookstack > bookstack-db.sql - The data volume at
/config(uploaded images, attachments,APP_KEY):docker run --rm -v bookstack_bookstack-config:/data -v "$PWD":/backup alpine \ tar czf /backup/bookstack-config.tgz -C /data .
Keep the APP_KEY (in /config) with the database backup: without the matching key, encrypted values in the database cannot be read. On the RemarkableCloud App Platform, database and volume backups follow the platform’s backup schedule.
Upgrades
- New builds ship as new
-rtags. Pull the new tag and recreate the container; BookStack runs any database migrations it needs on start:docker compose pull bookstack && docker compose up -d bookstack - Back up first, and keep the database dump and the
/configarchive from just before the upgrade. - Read the changelog. Every build is listed in
CHANGELOG.mdwith the base image digest and any behavior changes.
Changelog
Each build is pinned by digest and recorded here, so you can see what changed before you pull a new tag.
-
26.05.4-r1Current Sep 11, 2026
BookStack and other product names are trademarks of their respective owners. RemarkableCloud is not affiliated with or endorsed by them.
FAQ
BookStack in Docker, answered.
Short answers from the people who build and run this image.
Do I need a database?
Yes. BookStack stores pages, users, and permissions in MariaDB (or MySQL). The standalone compose file includes MariaDB.
What is APP_KEY and why does it matter?
It is BookStack's encryption key. It must stay the same across restarts, and it must differ between instances. The image generates one on first boot and keeps it in the /config volume, so this is handled for you; back it up with the database.
What are the first admin credentials?
The image rotates the upstream default and prints the login (email and generated password) once to the container log on first boot. Set RC_ADMIN_PASSWORD to pin a known password.
How does HTTPS work if the container only serves HTTP on port 80?
TLS is terminated at the reverse proxy (Traefik on the App Platform), which forwards requests to BookStack on the internal network. Set APP_URL to the HTTPS address and APP_PROXIES so links and redirects use the correct scheme.
Can I use MySQL instead of MariaDB?
Yes. BookStack connects with the MySQL driver, which works with both MySQL 8 and MariaDB; point DB_HOST at your server.
Pull it, or let us run it.
The same image runs BookStack on our managed servers, updates and monitoring included.