主题
部署
多租户部署支持 domain 和 shared_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_domainVITE_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-Tenant 和 Authorization:
http
Access-Control-Allow-Headers: Content-Type, Authorization, X-Tenant破坏性升级发布顺序
涉及租户识别协议的升级按以下顺序发布:
- 更新客户端和反向代理,使所有租户 API 发送并透传
X-Tenant,同步更新 CORS。 - 在同一发布窗口发布后端包与前端 tenancy 视图,确保前后端识别模式一致。
- 执行通用迁移、Seeder、软链接、worker 和 Scheduler 配置。
- 清理并重建配置与路由缓存。
- 通知用户重新登录,让前端重新建立当前标签页的租户上下文和独立 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租户资产与文件系统
租户初始化后,三个本地磁盘使用独立目录:
| 磁盘 | 实际目录 | 访问方式 |
|---|---|---|
uploads | storage/uploads/tenant-{uuid}/... | 公开业务上传,通过 /uploads/tenant-{uuid}/... 访问 |
static | storage/static/tenant-{uuid}/... | 私有文件,只通过应用读取 |
certs | storage/certs/tenant-{uuid}/... | 私有证书,只通过应用读取 |
上传接口返回类似路径:
text
uploads/tenant-{uuid}/2026-07-18/attachments/example.jpg页面使用站点绝对路径:
text
/uploads/tenant-{uuid}/2026-07-18/attachments/example.jpguploads 由 public/uploads -> storage/uploads 公开,适合图片和公开附件。密钥、证书及需要鉴权的文件存入 static 或 certs;项目需要自行实现鉴权下载接口。
domain 模式下,租户初始化会让 asset() 使用 stancl.tenancy.asset 作为资源根地址,tenant_asset($path) 也直接生成该命名路由。该路由通过 Host 初始化租户,主要读取租户 storage/app/public 下的文件。公开业务上传继续使用 /uploads/tenant-{uuid}/... 路径。
shared_domain 模式的浏览器图片标签无法自动附加 X-Tenant。图片和附件应直接使用上传接口返回的 /uploads/tenant-{uuid}/... 地址;需要鉴权的私有资源由项目自行提供下载接口。
资产排障
按顺序检查:
public/uploads是否链接到storage/uploads,目标文件是否真实存在于storage/uploads/tenant-{uuid}/...。tenancy.filesystem.disks是否包含uploads、static、certs,root_override是否指向对应存储根目录。config('tenancy.routes')是否为true。php artisan route:list --name=stancl.tenancy.asset是否能找到命名路由。- 配置或路由变更后执行
php artisan optimize:clear,再重建配置与路由缓存。
排查租户日志时先核对异常的最后发生时间。命名路由当前存在且新请求已恢复时,旧日志属于历史记录;新请求持续产生异常时继续检查路由缓存和服务进程加载的配置。
域名与租户准备
domain 模式可以使用 CatchAdmin 域名管理模块维护阿里云或腾讯云解析,也可以在云平台控制台直接配置。所有解析记录必须指向实际服务器 IP。
在 域名管理 → 域名配置 中保存云平台 API 密钥:

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

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

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

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


domain模式填写已经解析并配置 TLS 的主机名。shared_domain模式创建后使用租户 UUID 生成登录入口。
完成后分别验证中央登录、租户登录、租户 API、公开上传、私有文件授权、中央和租户队列、Scheduler 及监控页面。