ai编码实现bookstack外挂阿里云oss实现图片附件托管到阿里云oss

 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在同一级。

ai编码实现bookstack外挂阿里云oss实现图片附件托管到阿里云oss

外挂程序目录结构

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 存储支持安装完成 ✓

以上插件源代码下载

成功示意图

ai编码实现bookstack外挂阿里云oss实现图片附件托管到阿里云oss

原创文章,作者:产品大法师VIP Plus,如若转载,请注明出处:https://www.pmtemple.com/artificial-intelligence/18269/

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2026年3月10日 上午9:01
下一篇 2小时前

相关推荐

发表回复

登录后才能评论

评论列表(1条)

  • 清风潮流
    清风潮流 2026年3月17日 下午1:15

    这个AI编程的思路太酷了!就像把老式单品改造成潮流爆款一样,给BookStack注入新活力。作为品牌主理人,这种用AI解决实际问题的思路简直完美,效率翻倍还不破坏原有架构!🔥

微信公众号
微信公众号
edgesensor_high 小程序
小程序
分享本页
返回顶部