Laravel SaaS平台实现用户自定义域名绑定的自动化方案咨询
Laravel SaaS 自定义域名实现方案(无需手动配置虚拟主机)
完全可以在Laravel框架内配合Web服务器配置实现,不用再手动添加虚拟主机条目,下面是实战落地步骤:
1. 先搞定Web服务器配置(以Nginx为例)
- 把服务器配置成通配符监听,直接用
server_name _;,这样不管用户用子域名还是自定义域名,请求都会转到Laravel的public目录。示例配置片段:
server { listen 80; listen 443 ssl; server_name _; root /path/to/your/laravel/public; index index.php; # SSL配置:用泛域名证书(如*.domain.com)或多域名证书覆盖所有场景 ssl_certificate /path/to/ssl/cert.pem; ssl_certificate_key /path/to/ssl/key.pem; location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { fastcgi_pass unix:/var/run/php/php8.2-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; include fastcgi_params; } }
- 注意:自定义域名的HTTPS需要泛域名证书支持,可通过Let's Encrypt免费申请。
2. Laravel内的域名解析逻辑
- 数据库字段:在
users表新增两个字段:subdomain(存储用户默认子域名,如myapp)和custom_domain(存储验证通过的自定义域名,允许为空)。 - 域名解析中间件:写一个全局中间件
ResolveDomain,用来识别当前请求对应的用户:
<?php namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; use App\Models\User; class ResolveDomain { public function handle(Request $request, Closure $next) { $host = $request->getHost(); // 优先匹配自定义域名 $user = User::where('custom_domain', $host)->first(); // 未匹配到则尝试匹配子域名 if (!$user && str_ends_with($host, '.domain.com')) { $subdomain = str_replace('.domain.com', '', $host); $user = User::where('subdomain', $subdomain)->first(); } // 将用户实例绑定到请求,后续业务可直接调用 if ($user) { $request->attributes->set('current_user', $user); app()->instance('current_user', $user); } return $next($request); } }
- 把这个中间件添加到
app/Http/Kernel.php的全局中间件数组中,确保所有请求都经过解析。 - 路由兼容:子域名路由可正常使用
Route::domain('{subdomain}.domain.com'),自定义域名请求会通过中间件匹配到用户,复用相同业务路由即可。
3. 必须做的域名归属验证
用户提交自定义域名后,必须验证域名归属,防止恶意绑定:
- DNS验证:生成随机字符串,让用户在域名DNS解析中添加一条TXT记录(如
_laravel-verification.anotherdomain.com对应生成的字符串),系统通过DNS查询工具验证记录是否存在。 - 文件验证:生成唯一文件名(如
laravel-verification-xxxxxx.txt),让用户将该文件上传到域名根目录,文件内容为指定字符串。系统发起GET请求检查返回内容是否匹配。 - 只有验证通过后,才更新用户表的
custom_domain字段。
4. 静态资源与Session适配
- 静态资源:优先用CDN托管静态资源,或在
.env中设置ASSET_URL为CDN地址,避免不同域名下静态资源路径出错。若不用CDN,确保asset()生成当前域名的绝对路径。 - Session配置:在
.env中设置SESSION_DOMAIN=null,让Cookie自动适配当前请求域名,避免自定义域名下无法读取Session的问题。
5. 性能优化:缓存域名映射
每次请求查数据库会有性能损耗,建议将域名与用户ID的映射缓存到Redis/Memcached:
- 用户绑定/修改域名时更新缓存:
Cache::put("domain:{$host}", $user->id, 3600); - 中间件中优先查缓存,再查数据库:
$userId = Cache::get("domain:{$host}"); if ($userId) { $user = User::find($userId); } else { // 原数据库查询逻辑,查询到后存入缓存 }
内容的提问来源于stack exchange,提问作者Eyad Bereh
相关产品推荐
相关产品推荐

