Use case · Documentation wiki

BookStack self hosted on a dedicated server: install, lock down, back up

Self-hosting BookStack takes PHP 8.2 or newer, MySQL 8.0 or MariaDB 10.6 or newer, and a web server pointed at the app's public folder; on a fresh Ubuntu machine the project's own install script sets up all three. The work that matters comes after: the first admin login before the site is reachable, APP_URL, mail, and a backup that covers both the database and the uploads folders.

See the machines

What BookStack requires

BookStack is a PHP application on the Laravel framework that keeps its content in one MySQL or MariaDB database and its uploads on the local disk. The installation page lists the stack below.

ComponentDocumented requirement
PHP8.2 or newer, runnable from the command line; extensions curl, dom, gd, iconv, mbstring, mysqlnd, openssl, pdo, pdo_mysql, tokenizer, xml, zip
DatabaseMySQL 8.0+ or MariaDB 10.6+, one database, full rights on it because the app manages its own schema
ToolingGit for the standard update process; Composer 2.2.0+ for PHP dependencies
Web serverAny PHP-capable server, with its root set to the public folder
Optionalldap for LDAP login, exif for correct image rotation

The docs publish no CPU or memory figure. Our reading, not theirs: a team wiki is a light PHP-plus-database load, so the disk that holds uploads and backups, and the ease of recovering the box, decide the machine more than core count does. Shared PHP hosting is out; the project says it does not support it.

Script, manual or Docker

RouteWhat it doesFirst admin
Ubuntu 26.04 scriptApache, MySQL 8.4, PHP 8.5, clone of the release branch, vhost on port 80Your email, random 16-character password printed at the end
Ubuntu 24.04 / 22.04 scriptApache, MySQL 8.0, PHP 8.3 (24.04) or 8.4 (22.04)admin@admin.com / password
Manual installgit clone, composer install --no-dev, .env, key:generate, migrateadmin@admin.com / password
DockerCommunity images (linuxserver.io, solidnerd), not maintained by the projectCheck the image; treat the first account as public until changed

Every script is for a fresh OS only: it may overwrite an existing web setup, and it configures neither mail nor system security. That suits a dedicated machine you can reinstall from the control panel before you start. On the Docker route, the project's example compose file publishes 6875:80; Docker writes that rule around ufw, so a ufw deny does not stop it. Change it to 127.0.0.1:6875:80 and put a proxy in front. The example also carries a sample APP_KEY and database passwords: generate your own, and keep the compose file mode 600.

Installing on Ubuntu 26.04

  1. Firewall first, SSH only. Ubuntu's /etc/default/ufw ships with IPV6=yes; confirm it, so the same rules cover the v6 address.
  2. Download the script and read it before running anything. It is about 280 lines of plain bash: apt installs, a database user limited to the bookstack database, the clone into /var/www/bookstack, an Apache vhost.
  3. If the machine only has root, create your own user first (adduser you and usermod -aG sudo you), then log in as that user. Run the script with bash through sudo from that login, not a root shell. It sets file ownership to $SUDO_USER, so later updates run as you. Pass the hostname and the admin email as arguments.
  4. Note the login password printed at the end. The script prints it to the terminal; the log file it writes in the current directory gets the email, not the password.
sudo ufw allow OpenSSH
sudo ufw enable
grep IPV6 /etc/default/ufw

wget https://codeberg.org/bookstack/devops/raw/branch/main/scripts/installation-ubuntu-26.04.sh
less installation-ubuntu-26.04.sh
sudo bash installation-ubuntu-26.04.sh docs.example.com you@example.com

Never pipe an install script from the network straight into a shell. Download it, read it, then run the file you read.

First login before the port opens

Apache now listens on port 80, but ufw still drops it, so nobody outside can reach the login form. BookStack builds its redirects from APP_URL, which the script set to http://docs.example.com; point it at the tunnel for this one session, then log in from your laptop through SSH.

# on the server
sudo sed -i 's|^APP_URL=.*|APP_URL=http://localhost:8080|' /var/www/bookstack/.env

# on your laptop, then browse to http://localhost:8080
ssh -L 8080:127.0.0.1:80 you@203.0.113.10
  1. Log in, change the admin password, and set up multi-factor authentication (TOTP or backup codes) on the account.
  2. On a 24.04 or manual install the account is admin@admin.com with password password: change both the email and the password now, as the security page instructs.
  3. In Settings, check that registration is off and that Allow public viewing? matches what you want. It also switches the robots.txt rules.
  4. Review the roles. Tick Requires Multi-Factor Authentication on the Admin role if every admin must use it.
  5. Upload nothing yet. If you did, run php artisan bookstack:update-url http://localhost:8080 https://docs.example.com after the next step.

Going live: DNS, TLS, APP_URL

Point the DNS record at the server and open the web ports with sudo ufw allow 'Apache Full' (it covers 80 and 443 on both address families; the admin account is already locked down). Then add a certificate to the Apache site with the tool you already use (Let's Encrypt's HTTP challenge needs port 80 open), and set APP_URL=https://docs.example.com in .env. The security page asks for APP_URL so that generated links cannot be manipulated, and an https APP_URL turns on secure-only cookies by itself.

  • Images are publicly reachable by URL by default. Enable higher security image uploads in Settings to add a 16-character random string to each file name. Attachments sit behind login.
  • Set LOG_FAILED_LOGIN_MESSAGE="Failed login for %u" to log failed logins for Fail2Ban.
  • Behind a reverse proxy, list it in APP_PROXIES or the audit log records the proxy's address for everyone.
  • Set .env to 640 (sudo chmod 640 /var/www/bookstack/.env; the script leaves it at 740), as the permissions page suggests: it holds the database password, APP_KEY and the SMTP login.

Outgoing mail

Invites, email confirmation and password resets all need mail, and the script leaves it unset. Put the SMTP values in .env: MAIL_HOST, MAIL_PORT=587, MAIL_ENCRYPTION=tls, MAIL_USERNAME, MAIL_PASSWORD, MAIL_FROM and MAIL_FROM_NAME, with MAIL_DRIVER=smtp (sendmail is the alternative). Editing the file keeps the password out of shell history. Then use Send a Test Email under Settings > Maintenance, which shows the error if sending fails. If notifications slow page saves, the email docs describe QUEUE_CONNECTION=database with a systemd queue worker.

Backups and updates

BookStack has no built-in backup. The backup page names two halves: a mysqldump of the database, and the files .env, public/uploads (images), storage/uploads (attachments) and themes. Keep the old APP_KEY with them: multi-factor secrets are encrypted with it. Save the lines below as /usr/local/sbin/bookstack-backup.sh and run it from root's cron with bash; root reaches MySQL on Ubuntu through the socket, so no password goes on a command line.

# /usr/local/sbin/bookstack-backup.sh
set -eu
umask 077
D=/var/backups/bookstack
mkdir -p "$D"
cd /var/www/bookstack
mysqldump -u root bookstack > "$D/db-$(date +%F).sql"
tar -czf "$D/files-$(date +%F).tar.gz" .env public/uploads storage/uploads themes
find "$D" -type f -mtime +14 -delete

# /etc/cron.d/bookstack-backup
30 2 * * * root bash /usr/local/sbin/bookstack-backup.sh

Copy the folder to another machine; a backup on the same disk is not one. To update, back up first, then from /var/www/bookstack as your own user run git pull origin release, php bookstack-system-cli download-vendor (the 26.04 script's method, still marked beta in the docs; composer install --no-dev on older installs) and php artisan migrate, then clear the caches with php artisan cache:clear, config:clear and view:clear. Read the version notes first: v26.09 errors out when APP_KEY is unset, and several recent releases are security fixes.

Which machine, and when not to

Our dedicated server range puts this in the single-socket class: one processor in its own chassis with its own out-of-band console, the usual base for a web or application server with its database on the same box. The console (HPE iLO, Dell iDRAC or a Supermicro BMC) is the way back in when a ufw rule locks out SSH. A Moonshot cartridge also fits a one-service wiki, but most cartridges have power control only, no console. Every line has root, an unmetered port and month-to-month terms; IPv6 is added at checkout at no charge. A racked machine is handed over in about 30 minutes once payment is approved, and the ready servers list shows what is on the shelf.

Self-hosting is the wrong call if nobody will apply updates: the release notes read as a list of security fixes. The same machine can carry the team's code next to its docs, as in the Gitea use case, or a scanned-paper archive, as in Paperless-ngx.

Questions

What is the default BookStack login?

On a manual install and with the Ubuntu 24.04 and 22.04 scripts, the first account is admin@admin.com, password password. The Ubuntu 26.04 script instead takes an email address you supply and generates a 16-character password. Docker images document their own first login. Either way, change it before the site is reachable from the internet.

Can I run BookStack in Docker?

Yes, through community images: linuxserver.io and solidnerd are the two the docs link, and the project points to an example compose file. They are not maintained by the BookStack project. Bind the published port to 127.0.0.1 and put a TLS proxy in front, because Docker's port rules bypass ufw.

How much RAM does a BookStack server need?

The official docs do not give a memory or CPU figure. They specify software: PHP 8.2+, MySQL 8.0+ or MariaDB 10.6+, Composer and a web server. Size the disk for uploads plus local backups, and pick memory for the database and PHP together.

I forgot the admin password. How do I get back in?

From the install directory run php artisan bookstack:create-admin; without options it asks for the details interactively, which keeps the password off the command line. The docs call it a good last resort when you are locked out.

Do I need to change anything when the domain changes?

Yes, two things. Set APP_URL in .env to the new base URL, and run php artisan bookstack:update-url with the old and new URLs, because image links are stored as absolute URLs in the database. Take a database backup before running it.

A whole machine for the team's documentation

Pick a line, install Ubuntu, and run the script you have read.

See the machines

Related on Server Room

Other use cases