bookstack是一个比较不错且轻量化的开源书籍类wiki,但是其图片都是保存在应用本地,用久了会占用大量服务器硬盘,开源代码里没有相关外挂第三方附件存储方案,于是我想了一个不影响其官方镜像更新的情况下,通过外挂注入的方式实现其支持将图片上传到阿里云oss的办法,以下是compose和外挂程序(PS:此程序我没写一个代码,全是用AI帮我做的)。
步骤一:登录阿里云控制台创建bucket,设定为公共读。
步骤二:用以下配置进行docker安装
docker-compose配置文件内容
# 声明 Compose 版本(适配主流 Docker 版本)
#version: '3.8' # 如果无法保存编排,可以注释掉這一行,算了我还是先给你注释掉好了。
# 所有服务嵌套在 services 下(必须缩进2个空格)
services:
# bookstack 服务(缩进2个空格,与services对齐层级)
bookstack:
image: lscr.io/linuxserver/bookstack:latest
container_name: bookstack
environment: # 环境变量(缩进4个空格)
- PUID=1000 # 列表形式,以-开头,缩进6个空格
- PGID=1000
- TZ=Etc/UTC # 时区与mariadb保持一致
- APP_URL=https://wiki.autopas.cn # 修改为你自己对外访问的IP地址
# 先注释下面這一行的APP_KEY,启动后生成再填入!启动后生成再填入!启动后生成再填入!
#- APP_KEY=base64:自己随便整个key
- DB_HOST=mariadb
- DB_PORT=3306
- DB_DATABASE=自定义你的数据库名称
- DB_USERNAME=自定义你的数据库用户名
- DB_PASSWORD=自定义你的数据库密码
# === BookStack 存储配置 ===
- STORAGE_TYPE=custom
# 图片/附件 URL 前缀,自动拼接 OSS 公网地址 + prefix 路径
- STORAGE_URL=https://${OSS_BUCKET}.${OSS_ENDPOINT}/${OSS_PREFIX:-bookstack}
# === 阿里云 OSS 参数(从 .env 读取)===
- OSS_ACCESS_KEY_ID=${OSS_ACCESS_KEY_ID}
- OSS_ACCESS_KEY_SECRET=${OSS_ACCESS_KEY_SECRET}
- OSS_ENDPOINT=${OSS_ENDPOINT}
- OSS_BUCKET=${OSS_BUCKET}
- OSS_PREFIX=${OSS_PREFIX:-bookstack}
- OSS_USE_SSL=${OSS_USE_SSL:-true}
- OSS_IS_CNAME=${OSS_IS_CNAME:-false}
volumes: # 数据卷(缩进4个空格)
- ./bookstack_app_data:/config # 列表形式,-开头
# 挂载自定义 OSS 存储代码(只读)
- ./custom-storage:/custom-storage:ro
# 先执行 OSS 注入脚本,再启动官方服务
entrypoint: ["/bin/bash", "-c", "bash /custom-storage/install.sh & exec /init"]
ports: # 端口映射(缩进4个空格)
- 6876:80 # 列表形式,-开头
restart: unless-stopped
depends_on: # 依赖mariadb,确保先启动数据库
- mariadb
# mariadb 服务(缩进2个空格,与bookstack同级)
mariadb:
image: lscr.io/linuxserver/mariadb:11.4.4
container_name: mariadb
environment: # 环境变量(缩进4个空格)
- PUID=1000
- PGID=1000
- TZ=Etc/UTC
- MYSQL_ROOT_PASSWORD=自定义你的数据库超级管理员密码
- MYSQL_DATABASE=必须与上面你自定义的数据库名称一致
- MYSQL_USER=必须与上面你自定义的数据库用户名一致
- MYSQL_PASSWORD=必须与上面你自定义的数据库密码一致
volumes: # 数据卷(缩进4个空格)
- ./bookstack_db_data:/config
restart: unless-stopped
.evn配置
# 阿里云 OSS 配置
OSS_ACCESS_KEY_ID=你的阿里云bucketID
OSS_ACCESS_KEY_SECRET=你的阿里云bucket秘钥
OSS_ENDPOINT=oss-cn-hangzhou.aliyuncs.com # 换成你 Bucket 所在地域的 endpoint
OSS_BUCKET=你的阿里云bucket名称
OSS_PREFIX=bookstack
OSS_USE_SSL=true
OSS_IS_CNAME=false # 如果绑定了自定义域名到 OSS 则改为 true
步骤三:将oss注入程序放到bookstack的应用目录里
此程序全程使用claude编写和调试。
把custom-storage解压缩所得的文件放到bookstack的根目录下与其bookstack_app_data和bookstack_db_data在同一级。

外挂程序目录结构
bookstack-oss/
├── docker-compose.yml
├── .env
└── custom-storage/ # 挂载进容器的自定义代码
├── install.sh # 容器启动时执行,安装依赖
├── OssStorageProvider.php
└── config/
└── filesystems.php # 覆盖 Laravel 文件系统配置
install.sh
#!/bin/bash
APP_DIR="/app/www"
PROVIDER_SRC="/custom-storage/OssStorageProvider.php"
PROVIDER_DST="${APP_DIR}/app/App/Providers/OssStorageProvider.php"
FILESYSTEMS_SRC="/custom-storage/config/filesystems.php"
FILESYSTEMS_DST="${APP_DIR}/app/Config/filesystems.php"
ENV_FILE="${APP_DIR}/.env"
echo "[OSS] 开始安装阿里云 OSS 存储支持..."
cd "${APP_DIR}"
if ! php -r "require 'vendor/autoload.php'; new \Iidestiny\Flysystem\Oss\OssAdapter('','','','');" 2>/dev/null; then
echo "[OSS] 安装 flysystem-oss composer 包..."
composer require iidestiny/flysystem-oss --no-interaction --no-progress 2>&1
else
echo "[OSS] flysystem-oss 已安装,跳过"
fi
echo "[OSS] 注入 OssStorageProvider..."
cp "${PROVIDER_SRC}" "${PROVIDER_DST}"
echo "[OSS] 覆盖 filesystems 配置..."
cp "${FILESYSTEMS_SRC}" "${FILESYSTEMS_DST}"
# 注册 Provider
APP_CONFIG="${APP_DIR}/app/Config/app.php"
if ! grep -q "OssStorageProvider" "${APP_CONFIG}"; then
echo "[OSS] 注册 Provider 到 app/Config/app.php..."
sed -i "s/BookStack\\\\App\\\\Providers\\\\AppServiceProvider::class,/BookStack\\\\App\\\\Providers\\\\AppServiceProvider::class,\n BookStack\\\\App\\\\Providers\\\\OssStorageProvider::class,/" "${APP_CONFIG}"
else
echo "[OSS] Provider 已注册,跳过"
fi
# 后台延迟写入 .env
(
echo "[OSS] 等待 .env 生成..."
for i in $(seq 1 30); do
if [ -f "${ENV_FILE}" ] && grep -q "^APP_KEY=" "${ENV_FILE}"; then
break
fi
sleep 2
done
echo "[OSS] 写入 OSS 配置到 .env..."
update_env() {
local key=$1
local value=$2
if grep -q "^${key}=" "${ENV_FILE}"; then
sed -i "s|^${key}=.*|${key}=${value}|" "${ENV_FILE}"
else
echo "${key}=${value}" >> "${ENV_FILE}"
fi
}
# 自动拼接 STORAGE_URL,带上 prefix 路径
AUTO_STORAGE_URL="https://${OSS_BUCKET}.${OSS_ENDPOINT}/${OSS_PREFIX:-bookstack}"
sed -i "s/^STORAGE_TYPE=.*/STORAGE_TYPE=custom/" "${ENV_FILE}"
update_env "STORAGE_URL" "${AUTO_STORAGE_URL}"
update_env "OSS_ACCESS_KEY_ID" "${OSS_ACCESS_KEY_ID}"
update_env "OSS_ACCESS_KEY_SECRET" "${OSS_ACCESS_KEY_SECRET}"
update_env "OSS_ENDPOINT" "${OSS_ENDPOINT}"
update_env "OSS_BUCKET" "${OSS_BUCKET}"
update_env "OSS_PREFIX" "${OSS_PREFIX:-bookstack}"
update_env "OSS_USE_SSL" "${OSS_USE_SSL:-true}"
update_env "OSS_IS_CNAME" "${OSS_IS_CNAME:-false}"
echo "[OSS] 重新加载配置缓存..."
cd "${APP_DIR}" && php artisan config:clear && php artisan cache:clear
echo "[OSS] 阿里云 OSS 存储支持安装完成 ✓"
) &
echo "[OSS] 后台配置任务已启动,等待 /init 完成后自动写入..."
OssStorageProvider.php
<?php
namespace BookStack\App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Storage;
use Illuminate\Filesystem\FilesystemAdapter;
use League\Flysystem\Filesystem;
use Iidestiny\Flysystem\Oss\OssAdapter;
class OssStorageProvider extends ServiceProvider
{
public function boot(): void
{
Storage::extend('oss', function ($app, $config) {
$adapter = new OssAdapter(
$config['access_key'],
$config['secret_key'],
$config['endpoint'],
$config['bucket'],
$config['isCName'] ?? false,
$config['prefix'] ?? '',
[],
$config['use_ssl'] ?? true,
);
$filesystem = new Filesystem($adapter);
// 用 Laravel 的 FilesystemAdapter 包装,返回正确的接口类型
return new FilesystemAdapter($filesystem, $adapter, $config);
});
}
}
config/filesystems.php
<?php
return [
'default' => env('FILESYSTEM_DISK', 'local'),
// BookStack 用这个键决定图片存储驱动
'images' => env('STORAGE_TYPE', 'local'),
// BookStack 用这个键拼接图片公开 URL
'url' => env('STORAGE_URL', null),
'disks' => [
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
'throw' => false,
],
'uploads' => [
'driver' => 'local',
'root' => storage_path('uploads'),
'throw' => false,
],
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL') . '/storage',
'visibility' => 'public',
'throw' => false,
],
's3' => [
'driver' => 's3',
'key' => env('STORAGE_S3_KEY', ''),
'secret' => env('STORAGE_S3_SECRET', ''),
'region' => env('STORAGE_S3_REGION', ''),
'bucket' => env('STORAGE_S3_BUCKET', ''),
'url' => env('STORAGE_S3_ENDPOINT', ''),
'endpoint' => env('STORAGE_S3_ENDPOINT', ''),
'use_path_style_endpoint' => env('STORAGE_S3_PATH_STYLE', false),
],
// 阿里云 OSS 磁盘
'oss' => [
'driver' => 'oss',
'access_key' => env('OSS_ACCESS_KEY_ID'),
'secret_key' => env('OSS_ACCESS_KEY_SECRET'),
'endpoint' => env('OSS_ENDPOINT'),
'bucket' => env('OSS_BUCKET'),
'prefix' => env('OSS_PREFIX', 'bookstack'),
'use_ssl' => env('OSS_USE_SSL', true),
'isCName' => env('OSS_IS_CNAME', false),
],
// BookStack STORAGE_TYPE=custom 时指向 oss
'custom' => [
'driver' => 'oss',
'access_key' => env('OSS_ACCESS_KEY_ID'),
'secret_key' => env('OSS_ACCESS_KEY_SECRET'),
'endpoint' => env('OSS_ENDPOINT'),
'bucket' => env('OSS_BUCKET'),
'prefix' => env('OSS_PREFIX', 'bookstack'),
'use_ssl' => env('OSS_USE_SSL', true),
'isCName' => env('OSS_IS_CNAME', false),
],
],
'links' => [
public_path('storage') => storage_path('app/public'),
],
];
最后展示一下编排成功的日志
mariadb | Linuxserver.io version: 11.4.4-r1-ls174
mariadb | Build-date: 2025-02-18T07:42:37+00:00
mariadb | ───────────────────────────────────────
mariadb |
mariadb | [custom-init] No custom files found, skipping...
mariadb | 260316 15:50:08 mysqld_safe Logging to '/config/log/mysql/mariadb-error.log'.
mariadb | 260316 15:50:08 mysqld_safe Starting mariadbd daemon with databases from /config/databases
mariadb | Connection to localhost (::1) 3306 port [tcp/mysql] succeeded!
mariadb | Logrotate is enabled
mariadb | [ls.io-init] done.
bookstack | [OSS] 等待 .env 生成...
bookstack | [OSS] 写入 OSS 配置到 .env...
bookstack | [OSS] 重新加载配置缓存...
bookstack |
bookstack | INFO Configuration cache cleared successfully.
bookstack |
bookstack |
bookstack | INFO Application cache cleared successfully.
bookstack |
bookstack | [OSS] 阿里云 OSS 存储支持安装完成 ✓
以上插件源代码下载
成功示意图

原创文章,作者:产品大法师
,如若转载,请注明出处:https://www.pmtemple.com/artificial-intelligence/18269/
微信扫一扫
支付宝扫一扫
评论列表(1条)
这个AI编程的思路太酷了!就像把老式单品改造成潮流爆款一样,给BookStack注入新活力。作为品牌主理人,这种用AI解决实际问题的思路简直完美,效率翻倍还不破坏原有架构!🔥