You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Laravel+Forge搭建支持CNAME关联的类Shopify多子域名应用问询

嘿,看起来你已经搭好了基础的多租户子域名架构,我之前在做类似Shopify的Laravel多租户项目时,正好处理过这些问题,给你分享一些实操经验和完善方案:

一、核心架构完善建议

1. 强化多租户数据隔离

Laravel Spark默认是单租户逻辑,你需要扩展成严格的多租户隔离:

  • 新增Tenant模型,与用户、商品、订单等业务模型通过tenant_id关联,给所有关联字段加数据库索引
  • 全局查询作用域:给所有业务模型添加全局作用域,自动过滤当前租户的数据,避免跨租户访问
  • 中间件验证:在子域名路由组的前置中间件里,必须验证当前子域名对应的租户存在,否则返回404或引导至主站注册页

2. 子域名路由与容器绑定

在routes/web.php里用域名分组隔离租户路由:

Route::domain('{tenant}.app.com')->middleware('tenancy')->group(function () {
    // 租户专属路由:店铺首页、商品管理、订单查看等
    Route::get('/', 'Tenant\HomeController@index');
    Route::resource('products', 'Tenant\ProductController');
});

在HandleTenancy中间件里解析租户并绑定到容器,后续控制器可直接调用:

public function handle(Request $request, Closure $next)
{
    $tenantSlug = $request->route('tenant');
    $tenant = Tenant::where('slug', $tenantSlug)->firstOrFail();
    
    // 将租户实例绑定到容器,全局可用
    app()->instance(Tenant::class, $tenant);
    
    return $next($request);
}

3. 缓存与会话隔离

多租户场景下必须避免资源冲突:

  • 缓存:给所有缓存键添加租户ID前缀,或使用缓存标签Cache::tags([$tenant->id])->put(...)
  • 会话:修改config/session.php,将cookie配置为动态前缀,比如'cookie' => "session_{$tenant->id}"
  • 静态资源:用户上传的店铺logo、商品图建议用独立存储桶(比如S3)+ CDN,不要存在本地,避免子域名静态资源路由冲突

4. 子域名唯一性校验

用户注册生成子域名时,要确保slug唯一:

  • 将公司名称转成URL友好的slug(用Str::slug())
  • 检查数据库中是否存在相同slug,若存在则自动追加后缀(比如company-2.app.com)
  • 注册表单实时校验slug可用性,避免用户提交后才报错
二、CNAME关联实现方案

1. 用户侧配置流程

引导用户完成以下操作:

  1. 在自己的DNS服务商后台,添加一条CNAME记录,将自定义域名(比如store.example.com)指向其专属子域名(company.app.com)
  2. 可选:添加TXT记录完成域名所有权验证(比如_verify.store.example.com = 系统生成的随机令牌)

2. 应用侧绑定与验证

不要依赖实时解析CNAME(DNS缓存会导致延迟和性能问题),建议提前绑定:

  • 在租户后台添加「自定义域名」功能,让用户输入自己的域名
  • 系统自动验证:检查该域名的CNAME是否指向正确的租户子域名,或校验TXT记录是否匹配
  • 验证通过后,将自定义域名存储到Tenant模型的custom_domain字段

3. Nginx配置调整

Laravel Forge默认的服务器块是指定具体域名的,需要修改成支持所有域名:

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    listen 443 ssl default_server;
    listen [::]:443 ssl default_server;
    server_name _; # 匹配所有域名
    root /home/forge/app.com/public;

    # 通配符SSL证书(覆盖*.app.com),自定义域名建议让用户用Cloudflare SSL
    ssl_certificate /etc/nginx/ssl/app.com/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/app.com/privkey.pem;

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

    # 其他默认配置...
}

4. 自定义域名路由处理

扩展HandleTenancy中间件,支持自定义域名解析:

public function handle(Request $request, Closure $next)
{
    $host = $request->getHost();
    
    // 优先匹配自定义域名
    $tenant = Tenant::where('custom_domain', $host)->first();
    if ($tenant) {
        app()->instance(Tenant::class, $tenant);
        return $next($request);
    }
    
    // 匹配默认子域名格式
    if (str_ends_with($host, '.app.com')) {
        $tenantSlug = str_replace('.app.com', '', $host);
        $tenant = Tenant::where('slug', $tenantSlug)->firstOrFail();
        app()->instance(Tenant::class, $tenant);
        return $next($request);
    }
    
    // 未匹配到任何租户,引导至主站
    return redirect('https://app.com');
}
三、额外优化与注意事项
  • 日志隔离:修改Monolog配置,给每个租户的日志添加tenant_id标识,或按租户拆分日志文件,方便排查问题
  • 本地开发测试:修改本地hosts文件,添加127.0.0.1 test.app.com来模拟子域名访问
  • 性能优化:给tenant_id字段加复合索引(比如tenant_id + created_at),避免多租户场景下的全表扫描
  • SSL兼容性:自定义域名建议让用户通过Cloudflare等CDN配置SSL,避免你的服务器需要维护大量自定义域名证书

内容的提问来源于stack exchange,提问作者Nick Maddren

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 07:08:27