Laravel 多租户组件 spatie/laravel-multitenancy 指南

spatie/laravel-multitenancy 多租户组件,它可以帮助你快速实现 Laravel 多租户应用。比 tenancy/tenancy 更灵活。

数据库支持单库模式和1中心库+多租户库模式。多租户库模式下,用户表和用户tokens表可选择放在中心库,也可以放在租户库。

安装

1
2
3
4
5
composer require spatie/laravel-multitenancy
# 发布配置文件,生成 config/multitenancy.php 配置文件
php artisan vendor:publish --provider="Spatie\Multitenancy\MultitenancyServiceProvider" --tag="multitenancy-config"
# 在 database/migrations/landlord 目录下发布迁移文件,用于创建 tenants 表
php artisan vendor:publish --provider="Spatie\Multitenancy\MultitenancyServiceProvider" --tag="multitenancy-migrations"
1
2
3
4
5
6
7
Schema::create('tenants', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('domain')->unique(); // 用于外部传入id以切换租户,可以改成自己需要的
$table->string('database')->unique(); // 租户数据库
$table->timestamps();
});

配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
// config/multitenancy.php
return [
/*
* 这个类负责确定哪个租户应该是给定请求的最新租户。
* 必须继承 `Spatie\Multitenancy\TenantFinder\TenantFinder`
*/
'tenant_finder' => \App\Multitenancy\TenantFinder\HeaderTenantFinder::class,

/*
* 这些字段由`tender:artist`命令用于匹配一个或多个租户。
*/
'tenant_artisan_search_fields' => [
'id',
'tenant_code', // 默认是domain,根据自己需要修改
'database'
],

/*
* 这些任务将在切换租户时执行。
*
* 有效的任务是实现 `Spatie\Multitenance\Tasks\SwitchTenantTask` 的任何类
*/
'switch_tenant_tasks' => [
\Spatie\Multitenancy\Tasks\PrefixCacheTask::class,
\Spatie\Multitenancy\Tasks\SwitchTenantDatabaseTask::class,
\Spatie\Multitenancy\Tasks\SwitchRouteCacheTask::class,
],

/*
* 这个类是用于在租户上存储配置的模型。
*
* 必须是或继承 `Spatie\Multitenancy\Models\Tenant::class`
*/
'tenant_model' => \App\Models\Landlord\Tenant::class,

/*
* 如果在分派作业时有当前租户,则会在作业上自动设置当前租户的id。
* 执行作业时,作业上设置的租户将变为当前租户。
*/
'queues_are_tenant_aware_by_default' => true,

/*
* 用于连接租户数据库的连接名称。
*
* 如果设置为 `null`,则使用默认的数据库连接。
*/
'tenant_database_connection_name' => 'tenant',

/*
* 用于连接主数据库(Landlord 数据库)的连接名称。
*/
'landlord_database_connection_name' => 'landlord',

/*
* 此键名用于在 Laravel 服务容器(Container)中绑定当前租户实例。
*/
'current_tenant_container_key' => 'currentTenant',

/**
* 如果你希望使用 `SwitchRouteCacheTask` 将租户的路由缓存
* 到一个共享文件中,请将其设置为 `true`。
*/
'shared_routes_cache' => false,

/*
* 你可以通过自定义 Action(动作类)来定制该包的部分行为。
* 你的自定义 Action 必须继承自默认的 Action 类。
*/
'actions' => [
'make_tenant_current_action' => MakeTenantCurrentAction::class,
'forget_current_tenant_action' => ForgetCurrentTenantAction::class,
'make_queue_tenant_aware_action' => MakeQueueTenantAwareAction::class,
'migrate_tenant' => MigrateTenantAction::class,
],

/*
* 你可以自定义该包将队列任务(Queueable)解析为具体 Job 的方式。
*
* 例如,使用 laravel-actions 包(作者:Loris Leiva)时,
* 你可以将 JobDecorator 解析为 getAction(),配置如下:
* JobDecorator::class => 'getAction'
*/
'queueable_to_job' => [
SendQueuedMailable::class => 'mailable',
SendQueuedNotifications::class => 'notification',
CallQueuedClosure::class => 'closure',
CallQueuedListener::class => 'class',
BroadcastEvent::class => 'event',
],

/*
* 即使以下 Job 没有实现 TenantAware 接口,也会自动使其具备租户感知能力。
*/
'tenant_aware_jobs' => [
// ...
],

/*
* 即使以下 Job 没有实现 NotTenantAware 接口,也会强制使其失去租户感知能力。
*/
'not_tenant_aware_jobs' => [
// ...
],
];

自定义租户查找器

通过 X-Tenant-ID header 来确定当前租户。
在 config/multitenancy.php 中配置 tenant_finder 为这个类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php
namespace App\Multitenancy\TenantFinder;

use App\Models\Landlord\Tenant;
use Illuminate\Http\Request;
use Spatie\Multitenancy\TenantFinder\TenantFinder;

class HeaderTenantFinder extends TenantFinder
{
/**
* 3.x 签名:必须返回 Tenant 实例
*/
public function findForRequest(Request $request): \App\Models\Landlord\Tenant|null
{
// 这里可以换成子域名
$id = (int)trim($request->headers->get('X-Tenant-ID', ''));

if ($id === 0 || (!$tenant = Tenant::find($id))) {
abort(400, '无效的商户ID');
}

return $tenant;
}
}

模型集成

  • Spatie\Multitenancy\Models\Tenant 类有切换租户的能力。
  • Spatie\Multitenancy\Models\Concerns\UsesLandlordConnection 自动把模型数据库连接切换到中心库。
  • Spatie\Multitenancy\Models\Concerns\UsesTenantConnection 自动把模型数据库连接切换到租户库。

租户分配模型通过继承 Spatie\Multitenancy\Models\Tenant 类,使用 Spatie\Multitenancy\Models\Concerns\UsesLandlordConnection Trait来集成。
中心库模型使用 Spatie\Multitenancy\Models\Concerns\UsesLandlordConnection Trait 集成。
租户模型使用 Spatie\Multitenancy\Models\Concerns\UsesTenantConnection Trait 集成。

授权

App\Http\Kernel::$middlewareGroups 中添加:

1
2
3
4
5
6
7

'tenant' => [
// 获取当前租户
\Spatie\Multitenancy\Http\Middleware\NeedsTenant::class,
// 用 session 的时候需要添加
// \Spatie\Multitenancy\Http\Middleware\EnsureValidTenantSession::class,
],

在路由中使用中间件:

1
2
3
4
5
6
Route::middleware(['tenant', 'auth:sanctum'])->group(function () {
Route::get('/api/xxx', function () {
// 这里已经切换到租户数据库连接
$user = request()->user();
});
});

使用了 tenant 中间件后,自动调用 HeaderTenantFinder::findForRequest() 查找到租户,并切换到租户数据库。

tenant 和 auth:sanctum 放的顺序很重要。
如果用户表放在中心库,那么 auth:sanctum 中间件必须放在 tenant 中间件之前。
如果用户表放在租户库,那么 tenant 中间件必须放在 auth:sanctum 中间件之前,并且还要设置中间件的优先级,把
\Spatie\Multitenancy\Http\Middleware\NeedsTenant::class, 放到 App\Http\Kernel::$middlewarePriority 最前面。

App\Http\Kernel 没看到 $middlewarePriority,则到父类连其列表值一起复制下来。

临时切换切换到租户数据库

$tenant->execute(closure):临时切换、自动恢复、安全隔离。
只在闭包内生效,执行完自动切回原来的租户 / 主库,不会污染全局状态。

1
2
3
4
$tenant = Spatie\Multitenancy\Models\Tenant::find(1);
$tenant->execute(function() {
// 这里可以执行租户数据库的操作
});

永久切换切换到租户数据库

$tenant->makeCurrent():永久切换(直到手动改)、全局生效、需手动恢复。
一旦调用,整个后续请求生命周期都用这个租户库,直到你 forgetCurrent() 或切别的租户。

1
2
3
$tenant = Spatie\Multitenancy\Models\Tenant::find(1);
// 直接把当前租户数据库连接切换到租户库
$tenant->makeCurrent();

最简单的集成方式

上面的集成方式比较优雅,通过子域名或header来集成。

最简单的集成方式是通过URL参数来集成。

  1. 这个方式不需要实现 App\Multitenancy\TenantFinder\TenantFinder 类。
    在 config/multitenancy.php 中配置 tenant_finder 为 ``。

  2. 不需要添加切换租户的路由中间件。

例如:

1
2
3
4
5
Route::get('/api/{tenant}/other', function ($tenant) {
$tenant->execute(function() {
// 这里已经切换到租户数据库连接了
});
});

这个方式的缺点是不优雅,所有路由都需要添加租户参数、所有调用租户数据库的地方都是通过 $tenant->execute(closure) 来切换租户。

SQLServer 2019 导出SQL迁移数据到 SQLServer 2016

右键源数据库 → 任务(T)​ → 生成脚本(G)…
选择对象:选 “选择特定数据库对象”​ → 勾选要导出的表 (导入存储过程有可能会报错,不勾选)
设置脚本选项:输出选 “保存到文件”

点 高级(A)…(⚠️ 关键)

设置为:

为服务器版本编写脚本​ ✅ SQL Server 2016 (130)​
要编写脚本的数据的类型​ ✅ 架构和数据 (Schema and data)​
编写扩展属性​ ❌ False(避免你遇过的 15135 报错)
编写索引 / 主键 / 外键 ✅ True

SqlServer2016 快照同步

公司ERP产品有多个客户,每个客户都有自己的数据库实例。

现在公司实现一个数据分析统计平台,需要从每个客户的数据库实例中同步数据到数据分析服务器。

要求实时性不高,数据每天凌晨单向同步一次。

SQL Server 2016 快照复制(Snapshot Replication)是为我们量身定制的唯一最优解。

完美满足所有条件:

  • 单向同步
  • 一天一次定时
  • 同步后目标=源数据
  • 性能极好
  • 完全不影响主库
  • 最易部署、最易维护
  • 零代码、零脚本、零开发

3 步极速部署(10 分钟搞定)

前提条件

  1. 源库和目标库网络互通
  2. 源表必须有主键(所有业务表都有)
  3. 两台服务器都启动 SQL Server 代理(必须启动)

第一步:配置发布(源数据库)

  1. 打开 SSMS → 找到 复制 → 右键 新建 → 发布
  2. 选择源数据库 → 下一步
  3. 选择 快照发布 → 下一步
  4. 勾选要同步的(可多选)→ 下一步
  5. 关键:创建快照计划
    • 选择 每天 02:00 执行(避开业务时间)
  6. 勾选 立即创建快照(初始化用)
  7. 设置快照文件夹(开启压缩,跨网络更快)
  8. 安全账户选择 SQL 账号 → 完成

第二步:配置订阅(目标数据库)

  1. 右键 订阅 → 新建订阅
  2. 选择 查找 SQL Server 发布服务器 → 输入源服务器SQLServer的IP,端口,账号密码 → 连接
  3. 选择刚才创建的发布 → 下一步
  4. 选择 推送订阅(性能最好、最省心)
  5. 选择 点击 添加订阅服务器 ,填写目标服务器IP,端口、账号密码,把目标服务器添加到订阅服务器列表中。这里关键一点是:源服务器和目标服务器不是同一台服务器的时候,填写的目标服务器IP端口要求必须是源服务器可达的,不能是内网IP或主机名等。
  6. 选择 勾选 订阅服务器, 选择 目标库 → 下一步
  7. 选择 订阅服务器代理 后面的三个点,上面输入源服务器的 主机名\用户名、登录密码;连接到订阅服务器设置目标服务器数据库账号、密码。
  8. 一直 下一步 到完成。

第三步:验证

等待第一次同步完成
目标库数据 = 源库数据,完全一致

Linux 解决 Laravel 命令行与 Web 进程用户不一致的权限问题

在 Ubuntu 环境中,日常部署代码、执行 Composer 与 Artisan 命令,一般使用 ubuntu 普通用户;
而 Nginx、PHP-FPM 等 Web 服务默认以低权限用户 www-data 运行。

CLI 命令行用户与 Web 运行用户不一致,会直接造成 storagebootstrap/cache 目录读写拒绝、缓存生成失败、日志写入异常等权限问题。

一、统一用户方案

通过让 Web 与命令行共用同一运行用户,从根源规避权限冲突,分为两种实现方式:

1. Web 进程统一使用 ubuntu 用户

修改 PHP-FPM 配置,将进程执行用户改为 ubuntu
操作简单、彻底杜绝权限报错,日常维护最省心。

缺点是会扩大 Web 进程权限范围,存在一定安全隐患。
适合场景:单机单站、个人项目、自用服务、开发/自建生产环境。

2. 命令行统一使用 www-data 用户

保持 PHP-FPM 默认 www-data 隔离权限,执行 Laravel 相关命令时,手动切换为该用户运行。

示例:

1
sudo -u www-data php artisan view:cache

优势是保留系统原生安全隔离,适配企业生产、多站点服务器;
劣势为每次执行 Artisan、Composer 都需要追加用户切换命令,操作繁琐且容易遗漏。

二、附属组 + SGID 标准隔离方案(生产推荐)

该方案是 Laravel 生态公认最佳实践,兼顾安全性与运维便捷性,也是线上生产环境的主流配置。

核心思路: 不改动 Web 服务默认运行用户,通过附属组授权 + SGID 目录继承权限,让两个不同用户互相读写项目临时目录。

  1. ubuntu 追加加入 www-data 附属组,保留原有用户组权限不变;

务必使用 usermod -aG 追加模式,**不可省略 -a**,避免覆盖原有附属组导致权限丢失。

  1. 对读写高频目录绑定归属组,并配置 SGID 权限,使新文件自动继承目录属组,永久解决文件属主错乱问题。

执行命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 追加用户至 www-data 组
sudo usermod -aG www-data ubuntu

# 关键读写目录统一归属 www-data
sudo chown -R www-data:www-data storage bootstrap/cache


# 给文件(及目录) 664 权限
sudo chmod -R 664 storage/* bootstrap/cache/*

# 递归给目录 775 权限
sudo find storage -type d -exec chmod 775 {} \;
sudo find bootstrap/cache -type d -exec chmod 775 {} \;

# 配置 SGID,新建文件/目录自动继承所属组
sudo chmod -R g+s storage bootstrap/cache


# 退出 ubuntu 用户后重新登录,即可生效

这样,名ubuntu用户执行 Artisan 命令时,在 storage 或 bootstrap/cache 目录生成的文件用户为 ubuntu:www-data,php-fpm 生成的文件用户为 www-data:www-data,两者都可以对项目临时目录进行读写操作。

拓展:若业务安全要求极高,可搭配 Ubuntu ACL 精细化授权,进一步收紧权限范围,本文不做展开。

老版本 Chrome/Chromium 下载

问题

1、今年11月给客户做几个统计页面,链接到他们的Erp桌面客户端,基于 Chromium 75的。

2、去年给客户定做的 Erp 安卓客户端,带扫描头的手持终端设备,主要机型是 Android 6。这种一个人做完的项目,开发周期又短,必须是基于 Webview 来做,也就是包一层,用 web 来实现。

设备升级到最新版固件后,自带 Webview 版本是 Chrome/61.0.3163.98。

要解决这个问题,有3 种方法:

  1. 整合一个新版的chrome到app中。
  2. 用 GeckoView 来代替 Webview。
  3. 用系统自带的老版本的 Chrome。

对于安卓6来说,方案1和2可行性都不高,只能用方案3。

项目前端用 Vue2 + vant2,对于从 纯JS -> jQuery -> Vue1 -> Vue2 -> Vue3 都经历过的人来说,前端实现当然没啥问题,兼容性问题的测试是个主要问题,现在需要一个 Chromium 61 来调试。

下载

如果你需要的版本是 92 及以上的,可以在这里选择下载:https://vikyd.github.io/download-chromium-history-version/

如果需要更早的,到下面的链接慢慢扒拉。

http://commondatastorage.googleapis.com/chromium-browser-continuous/index.html

存档文件版本号跟浏览器发布版本号不一同,对应版本太难找?先从下面的连接看发布日期。
https://www.chromium.org/developers/calendar/

避坑,这些链接下载的安装包不能装

微信开发者工具开发企业微信时,怎样切换企业?

开发企业微信小程序时,同一个项目,切换 appid 时,如果app 属于不同的企业微信账号,则需要切换企业才能在模拟器中正常预览。否则调用 wx.qy.login()时会出现错误信息: {code: “”, errMsg: “qy__login:fail”},如果不出现这个错误,获取到的 corpiduserid 还是属于之前企业微信号的。

切换企业操作:

在微信开发者工具中 模拟器 的上方,点击模拟操作按钮(手机形状图标),点击【选择企业】,选择企业微信对应企业即可。

PHP 扩展管理工具 PIE

PHP PIE(PHP Installer for Extensions)是 PHP 官方推出的一款现代化扩展管理工具,旨在简化 PHP 扩展的安装与管理流程,被视为 PECL(PHP 扩展社区库)的潜在替代方案。

首个公开版本发布于 2023 年下半年,具体而言,其在 GitHub 上的首个正式发布版本(v0.1.0)于 2023 年 9 月推出。这一工具由 PHP 基金会主导开发,旨在为 PHP 扩展管理提供更现代化、自动化的解决方案,逐步替代传统的 PECL 工具。

自首次发布以来,PHP PIE 持续迭代更新,不断扩展支持的扩展范围并优化功能,截至目前(2025 年)已推出多个版本,成为 PHP 生态中备受关注的扩展管理工具。其发展节奏与 PHP 基金会对现代化工具链的推进策略相契合,进一步巩固了在 PHP 扩展管理领域的地位。

以下是其核心特性和使用要点:

核心特性

1.类似 Composer 的使用体验

采用简洁的命令行语法,类似composer的操作逻辑,例如:

1
2
pie install xdebug/xdebug  # 安装Redis扩展
pie install xdebug/xdebug:^3.2 # 安装指定版本的Xdebug

2.自动化处理流程

  • 自动从 Packagist 获取扩展包,无需手动查找资源。
  • 自动编译扩展(Linux/macOS)或使用预编译 DLL(Windows)。
  • 自动修改 php.ini 配置文件,添加扩展加载指令(如 extension=redis)。

3.多 PHP 版本支持

可指定为不同 PHP 版本安装扩展,例如:

1
pie install mongodb/mongodb --php /usr/bin/php8.4  # 为PHP 8.4安装MongoDB扩展

4.与现代开发流程兼容

支持在 CI/CD 管道中自动化安装扩展,无缝融入项目的自动化部署流程。你可以在 shell 脚本中添加 pie install 命令,实现自动安装扩展,也可以在 Docker 配置中指定安装哪些模块。

使用前提

  • 运行环境需 PHP 8.1 及以上版本(PIE 自身依赖),但可管理其他 PHP 版本的扩展。
  • Linux/macOS 需安装编译工具链(如gcc、make);
  • Windows 依赖扩展作者提供的预编译 DLL。

安装与配置

  1. 下载pie.phar(官方发布地址:GitHub)。
    curl -O https://github.com/php/pie/releases/latest/download/pie.phar

  2. 配置为全局命令(Linux/macOS 太容易搞定,我们就以 Windows 为例):

    • pie.phar 保存到 D:\portable\pie\ 目录。
    • 创建 pie.bat 文件,内容为: php "%~dp0pie.phar" %*
    • D:\portable\pie\ 添加到系统环境变量 Path 中,这样就可以直接在命令行使用pie命令了。
  3. 验证安装:在命令行中运行 pie -V,若显示版本信息则安装成功。

扩展安装位置

pie.phar 如果与执行php.exe在同一个目录,那么扩展默认安装到 ~/ext 文件夹中,否则默认安装到 pie.phar 所在目录的 ext 文件夹中。

适用场景与局限

  • 推荐场景:
    • 基于 PHP 8.1 + 的新项目
    • 需要自动化管理扩展的 CI/CD 流程
    • 主流扩展(如 Redis、Xdebug、MongoDB)的安装管理
  • 当前局限:
    • 扩展覆盖度不及 PECL,部分冷门扩展暂不支持(可在这里查看已支持的PHP扩展
    • Windows 环境依赖预编译 DLL,部分扩展可能无法安装
    • 暂未提供扩展卸载功能,需手动操作

解决 docker 报错 Error response from daemon

直接在浏览器中打开网址 https://registry-1.docker.io/v2/ 连不上,说明网络有问题。
原因是网络连接失败,原因你知道。

加入 dns 配置,修改镜像源

修改配置文件 /etc/docker/daemon.json, Windows 为 C:\Users\用户名\.docker\daemon.json 文件,加入如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
"dns": [
"8.8.8.8",
"8.8.4.4"
],
"registry-mirrors": [
"https://docker.m.daocloud.io/",
"https://huecker.io/",
"https://dockerhub.timeweb.cloud",
"https://noohub.ru/",
"https://dockerproxy.com",
"https://docker.mirrors.ustc.edu.cn",
"https://docker.nju.edu.cn",
"https://xx4bwyg2.mirror.aliyuncs.com",
"http://f1361db2.m.daocloud.io",
"https://registry.docker-cn.com",
"http://hub-mirror.c.163.com",
"https://mirror.ccs.tencentyun.com"
]

重启 docker 服务

Windows 下如果重启无效,可退出 Docker Desktop 再打开。

如何在 WebStorm 中调试 AdonisJS 项目,超详细教程来了!

AdonisJS 官方文档虽然详尽地涵盖了 VSCode 的调试指南,却没有关于 Jetbrains 系列产品的相应调试说明。
了解 Jetbrains 产品的调试配置以后,要配置 WebStorm 来调试 AdonisJS 其实是非常容易的。

步骤一: 创建或编辑运行/调试配置

用 WebStorm 打开你的 AdonisJS 项目后,点击调试工具栏上的下拉菜单,点击编辑配置。

在弹出的窗口中,点击右上角的“+”按钮,选择“Node.js”作为调试类型,然后(如下图)输入配置信息。

  • 【名称】输入调试配置的名称,便于识别。
  • 【Node 解释器】选择项目所使用的 Node 解释器。
  • 【工作目录】为项目根目录。
  • 【应用程序形参】输入 ace serve --hmr

步骤二: 启动调试

点击调试工具栏的下拉菜单,选择刚加的调试配置(如下图)

然后再点击调试按钮(那只小虫子,如下图),或者按 Shift + F9 快捷键,就可以启动调试了。

启动调试后,只要给程序执行经过位置加上断点,程序执行到断点处就会暂停下来,这样我们就可以查看程序当前执行所在位置的各个变量的值了。

具体调试操作就不多说了,你自己能搞定。

Certbot 部署 Nginx 免费 SSL 证书

在 Linux 上使用 Certbot 为 Nginx 部署 SSL 证书是一个很简单的过程,只需要执行几个命令就可以。
以下演示在 Ubuntu/Debian 上通过 Certbot 为 Nginx 服务器获取并安装SSL证书,其他 Linux 系统安装命令类似。

安装 Nginx

首先,确保你的 Ubuntu/Debian 服务器上已经安装了 Nginx。如果还没有安装,可以使用以下命令进行安装:

1
2
sudo apt update
sudo apt install nginx

部署 Nginx http 站点

先部署好 Nginx http 站点,certbot-nginx 插件将自动往 Nginx 配置中加入 SSL 部署配置。

安装 Certbot 及其 Nginx 插件

1
2
sudo apt install certbot python3-certbot-nginx
#sudo apt install certbot python3-certbot-apache # Apache 可使用此命令

获取并安装SSL证书

安装 Certbot 和 Nginx 都安装后,你可以使用 Certbot 的 Nginx 插件来自动为你的网站获取并安装SSL证书。运行以下命令:

1
2
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
#sudo certbot --apache -d yourdomain.com -d www.yourdomain.com # Apache 可使用此命令

记得将 yourdomain.com 替换为你的实际域名。

执行此命令, Certbot 将执行以下操作:

  • 自动检测你的 Nginx 配置。
  • 提示你验证对域名的所有权(通过请求域名 HTTP 站点)。
  • 获取 Let’s Encrypt 的 SSL 证书。
  • 自动修改 Nginx 配置文件,以使用新的 SSL 证书和密钥。
  • 重新加载 Nginx 以应用更改。
  • 加入定时更新证书的系统任务。