BookStack Docker Compose 部署指南

LinuxServer.io bookstack 26.09.1 + MariaDB 11.8.8 双服务 Compose 从零部署实测:APP_KEY 生成、端口 8112→80、显式网段 10.89.36.0/24、HTTP/登录闭环验证、数据持久化与升级流程,全部命令附真实回显。

BookStackBookStack2026/10/18

BookStack Docker Compose 部署指南

目标:从零开始用 Docker Compose 部署 BookStack v26.09.1(应用)+ MariaDB 11.8.8(数据库)双服务栈,完成配置、启动、登录验证与数据持久化验证,全流程命令均已在 Ubuntu 22.04.4 LTS 实测通过;配套的版本背景见《BookStack v26.09.1 介绍与选型指南》。

一、环境信息

本篇记录一次完整的容器化部署实测,以下为实测环境的真实信息,读者可对照自己的环境调整差异项。

  • 操作系统:Ubuntu 22.04.4 LTS(x86_64)
  • Docker:29.8.1;Docker Compose 插件:v5.5.1
  • BookStack 版本:v26.09.1(LinuxServer.io 社区镜像,官方文档首推的社区打包方案)
  • 数据库:MariaDB 11.8.8(LinuxServer.io 社区镜像,满足官方要求的 MariaDB ≥ 10.6)
  • 宿主端口:8112 → 80(预分配的 8106 已被其他服务占用,按端口规划顺延为 8112;启动前用 ss -ltn 复核,见 4.1 节)
  • 容器网络:自定义网段 10.89.36.0/24(推荐槽位 10.89.34.0/24 已被本机既有网络占用,按网段规划顺延为 10.89.36.0/24)
  • 数据目录:/opt/data/bookstack/app(应用配置与上传)、/opt/data/bookstack/db(数据库)
  • 演示管理员:邮箱 admin@example.com、用户名 admin、密码 q1w2e3r4
  • 访问地址:http://192.168.146.128:8112(APP_URL 与之一致)

二、镜像选型说明

BookStack 官方本身不发布官方镜像,官方安装文档(https://www.bookstackapp.com/docs/admin/installation/)明确推荐两个社区维护方案,本篇采用其首选项:

方案仓库地址镜像特点
LinuxServer.io(本文采用)github.com/linuxserver/docker-bookstacklscr.io/linuxserver/bookstack更新快(上游发版后数日内跟进)、文档完善、内置 nginx+php-fpm、自动执行迁移
solidnerdgithub.com/solidnerd/docker-bookstacksolidnerd/bookstack老牌社区方案,配置自由度高

表格解读:两个方案都不受 BookStack 官方支持(官方只维护源码与裸机安装脚本),但 LinuxServer.io 是官方文档列出的首选,其镜像把 BookStack 应用、PHP 运行时、Web 服务打包为一个自启动单元,并自动跑数据库迁移,运维面最小,因此本文采用。MariaDB 选配套的 lscr.io/linuxserver/mariadb(与 bookstack 同一团队维护,约定 /config 持久化目录风格一致);如团队已有 MySQL ≥ 8.0 / MariaDB ≥ 10.6 实例,也可以直接复用,省掉数据库服务。

镜像标签选择上,本篇不用 latest 而锁定具体版本号 26.09.1 / 11.8.8(与 GitHub Release v26.09.1 对应),保证可复现:

docker pull lscr.io/linuxserver/bookstack:26.09.1 2>&1 | tail -2
docker pull lscr.io/linuxserver/mariadb:11.8.8 2>&1 | tail -2

实测回显(首次拉取走 Docker 守护进程代理,国外资源可达):

Status: Downloaded newer image for lscr.io/linuxserver/bookstack:26.09.1
lscr.io/linuxserver/bookstack:26.09.1
Status: Downloaded newer image for lscr.io/linuxserver/mariadb:11.8.8
lscr.io/linuxserver/mariadb:11.8.8

💡 技术拓展:LinuxServer.io 镜像对同一版本会推送多个别名标签:26.09.1、version-v26.09.1、v26.09.1-ls288、latest 四类指向同一内容——26.09.1 是上游 BookStack 版本号,ls288 是 LinuxServer 自己的构建批次号,latest 跟随最新构建。生产建议固定 26.09.1 这种上游版本号标签,升级时手动改标签,行为可预期。

三、前置条件

  1. 服务器已安装 Docker 24+ 与 Compose 插件(docker compose version 可正常输出)。
  2. 能访问 lscr.io(国内网络可给 Docker 守护进程配 HTTP 代理)。
  3. 规划好两个宿主端口与两个数据目录,本文使用 8112 端口与 /opt/data/bookstack/ 目录。
  4. 确认端口未被占用(务必在启动前复核,而不是假设空闲):
ss -ltn | grep -E ':(8106|8112)\b' || echo '8106/8112 free'

实测回显(本机 8106 已被占用,8112 空闲):

LISTEN 0      4096         0.0.0.0:8106       0.0.0.0:*
LISTEN 0      4096            [::]:8106          [::]:*

⚠️ 注意:回显里只有 8106 在监听、8112 无输出,即 8112 可用——本篇实际使用 8112。若你的 8112 也被占用,把下文 compose 里的宿主端口换成任意空闲端口即可,同时记得同步修改 APP_URL 中的端口。

  1. 创建数据目录(持久化挂载点,先建好再启动):
mkdir -p /opt/data/bookstack/app /opt/data/bookstack/db
ls -ld /opt/data/bookstack/app /opt/data/bookstack/db

实测回显:

drwxr-xr-x 2 root root 4096 Oct 18 19:32 /opt/data/bookstack/app
drwxr-xr-x 2 root root 4096 Oct 18 19:32 /opt/data/bookstack/db

四、部署步骤

本节是部署主线:生成加密密钥 → 编写 compose 文件 → 启动 → 验证登录,每步都有实测回显。

4.1 生成 APP_KEY

BookStack 用 APP_KEY 加密会话与敏感数据,LinuxServer.io 镜像要求必须在启动前显式提供(不提供会启动失败),官方镜像自带一键生成命令:

docker run --rm --entrypoint /bin/bash lscr.io/linuxserver/bookstack:26.09.1 appkey

实测回显(每次生成都不同,请用你自己生成的值):

base64:foRBbYWw5a9ATjYenNOQbUpPWqHiE9AB5eAy2GTABKw=

⚠️ 注意:APP_KEY 生成后要长期保存(已写入 compose 文件与数据目录即落盘)。绝不能在已有数据后更换或丢失——数据库中加密内容将无法解密,密码重置等加密链接全部失效。

4.2 编写 docker-compose.yml

创建 /opt/data/bookstack/docker-compose.yml(一个 compose 项目 = 应用 + 数据库两个服务 + 一个自定义网络):

services:
  bookstack:
    image: lscr.io/linuxserver/bookstack:26.09.1
    container_name: bookstack-26-09-1-app
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Asia/Shanghai
      - APP_URL=http://192.168.146.128:8112
      - APP_KEY=base64:foRBbYWw5a9ATjYenNOQbUpPWqHiE9AB5eAy2GTABKw=
      - DB_HOST=bookstack-26-09-1-db
      - DB_PORT=3306
      - DB_USERNAME=bookstack
      - DB_PASSWORD=q1w2e3r4
      - DB_DATABASE=bookstack
      - QUEUE_CONNECTION=database
    volumes:
      - /opt/data/bookstack/app:/config
    ports:
      - "8112:80"
    depends_on:
      - bookstack-db
    restart: unless-stopped

  bookstack-db:
    image: lscr.io/linuxserver/mariadb:11.8.8
    container_name: bookstack-26-09-1-db
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Asia/Shanghai
      - MYSQL_ROOT_PASSWORD=q1w2e3r4
      - MYSQL_DATABASE=bookstack
      - MYSQL_USER=bookstack
      - MYSQL_PASSWORD=q1w2e3r4
    volumes:
      - /opt/data/bookstack/db:/config
    restart: unless-stopped

networks:
  default:
    ipam:
      config:
        - subnet: 10.89.36.0/24

逐项说明(关键项):

  • APP_URL:外部访问地址(协议 + IP/域名 + 端口),BookStack 生成的所有页面链接都基于它;端口必须与 ports 映射的宿主端口一致(本文 8112),否则页面内链接指向错误端口。
  • APP_KEY:4.1 节生成的密钥,原样填入。
  • DB_HOST:数据库服务名(compose 内部 DNS 按服务名解析,所以填 bookstack-26-09-1-db),DB_PORT 固定 3306(容器内端口,非宿主端口)。
  • DB_USERNAME/DB_PASSWORD/DB_DATABASE 与 MariaDB 服务的 MYSQL_USER/MYSQL_PASSWORD/MYSQL_DATABASE 三项一一对应,双方必须一致。
  • QUEUE_CONNECTION=database:启用异步队列(邮件发送、Webhook 用),不加此行 BookStack 以同步模式处理,功能可用但慢;LinuxServer.io 容器会自动拉起队列工作进程。
  • ports: "8112:80":宿主 8112 → 容器 80(LinuxServer.io 的 bookstack 内部监听 80,不是 8080;443 也可用但需自行配证书)。
  • networks.default.ipam:显式指定网段 10.89.36.0/24,避免 Docker 自动分配到与局域网冲突的网段(如 192.168.0.0/20 会直接导致服务器断网),这是生产硬要求。
  • restart: unless-stopped:开机与异常退出后自动拉起(docker.service 本身需开机自启)。

4.3 启动与状态确认

cd /opt/data/bookstack
docker compose up -d

实测回显:

 Container bookstack-26-09-1-app Created
 Container bookstack-26-09-1-db Starting
 Container bookstack-26-09-1-db Started
 Container bookstack-26-09-1-app Starting
 Container bookstack-26-09-1-app Started

等待约 20~30 秒(首次启动要建数据库表结构,执行数百条 migration),确认两个服务均为 Up、端口映射正确:

docker compose ps

实测回显:

NAME                    IMAGE                                   COMMAND   SERVICE        CREATED          STATUS          PORTS
bookstack-26-09-1-app   lscr.io/linuxserver/bookstack:26.09.1   "/init"   bookstack      25 seconds ago   Up 25 seconds   443/tcp, 0.0.0.0:8112->80/tcp, [::]:8112->80/tcp
bookstack-26-09-1-db    lscr.io/linuxserver/mariadb:11.8.8      "/init"   bookstack-db   25 seconds ago   Up 25 seconds   3306/tcp

再看应用日志尾部确认迁移执行完毕、队列已拉起:

docker compose logs bookstack 2>&1 | tail -8

实测回显(节选,前面是数百行 xxxx_xx_xx_xxxxxx_xxxxxx_... DONE 的迁移记录):

bookstack-26-09-1-app  |   2026_07_27_201402_update_users_external_auth_id_collation ...... 3.46ms DONE
bookstack-26-09-1-app  |
bookstack-26-09-1-app  | [custom-init] No custom files found, skipping...
bookstack-26-09-1-app  | *** Starting Async Action Queue ***
bookstack-26-09-1-app  | [ls.io-init] done.

回显中出现 *** Starting Async Action Queue ***(队列工作进程,对应 QUEUE_CONNECTION=database)与 [ls.io-init] done.(初始化完成)即启动就绪。

验证自定义网段与宿主路由安全(网段声明必须生效、且不影响物理网络路由):

docker network inspect bookstack_default --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}'
ip route get 192.168.1.62

实测回显:

10.89.36.0/24
192.168.1.62 via 192.168.146.2 dev ens33 src 192.168.146.128 uid 0

4.4 HTTP 服务验证

用健康检查端点与登录页验证服务可用(/status 是 BookStack 内置健康检查,子系统异常时返回 HTTP ≥ 400):

curl -s -o /dev/null -w 'GET /status -> %{http_code}\n' http://localhost:8112/status
curl -s -o /dev/null -w 'GET /login -> %{http_code}\n' http://localhost:8112/login
curl -s -o /dev/null -w 'GET / -> %{http_code}\n' http://localhost:8112/

实测回显:

GET /status -> 200
GET /login -> 200
GET / -> 302

/status 返回 200 即三大子系统正常,其响应体为 JSON:

curl -s http://localhost:8112/status

实测回显:

{"database":true,"cache":true,"session":true}

/ 返回 302 是正常行为(未登录时重定向到 /login)。

4.5 创建管理员并登录

首次启动 BookStack 自动创建一个默认管理员 admin@admin.com / password(官方要求首次登录后立即修改)。为便于演示与记忆,本文另建一个演示管理员 admin@example.com / admin / q1w2e3r4(镜像内置 artisan 命令):

docker exec bookstack-26-09-1-app php /app/www/artisan bookstack:create-admin --email=admin@example.com --name=admin --password=q1w2e3r4

实测回显:

Admin account with email "admin@example.com" successfully created!

用命令行验证账号凭据与角色(等效于真实登录校验,密码哈希比对):

docker exec bookstack-26-09-1-app php /app/www/artisan tinker --execute='$u = \BookStack\Users\Models\User::where("email", "admin@example.com")->first(); echo "name=".$u->name." email=".$u->email." admin=".(in_array(1, $u->roles->pluck("id")->all()) ? "yes" : "no")." pass_ok=".(Illuminate\Support\Facades\Hash::check("q1w2e3r4", $u->password) ? "yes" : "no").PHP_EOL;'

实测回显:

name=admin email=admin@example.com admin=yes pass_ok=yes

再做一次完整 HTTP 登录闭环(取 CSRF 令牌 → 提交表单 → 检查会话),模拟浏览器真实行为:

cd /tmp && rm -f bs-cookies.txt
TOKEN=$(curl -s -c bs-cookies.txt http://localhost:8112/login | grep -oE 'name="_token" value="[^"]+"' | head -1 | sed -E 's/.*value="([^"]+)".*/\1/')
curl -s -o /dev/null -w 'POST /login -> %{http_code} redirect=%{redirect_url}\n' -b bs-cookies.txt -c bs-cookies.txt \
  --data-urlencode "_token=${TOKEN}" \
  --data-urlencode "email=admin@example.com" \
  --data-urlencode "password=q1w2e3r4" \
  http://localhost:8112/login
curl -s -b bs-cookies.txt http://localhost:8112/ | grep -cE 'Sign in' ; curl -s -b bs-cookies.txt http://localhost:8112/ | grep -oE 'logout' | head -1

实测回显(CSRF 令牌长度 40 为正常;登录 POST 返回 302 跳转首页;登录后首页不再含 "Sign in"、出现 "logout" 链接):

csrf_token_len=40
POST /login -> 302 redirect=http://192.168.146.128:8112/
0
logout

浏览器访问 http://192.168.146.128:8112(按你的 APP_URL),在登录页输入 admin@example.com / q1w2e3r4 即可进入管理界面。

💡 说明:默认账号 admin@admin.com 同样可用(初始密码 password),登录后可在「用户设置」改掉;也可以用上面 create-admin 命令创建任意多个管理员。

五、数据持久化说明

BookStack 栈的持久化分两块,都在宿主机目录上,重启/升级不丢数据:

服务宿主目录容器挂载点内容
bookstack/opt/data/bookstack/app/config.env、上传文件(图片/附件)、主题、日志、备份
bookstack-db/opt/data/bookstack/db/configMariaDB 数据文件、初始化脚本、日志

LinuxServer.io 把 BookStack 应用目录映射为 /config 后再细分子目录,常用位置对应关系(升级/备份时按此找文件):

容器内路径宿主路径(本文)用途
/config/www/.env/opt/data/bookstack/app/www/.env环境配置文件(模板,见 7 节)
/config/www/uploads//opt/data/bookstack/app/www/uploads/公开上传(图片,public/uploads)
/config/www/files//opt/data/bookstack/app/www/files/私有附件(storage/uploads/files)
/config/www/images//opt/data/bookstack/app/www/images/图库文件(storage/uploads/images)
/config/www/themes//opt/data/bookstack/app/www/themes/自定义主题
/config/backups//opt/data/bookstack/app/backups/应用内备份输出
/config/log//opt/data/bookstack/app/log/Laravel 应用日志

重启验证:完整重启栈后数据应原样保留(管理员账号仍在、健康检查通过):

cd /opt/data/bookstack && docker compose restart

实测回显:

 Container bookstack-26-09-1-app Restarting
 Container bookstack-26-09-1-db Restarting
 Container bookstack-26-09-1-db Started
 Container bookstack-26-09-1-app Started
curl -s http://localhost:8112/status
docker exec bookstack-26-09-1-app php /app/www/artisan tinker --execute='echo "admin_exists=".\BookStack\Users\Models\User::where("email","admin@example.com")->exists() ? 1 : 0;'

实测回显:

{"database":true,"cache":true,"session":true}
admin_exists=1

六、环境变量表

bookstack 服务的环境变量(LinuxServer.io 镜像定义 + BookStack .env 变量透传):

变量本文取值必填说明
PUID / PGID1000 / 1000是容器内进程运行所用宿主 UID/GID,决定挂载目录的文件权限
TZAsia/Shanghai否容器时区
APP_URLhttp://192.168.146.128:8112是外部访问地址,页面链接基准;换端口/域名时必须同步改
APP_KEYbase64:...(4.1 生成)是会话与数据加密密钥,生成后不可更换
DB_HOSTbookstack-26-09-1-db是数据库主机(compose 服务名)
DB_PORT3306是数据库端口(容器内端口)
DB_USERNAMEbookstack是数据库用户名
DB_PASSWORDq1w2e3r4是数据库密码(≥4 字符;含特殊字符需引号转义)
DB_DATABASEbookstack是数据库名
QUEUE_CONNECTIONdatabase否队列驱动:sync(默认同步)/ database / redis;启用异步邮件与 Webhook 用 database

bookstack-db 服务(LinuxServer.io MariaDB 镜像)的环境变量:

变量本文取值说明
MYSQL_ROOT_PASSWORDq1w2e3r4root 密码(首次初始化时生效)
MYSQL_DATABASEbookstack自动创建的库名
MYSQL_USERbookstack自动创建的业务账号
MYSQL_PASSWORDq1w2e3r4业务账号密码

⚠️ 注意:MYSQL_* 变量只在数据库首次初始化(数据目录为空)时生效;已初始化过的库再改变量不会改密码,需用 SQL 或 mariadb-admin 调整。

七、配置参数说明

LinuxServer.io 镜像的配置生效优先级是:compose environment 注入的环境变量 > /config/www/.env 文件。首次启动时容器会把一份示例 .env 模板复制到 /opt/data/bookstack/app/www/.env,注意模板里都是占位值,真正生效的是 compose 里注入的变量:

grep -E '^(APP_KEY|APP_URL|DB_HOST)=' /opt/data/bookstack/app/www/.env
docker exec bookstack-26-09-1-app env | grep -E '^(APP_URL|DB_HOST)='

实测回显(文件里是模板占位值,环境里是真实生效值):

APP_KEY=SomeRandomString
APP_URL=https://example.com
DB_HOST=localhost
DB_HOST=bookstack-26-09-1-db
APP_URL=http://192.168.146.128:8112

结论:日常改配置优先改 compose 的 environment 段再 docker compose up -d(会自动重建容器);只有 compose 未注入的高级变量(如邮件、LDAP、OIDC)才去编辑 /opt/data/bookstack/app/www/.env 文件——文件里未被环境变量覆盖的键会生效。全部可用变量清单见《BookStack v26.09.1 配置参数详解》。改 APP_URL 后还要同步更新数据库里的历史 URL:

docker exec bookstack-26-09-1-app php /app/www/artisan bookstack:update-url --force <旧URL> <新URL>

<旧URL>、<新URL> 用你的实际地址替换(如 http://192.168.146.128:8112 换成新域名)。不带 --force 时命令会交互式确认(Are you sure you want to proceed? (yes/no)),脚本化执行加 --force。实测回显(本次新旧地址相同,替换 0 行属正常):

Updated 0 rows in attachments->path
Updated 0 rows in entity_page_data->html
Updated 0 rows in entity_page_data->text
Updated 0 rows in entity_page_data->markdown
Updated 0 rows in entity_container_data->description_html
Updated 0 rows in page_revisions->html
Updated 0 rows in page_revisions->text
Updated 0 rows in page_revisions->markdown
Updated 0 rows in images->url
Updated 0 rows in settings->value
Updated 0 rows in comments->html
Updated 0 JSON encoded rows in settings->value
URL update procedure complete.
============================================================================
Be sure to run "php artisan cache:clear" to clear any old URLs in the cache.
============================================================================

按提示清一次缓存(清除旧 URL 缓存):

docker exec bookstack-26-09-1-app php /app/www/artisan cache:clear

实测回显:

Application cache cleared successfully.

八、配置文件挂载

除 .env 外,如需深度定制可在宿主目录放置以下文件(均为 LinuxServer.io 镜像约定路径,改完 docker compose restart 生效):

宿主文件容器路径用途
/opt/data/bookstack/app/nginx/nginx.conf(或 site-confs/)/config/nginx/nginx 站点配置(加 HTTPS、改超时等)
/opt/data/bookstack/app/php/www2.conf 类/config/php/php-fpm 配置(上传大小、超时)
/opt/data/bookstack/app/www/themes/<主题名>//config/www/themes/自定义主题(BookStack 主题系统)

上传大小受两层限制:PHP 的 upload_max_filesize/post_max_size 与 BookStack 的 FILE_UPLOAD_SIZE_LIMIT(默认 50MB),大附件场景两层都要改。查看当前 php 配置生效值:

docker exec bookstack-26-09-1-app php -i | grep -E '^(upload_max_filesize|post_max_size)'

实测回显:

upload_max_filesize => 100M => 100M
post_max_size => 100M => 100M

九、等价 docker run

不使用 compose 时,等价的 docker run 命令如下(compose 自动建的网络需先手工创建,其余一一对应):

# 1. 先建自定义网络(显式网段)
docker network create --subnet 10.89.36.0/24 bookstack_default

# 2. 启动 MariaDB
docker run -d \
  --name bookstack-26-09-1-db \
  --network bookstack_default \
  -e PUID=1000 -e PGID=1000 -e TZ=Asia/Shanghai \
  -e MYSQL_ROOT_PASSWORD=q1w2e3r4 \
  -e MYSQL_DATABASE=bookstack \
  -e MYSQL_USER=bookstack \
  -e MYSQL_PASSWORD=q1w2e3r4 \
  -v /opt/data/bookstack/db:/config \
  --restart unless-stopped \
  lscr.io/linuxserver/mariadb:11.8.8

# 3. 启动 BookStack
docker run -d \
  --name bookstack-26-09-1-app \
  --network bookstack_default \
  -e PUID=1000 -e PGID=1000 -e TZ=Asia/Shanghai \
  -e APP_URL=http://192.168.146.128:8112 \
  -e APP_KEY=base64:foRBbYWw5a9ATjYenNOQbUpPWqHiE9AB5eAy2GTABKw= \
  -e DB_HOST=bookstack-26-09-1-db \
  -e DB_PORT=3306 \
  -e DB_USERNAME=bookstack \
  -e DB_PASSWORD=q1w2e3r4 \
  -e DB_DATABASE=bookstack \
  -e QUEUE_CONNECTION=database \
  -p 8112:80 \
  -v /opt/data/bookstack/app:/config \
  --restart unless-stopped \
  lscr.io/linuxserver/bookstack:26.09.1

启动后同样执行 4.4/4.5 节验证。生产环境建议仍用 compose:声明式、可版本化、单文件复制即可重建整栈。

十、常用运维命令

以下命令均在 /opt/data/bookstack(compose 项目目录)下执行,全部实测:

# 查看服务状态
docker compose ps

实测回显:

NAME                    IMAGE                                   COMMAND   SERVICE        CREATED          STATUS          PORTS
bookstack-26-09-1-app   lscr.io/linuxserver/bookstack:26.09.1   "/init"   bookstack      15 seconds ago   Up 15 seconds   443/tcp, 0.0.0.0:8112->80/tcp, [::]:8112->80/tcp
bookstack-26-09-1-db    lscr.io/linuxserver/mariadb:11.8.8      "/init"   bookstack-db   15 seconds ago   Up 15 seconds   3306/tcp
# 跟踪应用日志(-f 实时跟踪,Ctrl+C 退出)
docker compose logs -f bookstack
# 重启整个栈 / 单个服务
docker compose restart
docker compose restart bookstack
# 停止(保留容器与数据)与销毁(保留数据目录,删容器与网络)
docker compose stop
docker compose down

docker compose down 实测回显(数据目录 /opt/data/bookstack 保留):

 Container bookstack-26-09-1-app Stopping
 Container bookstack-26-09-1-app Stopped
 Container bookstack-26-09-1-app Removing
 Container bookstack-26-09-1-app Removed
 Container bookstack-26-09-1-db Stopping
 Container bookstack-26-09-1-db Stopped
 Container bookstack-26-09-1-db Removing
 Container bookstack-26-09-1-db Removed
 Network bookstack_default Removing
 Network bookstack_default Removed

重新 docker compose up -d 后验证数据不丢(健康检查通过、管理员账号仍在):

curl -s http://localhost:8112/status
docker exec bookstack-26-09-1-app php /app/www/artisan tinker --execute='echo "admin_exists=".\BookStack\Users\Models\User::where("email","admin@example.com")->exists() ? 1 : 0;'

实测回显:

{"database":true,"cache":true,"session":true}
admin_exists=1

升级流程(版本标签改到新版本号后拉取并重建):

# 1. 修改 docker-compose.yml 中 bookstack 的 image 标签为新版本号
# 2. 拉取新镜像(本测试时 26.09.1 已是最新,回显为"Pulled"即无更新)
docker compose pull

实测回显:

 Image lscr.io/linuxserver/mariadb:11.8.8 Pulling
 Image lscr.io/linuxserver/bookstack:26.09.1 Pulling
 Image lscr.io/linuxserver/mariadb:11.8.8 Pulled
 Image lscr.io/linuxserver/bookstack:26.09.1 Pulled
# 3. 重建应用容器(数据库迁移自动执行)
docker compose up -d
# 4. 验证
docker compose ps
curl -s http://localhost:8112/status

⚠️ 注意:升级前先做数据库备份(备份命令见《BookStack 日常运维手册》);跨多个大版本升级时先阅读官方 Updates 文档的中间版本说明。

十一、常见问题

Q1:启动失败,日志提示 APP_KEY 相关错误? APP_KEY 未设置或为空。LinuxServer.io 镜像强制要求显式提供。按 4.1 节用 docker run --rm --entrypoint /bin/bash lscr.io/linuxserver/bookstack:26.09.1 appkey 生成后填入 compose 再 docker compose up -d。已有数据后不可更换该值。

Q2:页面能打开但样式错乱、链接指向旧地址? APP_URL 与实际访问地址不一致。检查 compose 里 APP_URL 的协议、IP/域名、端口三要素是否与浏览器地址栏完全一致(本例为 http://192.168.146.128:8112);若首次部署后又改了地址,执行 docker exec bookstack-26-09-1-app php /app/www/artisan bookstack:update-url <旧URL> <新URL> 更新数据库历史 URL 后刷新。

Q3:预分配端口被占用(bind: address already in use)? docker compose up -d 报端口冲突时,先 ss -ltn | grep :<端口> 复核。本机实测时预分配的 8106 已被其他服务监听,遂改用 8112 并同步修改 APP_URL。选端口前先查一次是硬要求。

Q4:应用容器不断重启,日志提示数据库连接失败? BookStack 启动时 MariaDB 可能尚未完成初始化(首次启动要建库)。compose 的 depends_on 只保证启动顺序、不等待就绪;LinuxServer.io 的 bookstack 容器内置重试,通常几十秒内自愈。若持续失败,检查 DB_HOST 是否为数据库服务名、DB_PASSWORD 与 MYSQL_PASSWORD 是否一致、MariaDB 日志(docker compose logs bookstack-db)有无报错。

Q5:想用邮件找回密码 / Webhook,需要什么? 两件事:① compose 加 QUEUE_CONNECTION=database(本篇已加,日志可见 *** Starting Async Action Queue ***);② 在 .env 文件或 compose 环境变量中配置 SMTP(MAIL_HOST/MAIL_PORT/MAIL_USERNAME/MAIL_PASSWORD/MAIL_FROM 等),改完 docker compose up -d 重建,再到管理界面「设置 → 维护 → 发送测试邮件」验证。SMTP 各参数含义见《BookStack v26.09.1 配置参数详解》。

Q6:反向代理(Nginx/Traefik)后面怎么部署? APP_URL 填对外域名(含协议),ports 可以不再暴露到宿主(expose: 80),在反代上游填 http://bookstack-26-09-1-app:80;若经过多层代理导致客户端 IP 识别错误,追加 APP_PROXIES 环境变量为代理 IP(多值逗号分隔)。

Q7:数据库密码忘了怎么处理? LinuxServer.io MariaDB 的 root@localhost 默认走本地 socket 认证(无需密码),容器内直接以 root 进入并重置业务账号密码(宿主上执行):

docker exec -it bookstack-26-09-1-db mariadb -uroot -e "ALTER USER 'bookstack'@'%' IDENTIFIED BY 'q1w2e3r4'; FLUSH PRIVILEGES; SELECT User,Host FROM mysql.user WHERE User='bookstack';"

实测回显(无报错且列出业务账号即成功):

User    Host
bookstack       %

改完后 BookStack 侧的 DB_PASSWORD 无需变动(值一致即可)。注意 TCP 方式连 root(mariadb -h127.0.0.1 -uroot -p...)会因 root@localhost 未设密码而报 ERROR 1045 (28000): Access denied,属镜像默认行为。管理员密码遗忘则用 4.5 节的 bookstack:create-admin 再建一个管理员。

十二、参考链接

  1. BookStack 官方安装文档(Docker 章节列出社区方案):https://www.bookstackapp.com/docs/admin/installation/
  2. LinuxServer.io bookstack 镜像文档:https://docs.linuxserver.io/images/docker-bookstack/
  3. LinuxServer.io bookstack 仓库:https://github.com/linuxserver/docker-bookstack
  4. LinuxServer.io mariadb 镜像文档:https://docs.linuxserver.io/images/docker-mariadb/
  5. BookStack 官方更新文档:https://www.bookstackapp.com/docs/admin/updates/
  6. BookStack 官方文档站:https://www.bookstackapp.com/docs/