Laravel多租户应用单容器配置多子域名与环境变量可行性咨询
实现单容器Laravel多租户动态数据库切换(基于子域名)
可以实现,但不能给单个容器配置多个静态环境变量,因为容器的环境变量是启动时固定的。要满足你的需求,核心思路是:通过子域名识别租户,在Laravel运行时动态切换数据库连接,而非依赖容器的静态ENV_VARIABLES。
具体实现步骤
1. 反向代理层处理子域名(以Nginx为例)
单容器需要接收所有子域名的请求,前端需配置Nginx反向代理,解析子域名并传递租户标识到Laravel:
server { listen 80; # 匹配所有子域名,捕获学校标识 server_name ~^(?<school>[a-z0-9-]+)\.yourdomain\.com; location / { proxy_pass http://your-laravel-container:80; # 将捕获的学校标识通过请求头传给Laravel proxy_set_header X-School $school; # 传递原始Host头(可选,Laravel也可直接解析Host获取子域名) proxy_set_header Host $host; } }
2. Laravel中编写动态切换数据库的中间件
创建全局中间件,用于识别租户并切换数据库连接:
- 生成中间件:
php artisan make:middleware TenantDatabaseMiddleware
- 编辑中间件代码(
app/Http/Middleware/TenantDatabaseMiddleware.php):
<?php namespace App\Http\Middleware; use Closure; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\DB; use Illuminate\Http\Request; class TenantDatabaseMiddleware { public function handle(Request $request, Closure $next) { // 从请求头获取学校标识, fallback到解析Host头的子域名 $schoolIdentifier = $request->header('X-School') ?? explode('.', $request->getHost())[0]; // 可选:验证学校标识合法性,比如从系统配置表查询是否存在 // $validSchool = \App\Models\School::where('domain_identifier', $schoolIdentifier)->firstOrFail(); // 根据标识拼接数据库名(按你的命名规则调整) $databaseName = "school_{$schoolIdentifier}"; // 动态修改数据库连接配置 Config::set('database.connections.tenant.database', $databaseName); // 设置为默认连接,或在模型中指定$connection = 'tenant' DB::setDefaultConnection('tenant'); return $next($request); } }
- 在
app/Http/Kernel.php中注册中间件,加到web或api中间件组:
protected $middlewareGroups = [ 'web' => [ // ...其他中间件 \App\Http\Middleware\TenantDatabaseMiddleware::class, ], ];
3. 配置Laravel数据库连接
在config/database.php中添加租户专用连接配置(复用基础数据库参数):
'connections' => [ // ...默认mysql配置 'tenant' => [ 'driver' => 'mysql', 'host' => env('DB_HOST', '127.0.0.1'), 'port' => env('DB_PORT', '3306'), 'database' => '', // 留空,由中间件动态设置 'username' => env('DB_USERNAME', 'root'), 'password' => env('DB_PASSWORD', ''), // ...其他配置(charset、collation等) ], ],
4. 容器部署注意事项
- 容器只需设置基础数据库连接环境变量,不需要
DB_DATABASE:docker run -d \ -e DB_HOST=your-db-server \ -e DB_USERNAME=db-user \ -e DB_PASSWORD=db-pass \ --name laravel-multitenant \ your-laravel-image - 确保数据库服务器允许容器IP访问,且所有学校对应的数据库已提前创建。
- 若使用Docker Compose,只需在服务配置中声明上述基础环境变量即可。
不推荐的方案:单容器多进程
如果硬要使用不同环境变量的方式,只能在容器内用进程管理器(如supervisord)启动多个Laravel服务实例,每个实例绑定不同子域名和环境变量,但会造成资源浪费,且不符合多租户共用代码库的优雅设计,不建议采用。
内容的提问来源于stack exchange,提问作者Ation
相关产品推荐
相关产品推荐

