Why self-host BookStack on a VPS
BookStack stands out for its simplicity: where other wikis overwhelm the user with options, it enforces a clear hierarchy — shelves, books, chapters, pages — that makes documentation immediately navigable. Built on Laravel, it is lightweight and easy to maintain. Self-hosted on a VPS, it keeps all your internal documentation — procedures, runbooks, customer knowledge base — on your own infrastructure, with no per-user subscription. For an agency documenting its projects or a technical team centralizing its procedures, it is a private wiki you control end to end, with full-text search, fine-grained permission management and a WYSIWYG or Markdown editor.
Concrete benefits of a self-hosted BookStack
- Clear structure of shelves/books/chapters/pages: effortlessly navigable documentation.
- WYSIWYG and Markdown editor of your choice, with integrated Draw.io diagrams.
- Granular permissions by role and by book to partition sensitive content.
- Fast full-text search across the entire knowledge base.
- LDAP, SAML or OAuth authentication to integrate with your enterprise directory.
- Lightweight footprint: a VPS with 2 GB of RAM is enough for team documentation.
- No per-user subscription — as many contributors as needed at no extra cost.
Hardware and software prerequisites
BookStack is undemanding. A VPS with 1 to 2 vCPU and at least 2 GB of RAM comfortably hosts a team's documentation; with BookStack and MariaDB running together, 2 GB is the recommended minimum — below that, Laravel migrations on first startup can fail due to out-of-memory. Consumption climbs mainly with the volume of uploaded images.
Plan for 15 to 25 GB of SSD depending on the volume of attachments. On the software side: Docker 24+ and the Compose v2 plugin (docker compose without a hyphen), a wiki.yourdomain.com subdomain with an A record, and SMTP access for invitations and email notifications.
BookStack vs self-hosted alternatives
Scroll the table
| Tool | Stack | Min. RAM | Strength |
|---|---|---|---|
| BookStack | Laravel + MariaDB | 2 GB | Book/chapter hierarchy, WYSIWYG |
| Wiki.js | Node.js + any DB | 512 MB | Modern editor, Git sync |
| Outline | Node.js + PostgreSQL | 1 GB | Notion-like UI, rich API |
| Confluence | SaaS / on-premise | 4 GB+ | Atlassian integration, mature |
Deploy BookStack with Docker Compose and SSL
Prepare the VPS and install Docker
Connect via SSH then install Docker and the Compose plugin:
curl -fsSL https://get.docker.com | sh apt install docker-compose-plugin mkdir -p /opt/bookstack && cd /opt/bookstackVerify:
docker compose versionshould show v2.x or higher. The community imagelscr.io/linuxserver/bookstackis the most widely used and best maintained for containerized deployment.Create the docker-compose.yml file
Create
/opt/bookstack/docker-compose.ymlwith two services — MariaDB and BookStack — on a dedicated network:services: mariadb: image: mariadb:10.11 environment: MYSQL_ROOT_PASSWORD: changeme_root MYSQL_DATABASE: bookstack MYSQL_USER: bookstack MYSQL_PASSWORD: changeme_bk volumes: - ./data/mariadb:/var/lib/mysql networks: [bookstack] bookstack: image: lscr.io/linuxserver/bookstack:latest environment: PUID: 1000 PGID: 1000 APP_URL: https://wiki.yourdomain.com DB_HOST: mariadb DB_USER: bookstack DB_PASS: changeme_bk DB_DATABASE: bookstack MAIL_DRIVER: smtp MAIL_HOST: smtp.yourdomain.com MAIL_PORT: 587 MAIL_FROM: [email protected] MAIL_USERNAME: [email protected] MAIL_PASSWORD: your_smtp_password ports: - "6875:80" volumes: - ./data/bookstack:/config depends_on: [mariadb] networks: [bookstack] networks: bookstack:APP_URLmust exactly match the final HTTPS URL. An incorrect value breaks internal links and uploads.Start the stack and check logs
docker compose up -d docker compose logs -f bookstackOn first startup, BookStack automatically runs the Laravel migrations to create the database schema. Wait for the line
Server running on http://0.0.0.0:80before continuing — this takes 30 to 60 seconds.Configure reverse proxy and SSL
With Caddy (automatic certificate management):
wiki.yourdomain.com { reverse_proxy localhost:6875 }Reload Caddy:
systemctl reload caddy.With Nginx + Certbot:
server { listen 80; server_name wiki.yourdomain.com; return 301 https://$host$request_uri; } server { listen 443 ssl; server_name wiki.yourdomain.com; ssl_certificate /etc/letsencrypt/live/wiki.yourdomain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/wiki.yourdomain.com/privkey.pem; location / { proxy_pass http://127.0.0.1:6875; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }Obtain the certificate with
certbot --nginx -d wiki.yourdomain.com.First login and securing the admin account
Open
https://wiki.yourdomain.com. The default account is[email protected]with the passwordpassword. Change them immediately under Settings → Profile.Then verify that SMTP works: Settings → Email configuration → Send a test email. If the test fails, check the logs:
docker compose logs bookstack | grep -i mail.
Advanced configuration: SSO, LDAP and SAML
BookStack supports several centralized authentication mechanisms, configurable via environment variables in docker-compose.yml.
LDAP / Active Directory: add the variables AUTH_METHOD=ldap, LDAP_SERVER, LDAP_BASE_DN, LDAP_USER_FILTER and LDAP_VERSION. Users then sign in with their corporate credentials without a separate BookStack account.
SAML 2.0 (for providers such as Authentik, Keycloak or Azure AD): set AUTH_METHOD=saml2 and fill in SAML2_IDP_ENTITYID, SAML2_IDP_SSO and SAML2_IDP_SLO. The official BookStack documentation provides examples per provider.
Social OAuth (GitHub, Google, Slack): each provider has its own *_APP_ID / *_APP_SECRET variable pair. This option suits teams that want to avoid managing passwords without deploying an LDAP server.
Backing up and restoring BookStack
A BookStack instance rests on three elements: the MariaDB database, the uploads folder (images and attachments) and the APP_KEY value in the configuration. Without the APP_KEY, encrypted content is unrecoverable after restoration.
Daily backup script to place in /etc/cron.daily/bookstack-backup:
#!/bin/bash
BACKUP_DIR=/var/backups/bookstack
mkdir -p $BACKUP_DIR
DATE=$(date +%Y%m%d)
docker exec $(docker ps -qf name=mariadb) \
mysqldump -u bookstack -pchangeme_bk bookstack \
> $BACKUP_DIR/bookstack-db-$DATE.sql
tar -czf $BACKUP_DIR/bookstack-uploads-$DATE.tar.gz /opt/bookstack/data/bookstack/uploads
find $BACKUP_DIR -mtime +14 -deleteThen copy these archives to external storage (S3, Backblaze B2, or your VPS object storage). Keep the APP_KEY in a secrets manager off the server — it is the only element that cannot be recreated.
Troubleshooting: common errors
A few errors come up regularly during a fresh installation or an update.
Frequent issues and solutions
- SMTP error 'Connection refused' or timeout: check that
MAIL_PORTmatches the actual port (587 for STARTTLS, 465 for SSL). Some SMTP servers block outgoing port 25. Test connectivity from the container:docker exec -it bookstack curl -v telnet://smtp.yourdomain.com:587. - Permissions on
storage/: 500 error or blank page: the/opt/bookstack/data/bookstackfolder must be owned by UID 1000 (thePUIDvariable). Fix withchown -R 1000:1000 /opt/bookstack/data/bookstackthen restart the container. - Slowness or MariaDB timeout at startup: BookStack waits for MariaDB to be ready. If the BookStack container restarts in a loop during the first seconds, that is normal. Add a
healthcheckto themariadbservice in the Compose file or wait 30 seconds before inspecting logs. - Images not displaying after a domain change:
APP_URLmust exactly match the public HTTPS URL. If you change domains, updateAPP_URLin the Compose file, restart the container, then runphp artisan bookstack:update-urlfrom inside the container to update the URLs stored in the database. - Migrations hang on first startup (OOM): if the VPS has less than 2 GB of RAM, Laravel migrations can be killed by the OOM killer. Add a 2 GB swap file (
fallocate -l 2G /swapfile && mkswap /swapfile && swapon /swapfile) or increase the VPS RAM before retrying.
Updating BookStack
The lscr.io/linuxserver/bookstack:latest image receives new versions shortly after their publication on GitHub. To update:
cd /opt/bookstack
docker compose pull
docker compose up -d
docker compose logs -f bookstackDatabase migrations are applied automatically on startup. Check the BookStack release notes before any major update: some versions introduce schema or configuration changes.
Security tip
Configure a robots.txt entry or protect your BookStack instance behind a web application firewall if it contains sensitive internal procedures. BookStack does not offer an 'intranet-only' mode by default — the public URL is accessible to anyone who knows the address. For truly private documentation, combine BookStack's granular permissions with a UFW rule or a WireGuard VPN that restricts access to port 443.
Further reading
- Host Nextcloud on a VPS — cloud storage and document collaboration.
- Host Gitea on a VPS — self-hosted Git forge for your development teams.
- Authentik on a VPS — open source SSO to centralize authentication for BookStack and your other apps.