1. 项目缘起:为什么选择Docker部署BookStack?

最近在整理团队内部的技术文档和知识库,发现用过的几个平台要么太重,要么太轻。太重的那种,光是配置环境就能劝退一批人,后续维护更是麻烦;太轻的,功能又过于简陋,连个像样的权限管理和版本控制都没有。后来发现了BookStack,一个开源的、界面清爽、功能又足够用的文档和知识库系统,用起来感觉挺对味。它基于PHP的Laravel框架,自带Markdown编辑器,支持章节、页面、图片管理,权限体系也够清晰,对于中小团队或者个人来说,是个不错的选择。

但问题来了,官方推荐的安装方式是传统的LAMP(Linux + Apache + MySQL + PHP)环境部署。对于不熟悉PHP环境配置,或者希望快速搭建、方便迁移和备份的开发者来说,这无疑是个门槛。这时候,Docker的优势就体现出来了。用Docker部署BookStack,相当于把整个运行环境(PHP、Nginx、MySQL)打包成一个“集装箱”,你只需要一条命令就能拉起服务,环境隔离、版本固定、一键部署和销毁,极大地简化了运维复杂度。特别是当你需要在不同机器(开发机、测试服务器、生产环境)上保持环境一致时,Docker几乎是目前最优雅的解决方案。

所以,这篇内容就围绕“用Docker部署BookStack”这个核心目标展开。我会带你从零开始,一步步完成部署,并分享我在这个过程中遇到的一些坑和对应的解决方案。无论你是想快速搭建一个个人知识库,还是为团队部署一个稳定的文档中心,这套流程都能直接拿来用。

2. 部署前的核心准备:理解架构与选型

在动手敲命令之前,我们先花点时间搞清楚我们要部署的是什么,以及Docker方案是如何构成的。这能帮你更好地理解后续的每一步操作,甚至在出问题时,能自己定位原因。

BookStack本身是一个Web应用,它的运行依赖几个核心组件:

  1. Web服务器 :用来处理HTTP请求,通常用Nginx或Apache。在Docker方案里,我们一般选用Nginx,因为它更轻量,与PHP-FPM(PHP的FastCGI进程管理器)配合是经典组合。
  2. PHP运行环境 :BookStack是用PHP写的,所以需要一个能执行PHP代码的环境,包括PHP本身和一系列必要的扩展(如MySQL驱动、GD图像处理库、XML支持等)。
  3. 数据库 :用来存储所有的书籍、页面、用户信息等数据。BookStack官方支持MySQL/MariaDB。
  4. 应用代码 :就是BookStack的源代码。

在传统的部署中,你需要手动在服务器上安装并配置这四部分,让它们能协同工作。而Docker化的思路,就是把这四部分分别(或部分合并)放到不同的容器(Container)里。

常见的Docker部署BookStack方案有两种:

  • 单容器方案 :有些Docker镜像会把Nginx、PHP-FPM和BookStack代码打包在一个容器里。这种方案最简单,一条 docker run 命令就能跑起来,适合快速体验。但缺点是不够灵活,比如你想自定义Nginx配置,或者单独升级PHP版本,会比较麻烦。
  • 多容器方案(推荐) :这也是更接近生产环境的做法。我们使用 docker-compose 工具,通过一个配置文件,定义并启动三个独立的容器:
    • 一个BookStack应用容器 :里面包含PHP-FPM和BookStack代码。
    • 一个Nginx容器 :专门处理Web请求,并将PHP请求转发给上面的应用容器。
    • 一个MySQL/MariaDB容器 :专门提供数据库服务。

这种方案结构清晰,每个容器各司其职,方便单独管理、配置和扩展。例如,数据库容器挂了,可以单独重启而不影响Web服务;想换用其他数据库(虽然BookStack不一定支持),也只需要替换这个容器。我们接下来要采用的,正是这种多容器方案。

注意 :确保你的宿主机(也就是运行Docker的机器)已经安装了Docker和Docker Compose。对于Linux系统,可以通过包管理器安装;对于Windows/macOS,安装Docker Desktop即可,它自带Docker Compose。你可以通过运行 docker --version docker-compose --version (或 docker compose version )来验证安装是否成功。

3. 实战部署:编写docker-compose.yml与启动服务

理解了架构,我们就可以开始动手了。整个过程的核心是编写一个 docker-compose.yml 文件。这个文件就像乐高说明书,告诉Docker需要哪些“积木”(镜像),以及如何把它们拼装起来。

3.1 创建项目目录与配置文件

首先,在你觉得合适的地方创建一个项目目录,比如 bookstack-docker ,并进入该目录。

mkdir bookstack-docker && cd bookstack-docker

然后,创建我们的核心配置文件 docker-compose.yml 。你可以用任何文本编辑器(如Vim, Nano, VS Code)来创建和编辑它。

version: '3.8'

services:
  # 数据库服务
  db:
    image: mariadb:10.6
    container_name: bookstack_db
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: your_strong_root_password_here
      MYSQL_DATABASE: bookstack
      MYSQL_USER: bookstack
      MYSQL_PASSWORD: your_strong_db_password_here
    volumes:
      - db_data:/var/lib/mysql
    networks:
      - bookstack_network

  # BookStack应用服务 (PHP-FPM + 代码)
  app:
    image: lscr.io/linuxserver/bookstack:latest
    container_name: bookstack_app
    restart: unless-stopped
    depends_on:
      - db
    environment:
      - DB_HOST=db
      - DB_DATABASE=bookstack
      - DB_USERNAME=bookstack
      - DB_PASSWORD=your_strong_db_password_here
      - APP_URL=http://localhost:8080 # 修改为你的实际访问地址或IP
    volumes:
      - app_data:/config
    networks:
      - bookstack_network

  # Web服务器 (Nginx)
  web:
    image: nginx:alpine
    container_name: bookstack_web
    restart: unless-stopped
    depends_on:
      - app
    ports:
      - "8080:80" # 将宿主机的8080端口映射到容器的80端口
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
      - app_data:/var/www/html:ro # 挂载应用代码和上传的文件
    networks:
      - bookstack_network

# 定义数据卷,用于持久化存储
volumes:
  db_data:
  app_data:

# 定义内部网络,让三个容器可以互相通信
networks:
  bookstack_network:
    driver: bridge

关键配置解读:

  1. 版本与环境变量 :我们使用了较新的 3.8 版本。环境变量是配置容器的关键。
    • db 服务:设置了MySQL的root密码、创建的数据库名、用户和密码。 务必替换 your_strong_root_password_here your_strong_db_password_here 为你自己的强密码!
    • app 服务:我们使用了 linuxserver/bookstack 镜像,这个镜像维护得比较好,集成了所需环境。通过环境变量告诉BookStack如何连接数据库( DB_HOST=db ,这里的 db 就是上面定义的数据库服务名)。 APP_URL 非常重要,它需要设置为你最终访问BookStack的完整URL(例如 http://你的服务器IP:8080 https://wiki.yourdomain.com ),这会影响系统生成的链接。初次测试可以先设为 http://localhost:8080
  2. 数据持久化 :使用 volumes db_data app_data )将数据库文件和BookStack的配置文件、上传的图片等数据保存在宿主机上。这样即使删除容器,数据也不会丢失。
  3. 网络 :创建了一个名为 bookstack_network 的桥接网络,三个服务都加入其中,它们可以通过服务名(如 db , app )直接相互访问,这是Docker Compose提供的便利。
  4. 端口映射 web 服务将容器的80端口映射到了宿主机的 8080 端口。这意味着你通过访问 http://宿主机IP:8080 就能打开BookStack。如果8080端口已被占用,可以改为其他端口,如 "8888:80"

3.2 配置Nginx

上面的配置中, web 服务挂载了一个 ./nginx.conf 文件。我们需要创建这个Nginx配置文件,它告诉Nginx如何将请求转发给后端的PHP-FPM(即 app 容器)。

bookstack-docker 目录下,创建 nginx.conf 文件:

server {
    listen 80;
    server_name localhost; # 生产环境请改为你的域名
    root /var/www/html;
    index index.php index.html;

    client_max_body_size 100M; # 允许上传大文件,如图片、PDF

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass app:9000; # 关键!指向app容器的9000端口(PHP-FPM默认端口)
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_intercept_errors on;
    }

    location ~ /\.ht {
        deny all;
    }
}

关键配置解读:

  • fastcgi_pass app:9000; :这是最核心的一行。它告诉Nginx,所有PHP文件的请求都转发到名为 app 的容器的9000端口。 app 正是我们 docker-compose.yml 里定义的服务名,Docker的网络机制会自动将其解析为正确的容器IP。
  • client_max_body_size 100M; :默认Nginx允许上传的文件很小,增加这个值可以让你在BookStack里上传更大的附件。
  • try_files $uri $uri/ /index.php?$query_string; :这是Laravel框架(BookStack基于它)常见的URL重写规则,将所有非静态文件的请求都引导到 index.php 处理。

3.3 启动所有服务

配置文件都准备好了,现在可以一键启动所有服务。在 bookstack-docker 目录下,运行:

docker-compose up -d

-d 参数表示在后台运行(detached mode)。Docker Compose会依次执行以下操作:

  1. 拉取(如果本地没有) mariadb:10.6 lscr.io/linuxserver/bookstack:latest nginx:alpine 镜像。
  2. 创建 bookstack_network 网络和 db_data app_data 数据卷。
  3. 按照依赖顺序启动容器:先启动 db ,然后 app ,最后 web

启动完成后,你可以用以下命令查看容器状态:

docker-compose ps

如果看到三个容器的状态都是 Up ,就说明启动成功了。

3.4 初始化访问与配置

打开浏览器,访问 http://你的服务器IP:8080 。如果一切顺利,你应该能看到BookStack的安装引导页面。

  1. 检查环境 :页面会列出所有需要的PHP扩展和权限要求。因为我们用的是精心维护的Docker镜像,通常所有条件都会是绿色的勾。
  2. 数据库配置 :在数据库配置部分,填写以下信息:
    • 主机 db (就是docker-compose里定义的服务名)
    • 端口 3306 (MariaDB默认端口)
    • 数据库名 bookstack
    • 用户名 bookstack
    • 密码 :你之前在 docker-compose.yml 里设置的 your_strong_db_password_here (这些信息都来自我们之前设置的环境变量)
  3. 设置管理员账号 :接下来设置第一个管理员用户的姓名、邮箱和密码。这个账号拥有最高权限,请务必记牢。
  4. 完成 :点击安装,片刻之后,系统会提示安装成功,并跳转到登录页面。用你刚设置的管理员邮箱和密码登录,就可以开始使用BookStack了!

4. 部署后的关键配置与优化

成功登录只是第一步。要让BookStack更好用、更安全,还需要进行一些关键配置。

4.1 修改默认的APP_URL

安装时我们可能用了 localhost 或测试IP。在生产环境,你需要将其改为正式的访问地址。这个配置存储在BookStack容器的环境变量和配置文件中。

最直接的方式是修改 docker-compose.yml app 服务的 APP_URL 环境变量,然后重启服务:

environment:
  - APP_URL=https://wiki.yourcompany.com # 改为你的实际域名

修改后,在项目目录下执行:

docker-compose down
docker-compose up -d

这会重建 app 容器并应用新的环境变量。

4.2 配置HTTPS(SSL证书)

在公网访问,强烈建议启用HTTPS。有几种方式:

  • 在Nginx容器内配置 :你可以修改 nginx.conf ,添加SSL证书和重定向规则。需要将你的证书文件( server.crt server.key )挂载到容器内。
  • 使用反向代理 (更推荐):在Docker集群前面,再部署一个Nginx或Caddy服务器作为反向代理和SSL终结器。这个代理服务器负责处理HTTPS、域名绑定,然后将HTTP请求转发给内部的 bookstack_web 容器(端口8080)。这样,BookStack的容器配置可以保持简单。很多云服务商也提供负载均衡器自带SSL证书管理。

一个简单的在 web 容器内配置HTTPS的 nginx.conf 示例(需要挂载证书文件):

server {
    listen 80;
    server_name wiki.yourcompany.com;
    return 301 https://$server_name$request_uri; # HTTP强制跳转HTTPS
}

server {
    listen 443 ssl http2;
    server_name wiki.yourcompany.com;

    ssl_certificate /etc/nginx/ssl/server.crt;
    ssl_certificate_key /etc/nginx/ssl/server.key;
    # 其他SSL优化配置...

    root /var/www/html;
    index index.php index.html;
    client_max_body_size 100M;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass app:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_intercept_errors on;
    }
}

然后在 docker-compose.yml 中为 web 服务添加证书卷挂载:

volumes:
  - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
  - ./ssl:/etc/nginx/ssl:ro # 假设证书放在宿主机的./ssl目录下
  - app_data:/var/www/html:ro

4.3 数据备份与恢复

数据是无价的。我们的数据(数据库和上传的文件)通过Docker卷持久化了,位于宿主机上Docker管理的区域。备份就是备份这些卷。

  • 查找卷的实际路径 :可以使用 docker volume inspect bookstack-docker_db_data docker volume inspect bookstack-docker_app_data 查看 Mountpoint ,那里就是数据在宿主机上的实际存储位置。
  • 备份数据库 :更规范的方式是进入数据库容器执行 mysqldump 命令。
    # 将备份文件导出到宿主机当前目录
    docker exec bookstack_db mysqldump -u bookstack -p'your_strong_db_password_here' bookstack > bookstack_backup_$(date +%Y%m%d).sql
    
  • 备份应用数据 :应用卷 app_data 里主要是配置文件、缓存和用户上传的图片/附件。可以直接打包宿主机上的挂载点目录。
    # 先找到挂载点路径
    VOLUME_PATH=$(docker volume inspect bookstack-docker_app_data --format '{{ .Mountpoint }}')
    tar -czf app_data_backup_$(date +%Y%m%d).tar.gz -C $VOLUME_PATH .
    
  • 恢复 :恢复时,先确保卷存在(docker-compose up时会自动创建),然后反向操作即可。恢复数据库: cat backup.sql | docker exec -i bookstack_db mysql -u bookstack -p'password' bookstack 。恢复应用数据:解压备份文件到卷的挂载点。

4.4 性能与资源限制

默认情况下,容器可以使用宿主机的所有资源。在生产环境,建议为容器设置资源限制,防止某个容器异常占用所有资源导致系统瘫痪。

docker-compose.yml 的每个服务下可以添加 deploy resources 限制(注意: deploy 仅在使用Docker Swarm模式时生效,单机使用 resources ):

services:
  app:
    # ... 其他配置 ...
    deploy: # 适用于Swarm模式
      resources:
        limits:
          cpus: '1'
          memory: 1G
        reservations:
          cpus: '0.5'
          memory: 512M
    # 或者使用(适用于docker-compose up)
    # mem_limit: 1g
    # cpus: "1.0"

5. 常见问题排查与运维技巧

即使按照步骤操作,也可能会遇到问题。这里分享几个我踩过的坑和解决办法。

5.1 容器启动失败:端口冲突

如果宿主机8080端口已被其他程序占用, docker-compose up 时会报错。解决方法:

  1. 修改 docker-compose.yml web 服务的端口映射,例如改为 "8888:80"
  2. 找出占用8080端口的进程并停止它( sudo lsof -i:8080 sudo netstat -tulpn | grep :8080 )。

5.2 访问页面显示“502 Bad Gateway”或“连接被拒绝”

这通常是Nginx无法连接到后端的PHP-FPM服务( app 容器)导致的。

  1. 检查容器状态和日志
    docker-compose ps # 确保所有容器都是Up状态
    docker-compose logs app # 查看app容器的日志,看PHP-FPM是否启动成功
    docker-compose logs web # 查看nginx容器的日志,看错误详情
    
  2. 常见原因
    • app 容器启动失败:可能是数据库连接失败(检查 db 容器是否正常,环境变量密码是否正确)、PHP扩展缺失(但官方镜像通常完整)。查看 app 日志能定位。
    • 网络问题 :确保 docker-compose.yml 中所有服务在同一个自定义网络( bookstack_network )里。Nginx配置中的 fastcgi_pass app:9000; 依赖于这个网络。
    • 权限问题 :BookStack需要对 /config 目录(即挂载的 app_data 卷)有读写权限。如果宿主机上的目录权限过严,可能导致容器内进程无法写入。可以尝试先不挂载卷,或者检查宿主机上Docker卷的权限(通常Docker管理的数据卷权限是正常的)。

5.3 上传文件大小限制

如果你上传图片或附件时遇到“文件过大”的错误,需要检查两处:

  1. Nginx配置 :我们已经设置了 client_max_body_size 100M;
  2. PHP配置 :还需要修改PHP的上传限制。这可以通过环境变量注入到 app 容器中。修改 docker-compose.yml app 服务的环境变量:
    environment:
      - DB_HOST=db
      # ... 其他变量
      - PHP_UPLOAD_MAX_FILESIZE=100M
      - PHP_POST_MAX_SIZE=100M
    
    然后重启服务: docker-compose down && docker-compose up -d

5.4 如何升级BookStack版本

使用Docker升级非常方便。 linuxserver/bookstack:latest 标签会指向最新的稳定版。

  1. 备份数据 :升级前务必按照4.3节的步骤备份数据库和应用数据。
  2. 拉取新镜像并重启
    docker-compose pull # 拉取所有服务的最新镜像
    docker-compose down # 停止并删除旧容器
    docker-compose up -d # 用新镜像创建并启动新容器
    
  3. 检查 :访问页面,确认功能正常。BookStack的数据库迁移通常是自动执行的。

5.5 日常运维命令备忘

  • 查看实时日志 docker-compose logs -f [service_name] ,例如 docker-compose logs -f app 可以实时查看PHP应用的日志。
  • 进入容器内部 docker exec -it bookstack_app /bin/bash ,可以进入应用容器检查文件、运行Artisan命令等。
  • 重启单个服务 docker-compose restart web
  • 停止所有服务但保留数据卷 docker-compose down
  • 停止所有服务并删除数据卷(危险!会丢失所有数据!) docker-compose down -v
  • 查看资源占用 docker stats

6. 进阶:自定义与扩展

基本的部署满足后,你可能会有一些定制化需求。

6.1 使用自定义的BookStack镜像

如果你需要安装额外的PHP扩展,或者修改一些默认的PHP配置,可以基于官方镜像构建自己的Docker镜像。

  1. 创建一个 Dockerfile
    FROM lscr.io/linuxserver/bookstack:latest
    # 安装额外的扩展,例如redis扩展
    RUN apt-get update && apt-get install -y php-redis && apt-get clean
    # 或者覆盖默认的php.ini配置
    COPY custom-php.ini /etc/php/8.x/fpm/conf.d/99-custom.ini
    
  2. 修改 docker-compose.yml ,将 app 服务的 image 改为构建你的Dockerfile:
    app:
      build: .
      # image: lscr.io/linuxserver/bookstack:latest # 注释掉这行
      container_name: bookstack_app
      # ... 其他配置不变
    
  3. 运行 docker-compose up -d --build 来重建自定义镜像的容器。

6.2 集成外部服务(如Redis缓存)

为了提高性能,可以为BookStack配置Redis作为缓存和Session驱动。这需要额外启动一个Redis容器,并修改BookStack的配置。

  1. docker-compose.yml 中添加 redis 服务:
    redis:
      image: redis:alpine
      container_name: bookstack_redis
      restart: unless-stopped
      networks:
        - bookstack_network
    
  2. 修改 app 服务的环境变量,告诉BookStack使用Redis:
    environment:
      - DB_HOST=db
      # ... 其他DB变量
      - REDIS_HOST=redis
      - REDIS_PORT=6379
      - CACHE_DRIVER=redis
      - SESSION_DRIVER=redis
      - QUEUE_CONNECTION=redis # 如果你也用队列的话
    
  3. 确保你的BookStack镜像(或自定义镜像)包含了PHP的Redis扩展(如 php-redis )。
  4. 重启服务: docker-compose up -d

6.3 配置邮件发送(用户注册、密码重置)

BookStack需要发送邮件(如密码重置链接)。你需要配置SMTP服务。

docker-compose.yml app 服务环境变量中添加邮件配置:

environment:
  # ... 数据库等配置
  - MAIL_DRIVER=smtp
  - MAIL_HOST=smtp.your-email-provider.com # 例如 smtp.gmail.com
  - MAIL_PORT=587
  - MAIL_USERNAME=your-email@example.com
  - MAIL_PASSWORD=your-email-password-or-app-specific-password
  - MAIL_ENCRYPTION=tls
  - MAIL_FROM_ADDRESS=noreply@yourdomain.com
  - MAIL_FROM_NAME="BookStack"

重要提示 :对于Gmail等第三方服务,可能需要启用“安全性较低的应用访问”或使用应用专用密码。更推荐使用专业的邮件发送服务(如SendGrid、Mailgun)或你自己的邮件服务器。

7. 从开发到生产:一些经验之谈

最后,分享几点从个人测试环境走到团队使用的生产环境过程中的体会。

关于镜像标签 :在生产环境,避免使用 :latest 这种浮动标签,因为它可能在你不知情时引入不兼容的更新。应该使用具体的版本标签,例如 lscr.io/linuxserver/bookstack:23.11.1 。你可以在Docker Hub或LinuxServer的页面查看可用的版本标签。

关于数据安全 :数据库密码、邮件密码等敏感信息,不应该明文写在 docker-compose.yml 里。可以考虑使用Docker Secrets(在Swarm模式下)或者通过环境变量文件( .env )来管理,并在 .gitignore 中忽略这个文件。例如,创建一个 .env 文件:

MYSQL_ROOT_PASSWORD=超级复杂的密码1
MYSQL_PASSWORD=超级复杂的密码2
APP_URL=https://wiki.real.com

然后在 docker-compose.yml 中引用:

environment:
  - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
  - DB_PASSWORD=${MYSQL_PASSWORD}
  - APP_URL=${APP_URL}

启动时,Docker Compose会自动读取同目录下的 .env 文件。

关于监控与健康检查 :可以考虑为容器添加健康检查指令,这样Docker能知道服务是否真的“健康”。在 docker-compose.yml 中:

app:
  # ... 其他配置
  healthcheck:
    test: ["CMD", "curl", "-f", "http://localhost/health"] # 假设有健康检查端点
    interval: 30s
    timeout: 10s
    retries: 3
    start_period: 40s

关于性能 :对于访问量不大的内部知识库,这个配置足够了。如果遇到性能瓶颈,首先查看数据库( db 容器)的负载,考虑优化数据库查询或增加索引。其次,可以按照6.2节引入Redis缓存。最后,可以考虑将 web app 容器扩展到多个实例,前面用负载均衡,但这需要更复杂的编排(如Kubernetes)和Session共享机制。

整个过程走下来,你会发现用Docker部署和管理BookStack,远比手动配置LAMP环境要清爽和可控得多。一旦 docker-compose.yml 配置定型,无论是在新的服务器上复现环境,还是进行版本升级、数据迁移,都变得有章可循。希望这份详细的指南和踩坑记录,能帮你顺利搭建起属于自己的知识库系统。

更多推荐