Skip to content

部署

多租户部署支持 domainshared_domain 两种全局识别模式。同一套部署选择一种模式,并使用中央数据库保存租户、套餐和监控数据,每个租户使用独立数据库。

通用发布步骤

发布 tenancy 包后执行中央迁移、租户迁移、权限同步和前端视图发布:

shell
# 中央租户表与监控表
php artisan migrate --path=database/migrations/tenancy --force
php artisan migrate --path=database/migrations/monitor --force

# 所有可用租户的模块迁移
php artisan catch:tenant:migrate

# 同步租户管理、生命周期和调度权限
php artisan db:seed --class=TenancyMenusSeeder --force

# 发布前端页面
php artisan catch:tenant:install --only-view

# 建立 public/uploads -> storage/uploads
php artisan storage:link

确认上传软链接指向正确目录:

shell
ls -l public/uploads

生产环境分别守护中央和租户 worker:

shell
php artisan queue:work central --queue=default
php artisan queue:work tenant --queue=tenant

并由 cron 每分钟驱动 Laravel Scheduler:

text
* * * * * cd /var/www/catchadmin && php artisan schedule:run >> /dev/null 2>&1

发布完成后重建配置与路由缓存,并让 worker 加载新代码:

shell
php artisan optimize:clear
php artisan config:cache
php artisan route:cache
php artisan queue:restart

共享域名部署

shared_domain 使用一个后台域名,通过登录参数选择租户,并由普通 API 的 X-Tenant Header 传递租户 UUID:

dotenv
# 项目根目录 .env
TENANCY_IDENTIFICATION_MODE=shared_domain
TENANT_CENTRAL_DOMAIN=admin.example.com

# web/.env.production
VITE_TENANCY_IDENTIFICATION_MODE=shared_domain

VITE_TENANCY_IDENTIFICATION_MODE 在前端构建时写入产物。修改识别模式后需要重新构建并发布管理端。

租户登录入口:

text
https://admin.example.com/#/login?tenant=<tenant-uuid>

反向代理必须透传 X-Tenant。Nginx 代理到 HTTP 应用时可以显式配置:

nginx
proxy_set_header X-Tenant $http_x_tenant;

Nginx 通过 FastCGI 连接 PHP-FPM 时可以显式配置:

nginx
fastcgi_param HTTP_X_TENANT $http_x_tenant;

跨域部署需要在应用或网关的 CORS 配置中允许 X-TenantAuthorization

http
Access-Control-Allow-Headers: Content-Type, Authorization, X-Tenant

破坏性升级发布顺序

涉及租户识别协议的升级按以下顺序发布:

  1. 更新客户端和反向代理,使所有租户 API 发送并透传 X-Tenant,同步更新 CORS。
  2. 在同一发布窗口发布后端包与前端 tenancy 视图,确保前后端识别模式一致。
  3. 执行通用迁移、Seeder、软链接、worker 和 Scheduler 配置。
  4. 清理并重建配置与路由缓存。
  5. 通知用户重新登录,让前端重新建立当前标签页的租户上下文和独立 Token。

回切独立域名模式

切换 TENANCY_IDENTIFICATION_MODE=domain 前,为共享模式创建的租户补充 Domain 记录,并完成 DNS、TLS 证书和反向代理配置。所有租户域名可访问后统一切换环境变量、重建缓存并重新登录。

独立域名部署

domain 通过请求 Host 识别租户。以下配置作为现有 Laravel HTTPS server block 的域名补充:

nginx
server {
    listen 443 ssl;
    http2 on;

    server_name admin.example.com *.example.com;

    root /var/www/catchadmin/public;
    index index.php index.html;

    # 继续保留项目现有的 TLS、PHP-FPM 和 Laravel rewrite 配置。
}

为中央域名和租户域名配置 DNS、TLS;使用自定义租户域名时,将每个域名加入对应 server block。创建租户前先确认 DNS 已解析到实际服务器。

本地开发可以使用 tenant1.127.0.0.1.nip.io

text
http://tenant1.127.0.0.1.nip.io:8000

租户资产与文件系统

租户初始化后,三个本地磁盘使用独立目录:

磁盘实际目录访问方式
uploadsstorage/uploads/tenant-{uuid}/...公开业务上传,通过 /uploads/tenant-{uuid}/... 访问
staticstorage/static/tenant-{uuid}/...私有文件,只通过应用读取
certsstorage/certs/tenant-{uuid}/...私有证书,只通过应用读取

上传接口返回类似路径:

text
uploads/tenant-{uuid}/2026-07-18/attachments/example.jpg

页面使用站点绝对路径:

text
/uploads/tenant-{uuid}/2026-07-18/attachments/example.jpg

uploadspublic/uploads -> storage/uploads 公开,适合图片和公开附件。密钥、证书及需要鉴权的文件存入 staticcerts;项目需要自行实现鉴权下载接口。

domain 模式下,租户初始化会让 asset() 使用 stancl.tenancy.asset 作为资源根地址,tenant_asset($path) 也直接生成该命名路由。该路由通过 Host 初始化租户,主要读取租户 storage/app/public 下的文件。公开业务上传继续使用 /uploads/tenant-{uuid}/... 路径。

shared_domain 模式的浏览器图片标签无法自动附加 X-Tenant。图片和附件应直接使用上传接口返回的 /uploads/tenant-{uuid}/... 地址;需要鉴权的私有资源由项目自行提供下载接口。

资产排障

按顺序检查:

  1. public/uploads 是否链接到 storage/uploads,目标文件是否真实存在于 storage/uploads/tenant-{uuid}/...
  2. tenancy.filesystem.disks 是否包含 uploadsstaticcertsroot_override 是否指向对应存储根目录。
  3. config('tenancy.routes') 是否为 true
  4. php artisan route:list --name=stancl.tenancy.asset 是否能找到命名路由。
  5. 配置或路由变更后执行 php artisan optimize:clear,再重建配置与路由缓存。

排查租户日志时先核对异常的最后发生时间。命名路由当前存在且新请求已恢复时,旧日志属于历史记录;新请求持续产生异常时继续检查路由缓存和服务进程加载的配置。

域名与租户准备

domain 模式可以使用 CatchAdmin 域名管理模块维护阿里云或腾讯云解析,也可以在云平台控制台直接配置。所有解析记录必须指向实际服务器 IP。

域名管理 → 域名配置 中保存云平台 API 密钥:

catchadmin 多租户域名配置

随后在 域名管理 → 域名列表 注册主域名:

catchadmin 多租户域名配置

域名记录保存后可以查看同步结果:

catchadmin 多租户域名配置

进入解析管理添加指向实际服务器 IP 的记录,并等待 DNS 生效:

catchadmin 多租户域名配置

创建租户前先创建启用状态的套餐并分配权限。随后在租户管理页面创建租户:

catchadmin 多租户套餐管理

catchadmin 多租户配置

  • domain 模式填写已经解析并配置 TLS 的主机名。
  • shared_domain 模式创建后使用租户 UUID 生成登录入口。

完成后分别验证中央登录、租户登录、租户 API、公开上传、私有文件授权、中央和租户队列、Scheduler 及监控页面。