BookStack
Open-source wiki and documentation platform written in PHP (Laravel): content is organised into shelves, books, chapters and pages, with a WYSIWYG and a Markdown editor. Runs here as the linuxserver.io image with a MariaDB database.
Resources by load level
What the app itself needs at each level, next to what we recommend for a server that runs only this app.
| Level | What it means | App requirements | Recommended |
|---|---|---|---|
| LightEstimate | Up to 10 users, 1 uncached page request at a time, up to 5 GiB of images and attachments, database up to 256 MiB. | 1 vCPU · 0.875 GiB RAM · 6.887 GiB disk | 1.32 vCPU · 2.55 GiB RAM · 17.351 GiB disk |
| MediumEstimate | Up to 50 users, 3 uncached page requests at once, up to 20 GiB of images and attachments, database up to 512 MiB. | 3 vCPU · 1.5 GiB RAM · 22.387 GiB disk | 3.72 vCPU · 3.3 GiB RAM · 35.176 GiB disk |
| HeavyEstimate | Up to 200 users, 5 uncached page requests at once (the image's PHP-FPM limit), up to 50 GiB of images and attachments, database up to 1 GiB. | 5 vCPU · 2.625 GiB RAM · 53.387 GiB disk | 6.12 vCPU · 4.65 GiB RAM · 70.826 GiB disk |
Recommended = app requirements + system baseline + safety headroom, under sizing policy 2026.10.0. Options stay at their defaults. “Estimate” means the sources give no number for that case, so it is worked out from them by the method stated under Components. How the numbers are built
Ready-to-run files
Support level Supported
Compose template from the official sources; not yet verified by a run.
Components
What each component needs at each load level, before baseline and headroom.
| Component | Light | Medium | Heavy | Sources |
|---|---|---|---|---|
| BookStack (linuxserver.io image: nginx + PHP-FPM 8.5) (app) | 0.75 / 0.375 / 5.762 | 2.25 / 0.625 / 20.762 | 3.75 / 0.875 / 50.762 | [2][11][19][29][30][33][34][35] |
| MariaDB (database) | 0.25 / 0.5 / 1.125 | 0.75 / 0.875 / 1.625 | 1.25 / 1.75 / 2.625 | [36][37][38][41] |
How the estimates are worked out
- BookStack (linuxserver.io image: nginx + PHP-FPM 8.5) · Light: No upstream figure. vCPU: a request waits on its DB queries, so 1 request needs at most 1 vCPU; 75% here. RAM: 256 MiB fixed (OPcache 128, memcached up to 64, 64 for nginx, FPM master, s6) + 1 x memory_limit 128 MiB = 0.375 GiB. Disk: Image 115,431,525 B compressed (0.108 GiB) + 434,337,792 B unpacked (0.405 GiB), both kept by the containerd store = 0.512 GiB. + 5 GiB uploads + 0.25 GiB logs, caches, sessions and themes.
- BookStack (linuxserver.io image: nginx + PHP-FPM 8.5) · Medium: Same method with 3 concurrent requests: vCPU 75% of 3 = 2.25. RAM: 256 MiB fixed + 3 x 128 MiB memory_limit = 0.625 GiB. Disk: Image 115,431,525 B compressed (0.108 GiB) + 434,337,792 B unpacked (0.405 GiB), both kept by the containerd store = 0.512 GiB. + 20 GiB uploads + 0.25 GiB logs, caches and sessions.
- BookStack (linuxserver.io image: nginx + PHP-FPM 8.5) · Heavy: Same method with 5 concurrent requests, the pool's pm.max_children: vCPU 75% of 5 = 3.75. RAM: 256 MiB fixed + 5 x 128 MiB memory_limit = 0.875 GiB. More needs a larger pool in /config/php/www2.conf. Disk: Image 115,431,525 B compressed (0.108 GiB) + 434,337,792 B unpacked (0.405 GiB), both kept by the containerd store = 0.512 GiB. + 50 GiB uploads + 0.25 GiB logs, caches and sessions.
- MariaDB · Light: vCPU: the remaining 25% of the 1-vCPU request budget. RAM: buffer pool sized to hold the 256 MiB database; 256 MiB / 0.6 (pool = 60-70% of RAM) = 0.42, rounded up to 0.5 GiB. Disk: image 103 MiB compressed, 0.5 GiB allowed + 0.25 GiB data + 96 MiB redo log + 0.25 GiB local dump = 1.09, rounded to 1.125 GiB.
- MariaDB · Medium: vCPU: 25% of the 3-vCPU request budget. RAM: buffer pool raised to 512 MiB to hold the database; 512 MiB / 0.6 = 0.83, rounded up to 0.875 GiB. Disk: 0.5 GiB image allowance + 0.5 GiB data + 96 MiB redo log + 0.5 GiB local dump = 1.59, rounded to 1.625 GiB.
- MariaDB · Heavy: vCPU: 25% of the 5-vCPU request budget. RAM: buffer pool raised to 1 GiB to hold the database; 1 GiB / 0.6 = 1.67, rounded up to 1.75 GiB. Disk: 0.5 GiB image allowance + 1 GiB data + 96 MiB redo log + 1 GiB local dump = 2.59, rounded to 2.625 GiB.
async-queue· BookStack (linuxserver.io image: nginx + PHP-FPM 8.5): One extra PHP CLI process (artisan queue:work) that runs one job at a time: RAM up to its 128 MiB memory_limit; vCPU a 0.25 allowance, since jobs (an e-mail, a webhook call) are short and mostly wait on the network. Jobs are rows in the existing database.
Options that change resources
async-queueSends e-mail and webhooks in the background (QUEUE_CONNECTION=database): the image then starts a queue worker, so saving a page no longer waits for those actions.
Default: off
Ports
Public ports are meant to be reached from outside the stack, usually through a reverse proxy; internal ones stay on the stack's own network.
| Component | Port | Exposure | Purpose | Sources |
|---|---|---|---|---|
| BookStack (linuxserver.io image: nginx + PHP-FPM 8.5) | 80/tcp | Public, through a proxy | Web UI and REST API (nginx + PHP-FPM), behind a TLS reverse proxy | [1][2][8] |
| BookStack (linuxserver.io image: nginx + PHP-FPM 8.5) | 443/tcp | Internal only | nginx HTTPS with the image's self-signed certificate; unused, TLS ends at the proxy | [3][8][9] |
| BookStack (linuxserver.io image: nginx + PHP-FPM 8.5) | 443/udp | Internal only | nginx HTTP/3 (QUIC) listener of the image; unused | [8] |
| BookStack (linuxserver.io image: nginx + PHP-FPM 8.5) | 11211/tcp | Internal only | memcached started by the image; BookStack's default CACHE_DRIVER is file | [10][11][25] |
| MariaDB | 3306/tcp | Internal only | MariaDB client protocol for BookStack | [39] |
User and permissions (UID/GID)
The user each container's process runs as, and the paths it writes to. A bind mount for one of these paths must be writable by that UID:GID.
| Component | UID:GID | User | Starts as root | Writes to | Sources |
|---|---|---|---|---|---|
| BookStack (linuxserver.io image: nginx + PHP-FPM 8.5) | 1000:1000 | abc | Yes, prepares its directories, then drops to this user | /config | [1][4][6][29][31][32] |
| MariaDBDerived | 999:999 | mysql | Yes, prepares its directories, then drops to this user | /var/lib/mysql | [42][43][44] |
- BookStack (linuxserver.io image: nginx + PHP-FPM 8.5): The image starts as root (s6 /init, no USER): it gives user abc the PUID/PGID (1000 in the template and the official example, 911 when unset), chowns /config to abc, and PHP-FPM, the queue worker and memcached run as abc.
- MariaDB: The entrypoint starts as root, chowns /var/lib/mysql to mysql and re-execs with gosu mysql. The IDs are not fixed: useradd -r / groupadd -r on fresh ubuntu:noble take the top of the system range (SYS_UID_MAX 999). Check with: docker run --rm mariadb:12.3.3 id mysql.
Storage growth
How much each component's data grows per month at each load level, on top of the disk in the profile. A value marked Assumption is ANAROQ's stated assumption, not a figure from the sources; the notes say what it rests on.
| Component | Light | Medium | Heavy | Sources |
|---|---|---|---|---|
| BookStack (linuxserver.io image: nginx + PHP-FPM 8.5)Assumption | 0.417 | 1.667 | 4.167 | [2][19] |
| MariaDBAssumption | 0.021 | 0.042 | 0.084 | [25][39] |
What the growth figures rest on
- BookStack (linuxserver.io image: nginx + PHP-FPM 8.5): BookStack publishes no growth rate. Assumes the preset's 5 GiB of uploaded images and attachments in /config fills over 12 months: 5 / 12 = 0.417.
- BookStack (linuxserver.io image: nginx + PHP-FPM 8.5): Same 12-month assumption: 20 GiB of uploads / 12 = 1.667.
- BookStack (linuxserver.io image: nginx + PHP-FPM 8.5): Same 12-month assumption: 50 GiB of uploads / 12 = 4.167.
- MariaDB: Assumes the preset's 256 MiB database is reached over 12 months: 0.25 / 12 = 0.0208, rounded up to 0.021. Page revisions are capped at 100 per page (REVISION_LIMIT) and deleted items leave after 30 days (RECYCLE_BIN_LIFETIME).
- MariaDB: Same 12-month assumption: 0.5 GiB database / 12 = 0.0417, rounded up to 0.042.
- MariaDB: Same 12-month assumption: 1 GiB database / 12 = 0.0833, rounded up to 0.084.
Upgrade and rollback
How to move to a new version safely, and how to go back if it fails.
Back up first
Back up the database (mariadb-dump of bookstack) and the /config volume, which holds .env, uploaded images, attachments and themes, before updating. [2][19][20]
Upgrade steps
- Read the Version Specific Instructions on the BookStack updates page for every release between yours and the target; only the latest version gets fixes. [20][24]
- Set the new pinned linuxserver.io tag (v<version>-ls<build>) in the Compose file, then run docker compose pull and docker compose up -d. On every start the image runs php artisan migrate --force, so database changes apply by themselves. [4][20][28]
- If pages look stale after the update, clear the caches: docker compose exec bookstack php /app/www/artisan cache:clear (and config:clear, view:clear). [3][20]
- For a new MariaDB image, change its pinned tag the same way; across major versions set MARIADB_AUTO_UPGRADE so mariadb-upgrade updates the system tables. [39]
Roll back
BookStack documents no downgrade: stop the stack, restore the database dump and the /config backup taken before the update, and pin the previous image tag. [4][19][20]DerivedThe update guide says to back up first to prevent data loss, and the image migrates the database forward on start, so an older image cannot use the updated schema; restoring the backup is the way back.
Known breaking changes
- In v26.09: APP_KEY must be set: BookStack no longer falls back to a default key and errors instead. The template always sets it from .env. [20]
- In v26.05: Revision access became a separate role permission, so some users may lose access to page revisions after the update. PDF export needs storage/fonts to be writable. [20]
- In v25.12: Minimum database raised to MySQL 8.0 or MariaDB 10.6; older versions are no longer tested or supported. [17][20]
- In v25.11: Large database structure changes: take a good backup first and allow minutes, not seconds, for the migration on large instances. [20]
Limits
- The image's PHP-FPM pool allows 5 workers (pm.max_children 5) with a 128 MB memory_limit, so at most 5 page requests are processed at once. More needs a larger pool in /config/php/www2.conf and more RAM. [29][30][33]
- No mail server is configured, so invitations, password resets and notifications are not sent until MAIL_* (SMTP) settings are added to the environment or to /config/www/.env. [2][22][25]
- Uploads are limited to 50 MB per file by BookStack (FILE_UPLOAD_SIZE_LIMIT); the image raises PHP's upload and post limits to 100 MB. [4][25]
- BookStack has no official image: this is the community linuxserver.io image the BookStack docs list first. MariaDB runs with its default 128 MiB buffer pool; at medium and heavy, raise innodb_buffer_pool_size as the presets assume. [1][17][36]
Security
- A new instance has the default admin login [email protected] with the password password. Change both right after the first login, before the URL is reachable by anyone else (local mode and an SSH tunnel are safe for that first step). [2][17][18]
- APP_KEY is a credential: it encrypts MFA secrets, cookies and sessions. Keep it secret and with your backups; a changed key breaks MFA logins until users set MFA up again. [18][19]
- Uploaded images are public to anyone who knows their URL (STORAGE_TYPE local). For private content, enable higher security image uploads or use local_secure or local_secure_restricted. [18][21]
- Behind a proxy, set APP_URL to the https address and trust only the proxy in APP_PROXIES. Webhooks may call any host by default (ALLOWED_SSR_HOSTS *); restrict it if editors are not fully trusted. [18][25]
- Do not publish MariaDB port 3306; keep it on the internal network. The BookStack DB user gets access to its own database only, and the root password is random. [18][39]
Backup
- Back up both parts: the database records and the files. Database: a logical dump of the bookstack database with mariadb-dump (the docs use mysqldump), not a copy of live data files. [19][38]
- Files: the /config volume, above all www/.env, www/uploads (images), www/files and www/images (attachments and stored images) and www/themes, which the image maps to BookStack's .env, public/uploads, storage/uploads and themes. [2][19]
- Keep BOOKSTACK_APP_KEY with the backup and restore the same key. On a restore, load the database before the BookStack container starts; at a new URL, run the Update System URL command. [18][19][23]
Latest release
- This profile was checked against
BookStack v26.09.1
This profile was checked against the newest release.
- Checked on
- 14 Oct 2026
- State
- Checked within the last 90 days
- Where releases are published
- Project site
Version
- Profile status
- Published
- Checked against release
- BookStack v26.09.1
- Profile version
- 1.0.0
- Figures verified
- 14 Oct 2026
- Catalog release
- 2026.10.10
- Sizing policy
- 2026.10.0
- Compose file
- Unverified
Project and alternatives
- Official site
- www.bookstackapp.com
- Source code
- codeberg.org/bookstack/bookstack
Sources
- BookStack devops: lsio-docker/docker-compose.yml (linuxserver bookstack + mariadb, APP_URL, APP_KEY, DB_*, /config volume, 6875:80) (Official Compose · read 14 Oct 2026)
- linuxserver/docker-bookstack README at e6221fc (default admin login, env vars, /config path mapping, QUEUE_CONNECTION, changelog) (Community · read 14 Oct 2026)
- linuxserver/docker-bookstack Dockerfile at e6221fc (alpine-nginx base, PHP 8.5, memcached, /config symlinks, EXPOSE 80 443, VOLUME /config, no HEALTHCHECK) (Community · read 14 Oct 2026)
- linuxserver/docker-bookstack init-bookstack-config/run: halts without APP_KEY, waits for DB_HOST, runs artisan migrate --force, chowns /config to abc (Community · read 14 Oct 2026)
- linuxserver/docker-bookstack init-hook: the queue worker service starts only when QUEUE_CONNECTION is set (Community · read 14 Oct 2026)
- linuxserver/docker-bookstack svc-queue-worker/run: php artisan queue:work as abc (s6-setuidgid) (Community · read 14 Oct 2026)
- linuxserver/docker-bookstack AGENTS.md: do not add HEALTHCHECK or USER; the base image owns init and starts as root (Community · read 14 Oct 2026)
- linuxserver/docker-baseimage-alpine-nginx 3.24: default site conf (listen 80, 443 ssl and 443 quic) (Community · read 14 Oct 2026)
- linuxserver/docker-baseimage-alpine-nginx 3.24 init-keygen/run: self-signed certificate in /config/keys (Community · read 14 Oct 2026)
- linuxserver/docker-bookstack svc-memcached/run: memcached -u abc with default options (Community · read 14 Oct 2026)
- memcached(1) man page: -m default 64 MB, -p TCP port default 11211, -l default INADDR_ANY (Official docs · read 14 Oct 2026)
- BookStack v26.09.1 app/Settings/StatusController.php: GET /status checks database, cache and session, 500 on failure (Official repository · read 14 Oct 2026)
- BookStack v26.09.1 app/Config/app.php: key from APP_KEY, cipher AES-256-CBC, url from APP_URL, proxies from APP_PROXIES (Official repository · read 14 Oct 2026)
- BookStack v26.09.1 TrustProxies middleware: APP_PROXIES split on commas, X-Forwarded-For/Host/Port/Proto trusted (Official repository · read 14 Oct 2026)
- Laravel 12.x docs: Requests, Configuring Trusted Proxies (IPs and CIDR ranges such as 10.0.0.0/8) (Official docs · read 14 Oct 2026)
- MariaDB docs: Using Healthcheck.sh (--connect --innodb_initialized) (Official docs · read 14 Oct 2026)
- BookStack docs: Installation (requirements PHP 8.2+, MySQL 8.0+ or MariaDB 10.6+; community Docker images: LinuxServer.io first, then solidnerd; default admin login; /status health endpoint) (Official docs · read 14 Oct 2026)
- BookStack docs: Security (change [email protected], APP_URL, trusted proxies, APP_KEY is a 32-byte credential) (Official docs · read 14 Oct 2026)
- BookStack docs: Backup and Restore (mysqldump, .env, public/uploads, storage/uploads, themes; keep APP_KEY) (Official docs · read 14 Oct 2026)
- BookStack docs: Updating BookStack (back up first, artisan migrate, version-specific instructions) (Official docs · read 14 Oct 2026)
- BookStack docs: File Upload Storage (local images are public; local_secure and local_secure_restricted) (Official docs · read 14 Oct 2026)
- BookStack docs: Email & Webhooks (SMTP settings; async action handling with QUEUE_CONNECTION=database and a queue worker) (Official docs · read 14 Oct 2026)
- BookStack docs: Commands (create an admin user, update system URL, delete page revisions) (Official docs · read 14 Oct 2026)
- BookStack project FAQ: MIT license; no official managed hosting service; only the latest version is supported (Official docs · read 14 Oct 2026)
- BookStack v26.09.1 .env.example.complete (CACHE_DRIVER file, QUEUE_CONNECTION sync, REVISION_LIMIT 100, RECYCLE_BIN_LIFETIME 30, FILE_UPLOAD_SIZE_LIMIT 50, ALLOWED_SSR_HOSTS *) (Official repository · read 14 Oct 2026)
- BookStack releases on Codeberg (v26.09.1 of 2026-09-29 is the latest) (Release notes · read 14 Oct 2026)
- Codeberg API: latest BookStack release (tag v26.09.1) (Release notes · read 14 Oct 2026)
- Docker Hub tags of linuxserver/bookstack (v26.09.1-ls288 newest build on 2026-10-14; version-v26.09.1 and latest move with each build) (Community · read 14 Oct 2026)
- linuxserver/bookstack:v26.09.1-ls288 amd64: 115,431,525 B compressed, 434,337,792 B unpacked (11 layers); has curl, pm.max_children 5, memory_limit 128M; no User, no Healthcheck (Measurement · read 14 Oct 2026)
- linuxserver/docker-baseimage-alpine-nginx 3.24 init-php/run: /config/php/php-local.ini and /config/php/www2.conf override php.ini and www.conf (Community · read 14 Oct 2026)
- linuxserver/docker-baseimage-alpine 3.24 init-adduser/run: user abc set to PUID/PGID (default 911) at start (Community · read 14 Oct 2026)
- linuxserver.io docs: Understanding PUID and PGID (Community · read 14 Oct 2026)
- PHP manual: FPM configuration (pm.max_children is the maximum number of child processes) (Official docs · read 14 Oct 2026)
- PHP manual: OPcache runtime configuration (opcache.memory_consumption default 128 MB) (Official docs · read 14 Oct 2026)
- Docker: containerd image store is the default on fresh Engine 29+ installs and keeps images compressed and uncompressed (Official docs · read 14 Oct 2026)
- MariaDB docs: InnoDB system variables (buffer pool default 128 MiB, innodb_log_file_size default 96 MB) (Official docs · read 14 Oct 2026)
- MariaDB docs: MariaDB Memory Allocation (Official docs · read 14 Oct 2026)
- MariaDB docs: Container Backup and Restoration (Official docs · read 14 Oct 2026)
- Docker Official Image mariadb: documentation (Official docs · read 14 Oct 2026)
- docker-library official-images: mariadb tags (12.3.3 = lts) (Official repository · read 14 Oct 2026)
- Docker Hub: mariadb:12.3.3 (linux/amd64 107,837,515 B compressed) (Official repository · read 14 Oct 2026)
- MariaDB/mariadb-docker 12.3 Dockerfile: groupadd -r mysql / useradd -r mysql on ubuntu:noble without fixed IDs, gosu (Official repository · read 14 Oct 2026)
- MariaDB/mariadb-docker 12.3 docker-entrypoint.sh: chowns the datadir to mysql, then exec gosu mysql (Official repository · read 14 Oct 2026)
- shadow-maint/shadow lib/find_new_uid.c: system IDs taken in SYS_UID_MIN..SYS_UID_MAX (default 999), searched from the top (Official repository · read 14 Oct 2026)