+
::: warning 注意
对PuTTY的任何设置更新都要再次手动保存Session,不然关闭后就会丢失
-:::
-
-
+:::
4. 点击 Open 就会进入SSH连接窗口,对应下图输入用户名与密码,与你的VPS远程主机建立连接。(本文假设默认用户名是 `root`,另外,在Linux系统输入密码的时候,是不会出现 `******` 这种提示符的,这样可以避免密码长度泄漏,不是你的键盘坏掉了哦!)
@@ -86,4 +86,4 @@
**恭喜你又迈出了坚实的一步!** 现在,你已经可以通过SSH来登录你的远程服务器了!那登录进去之后,除了升级软件之外,应该再做点什么呢?敬请进入下一章一探究竟吧!
-> `⬛⬛⬛⬜⬜⬜⬜⬜ 37.5%` :::
+> ⬛⬛⬛⬜⬜⬜⬜⬜ 37.5%
diff --git a/docs/document/level-0/ch04-security.md b/docs/document/level-0/ch04-security.md
index 651f682a..7c82a17e 100644
--- a/docs/document/level-0/ch04-security.md
+++ b/docs/document/level-0/ch04-security.md
@@ -79,9 +79,9 @@ Linux服务器的安全防护是一个纷繁复杂的巨大课题。无数的网
- 说明:如果这一行开头有个`#`,证明这一行【不生效】(被注释掉了),你可像我一样在文件最后写一个不带`#`的,或者把`#`删掉就好。
-::: warning 注意
-本文以`9753`为例,就意味着随着本文的发布,这个端口会变成一个不大不小的特征,也许会被攻击者优先尝试、也许被GFW干扰、阻断。所以我强烈建议你用一个自己想到的其他端口,毕竟,你有6万多个端口可以自由选择。
-:::
+ ::: warning 注意
+ 本文以`9753`为例,就意味着随着本文的发布,这个端口会变成一个不大不小的特征,也许会被攻击者优先尝试、也许被GFW干扰、阻断。所以我强烈建议你用一个自己想到的其他端口,毕竟,你有6万多个端口可以自由选择。
+ :::
6. 我们要做的第三件事,是【保存文件并退出】
@@ -153,11 +153,11 @@ Linux服务器的安全防护是一个纷繁复杂的巨大课题。无数的网
在 `User Privilege Specification` 下加入一行 `vpsadmin ALL=(ALL) NOPASSWD: ALL` 即可。
-::: warning 注意
-我要特别说明的是`NOPASSWD`这个设置,它的意思是`vpsadmin`用户临时使用`root`权限时,不用额外输入密码。**这与一般的安全建议相反**。我之所以如此推荐,是因为很多新人不顾危险坚持使用`root`账号就是因为用`root`时不用重复输入密码、觉得轻松。“两害相权取其轻”,我认为【直接用`root`用户的风险】大于【使用`sudo`时不用输密码的风险】,所以做了以上的建议。
+ ::: warning 注意
+ 我要特别说明的是`NOPASSWD`这个设置,它的意思是`vpsadmin`用户临时使用`root`权限时,不用额外输入密码。**这与一般的安全建议相反**。我之所以如此推荐,是因为很多新人不顾危险坚持使用`root`账号就是因为用`root`时不用重复输入密码、觉得轻松。“两害相权取其轻”,我认为【直接用`root`用户的风险】大于【使用`sudo`时不用输密码的风险】,所以做了以上的建议。
-如果你希望遵守传统习惯、每次使用`sudo`时需要输入密码,那么这一行改成 `vpsadmin ALL=(ALL:ALL) ALL` 即可。
-:::
+ 如果你希望遵守传统习惯、每次使用`sudo`时需要输入密码,那么这一行改成 `vpsadmin ALL=(ALL:ALL) ALL` 即可。
+ :::
7. 完整流程演示如下:
@@ -223,9 +223,9 @@ Linux服务器的安全防护是一个纷繁复杂的巨大课题。无数的网
1. 点击`Generate`开始生成(在界面空白处乱晃鼠标增加随机数)
-::: warning 注意
-本图中是以 `2048` 位的 `RSA` 密钥为例的。但实际上,如果要获得与 `EDCSA/Ed25519` 的 `256` 位密钥相同的安全性,你需要使用 `3072` 位的 `RSA` 密钥。(即右下角的数字改成 `3072`)
-:::
+ ::: warning 注意
+ 本图中是以 `2048` 位的 `RSA` 密钥为例的。但实际上,如果要获得与 `EDCSA/Ed25519` 的 `256` 位密钥相同的安全性,你需要使用 `3072` 位的 `RSA` 密钥。(即右下角的数字改成 `3072`)
+ :::
2. 你可以给私钥设置密码,增加一层安全性
3. 点击 `Save public key` 保存公钥,文件名为 `id_rsa.pub`
@@ -317,4 +317,4 @@ Linux服务器的安全防护是一个纷繁复杂的巨大课题。无数的网
现在我们终于有了一个安全的系统基础,下一章,我们就可以开始逐步安装配置Xray需要的基础设施了!(什么基础设施呢?一个网页,一张证书)
-> `⬛⬛⬛⬛⬜⬜⬜⬜ 50%` :::
+> ⬛⬛⬛⬛⬜⬜⬜⬜ 50%
diff --git a/docs/document/level-0/ch05-webpage.md b/docs/document/level-0/ch05-webpage.md
index ec41d5d2..11d4ebd0 100644
--- a/docs/document/level-0/ch05-webpage.md
+++ b/docs/document/level-0/ch05-webpage.md
@@ -101,11 +101,9 @@
}
```
-
-::: warning 特别注意!
-如我在【第3步】中的提示所说,请务必确保 `/home/vpsadmin/www/webpage` 改成你的实际文件路径。
-:::
-
+ ::: warning 特别注意!
+ 如我在【第3步】中的提示所说,请务必确保 `/home/vpsadmin/www/webpage` 改成你的实际文件路径。
+ :::
3. 让 `nginx` 重新载入配置使其生效
```
@@ -152,4 +150,4 @@
至此,Xray的第一个基础设施【网页】已经就位,我们马上就进入第二个基础设施【证书】吧!
-> `⬛⬛⬛⬛⬛⬜⬜⬜ 62.5%` :::
+> ⬛⬛⬛⬛⬛⬜⬜⬜ 62.5%
diff --git a/docs/document/level-0/ch06-certificates.md b/docs/document/level-0/ch06-certificates.md
index 02a93ea6..8ec5585f 100644
--- a/docs/document/level-0/ch06-certificates.md
+++ b/docs/document/level-0/ch06-certificates.md
@@ -48,14 +48,14 @@
$ acme.sh --issue --test -d 二级域名.你的域名.com -w /home/vpsadmin/www/webpage --keylength ec-256
```
-::: warning 说明
-`ECC`证书的主要优势在于它的Keysize更小,意味着同等大小下安全性的提升和加密解密速度的加快。如 ECC-256bit 的强度大约相当于 RSA-3072bit,何乐而不为呢?当然,有人说ECC证书握手会明显更快,这我觉得就有些夸张了,因为RSA握手也没有太慢,就算有差别应该也是毫秒级,很难直接感知。
+ ::: warning 说明
+ `ECC`证书的主要优势在于它的Keysize更小,意味着同等大小下安全性的提升和加密解密速度的加快。如 ECC-256bit 的强度大约相当于 RSA-3072bit,何乐而不为呢?当然,有人说ECC证书握手会明显更快,这我觉得就有些夸张了,因为RSA握手也没有太慢,就算有差别应该也是毫秒级,很难直接感知。
-另外,如果有些网站确实需要兼容某些古老设备的,那也还是请按需选择`RSA`证书。
-:::
+ 另外,如果有些网站确实需要兼容某些古老设备的,那也还是请按需选择`RSA`证书。
+ :::
2. 你最终应该看到类似这样的提示:
- ```
+ ``` log
[Wed 30 Dec 2022 04:25:12 AM EST] Using ACME_DIRECTORY: https://acme-staging-v02.api.letsencrypt.org/directory
[Wed 30 Dec 2022 04:25:13 AM EST] Using CA: https://acme-staging-v02.api.letsencrypt.org/directory
[Wed 30 Dec 2022 04:25:13 AM EST] Create account key ok.
@@ -76,7 +76,7 @@
[Wed 30 Dec 2022 04:25:25 AM EST] Downloading cert.
[Wed 30 Dec 2022 04:25:25 AM EST] Le_LinkCert='https://acme-staging-v02.api.letsencrypt.org/acme/cert/xujss5xt8i38waubafz2xujss5xt8i38waubz2'
[Wed 30 Dec 2022 15:21:52 AM EST] Cert success.
---BEGIN CERTIFICAT--
+ --BEGIN CERTIFICAT--
sxlYqPvWreKgD5b8JyOQX0Yg2MLoRUoDyqVkd31PthIiwzdckoh5eD3JU7ysYBtN
cTFK4LGOfjqi8Ks87EVJdK9IaSAu7ZC6h5to0eqpJ5PLhaM3e6yJBbHmYA8w1Smp
wAb3tdoHZ9ttUIm9CrSzvDBt6BBT6GqYdDamMyCYBLooMyDEM4CUFsOzCRrEqqvC
@@ -101,7 +101,7 @@
NZFQWYJLNVf2M9CCJfbEImPYgvctrxl39H6KVYPCw1SAdaj9NneUqmREOQkKoEB0
x6PmNirbMscHhQPSC0JQaqUgaQFgba1ALmzRYAnYhNb0twkTxWbY7DBkAarxqMIp
yiLKcBFc5H7dgJCImo7us7aJeftC44uWkPIjw9AKH=
---END CERTIFICAT--
+ --END CERTIFICAT--
[Wed 30 Dec 2022 15:21:52 AM EST] Your cert is in /home/vpsadmin/.acme.sh/二级域名.你的域名.com_ecc/二级域名.你的域名.com.cer
[Wed 30 Dec 2022 15:21:52 AM EST] Your cert key is in /home/vpsadmin/.acme.sh/二级域名.你的域名.com_ecc/二级域名.你的域名.com.key
[Wed 30 Dec 2022 15:21:52 AM EST] The intermediate CA cert is in /home/vpsadmin/.acme.sh/二级域名.你的域名.com_ecc/ca.cer
@@ -111,6 +111,7 @@
3. 注意:这里申请的是测试证书,没办法直接用的,只是用来证明你的域名、配置全都正确。仔细观察,你会发现给你发证书的域名是 `https://acme-staging-v02.api.letsencrypt.org`,这个 `staging` 你就理解成【测试服】吧!
4. 如果这一步出错的话,你可以运行下面的命令,来查看详细的申请过程和具体的错误。(看不懂就隐藏掉敏感信息后,去Xray群里问吧)
+
```
$ acme.sh --issue --test -d 二级域名.你的域名.com -w /home/vpsadmin/www/webpage --keylength ec-256 --debug
```
@@ -128,12 +129,12 @@
$ acme.sh --issue -d 二级域名.你的域名.com -w /home/vpsadmin/www/webpage --keylength ec-256 --force
```
-::: warning 说明
-`--force` 参数的意思就是,在现有证书到期前,手动(强行)更新证书。上一步我们从“测试服”申请的证书虽然不能直接用,但是它本身是尚未过期的,所以需要用到这个参数。
-:::
+ ::: warning 说明
+ `--force` 参数的意思就是,在现有证书到期前,手动(强行)更新证书。上一步我们从“测试服”申请的证书虽然不能直接用,但是它本身是尚未过期的,所以需要用到这个参数。
+ :::
2. 你最终应该看到跟上面很像的提示:
- ```
+ ``` log
vpsadmin@vps-server:~$ acme.sh --issue -d 二级域名.你的域名.com -w /home/vpsadmin/www/webpage --keylength ec-256
[Wed 30 Dec 2022 15:22:51 AM EST] Using CA: https://acme-v02.api.letsencrypt.org/directory
[Wed 30 Dec 2022 15:22:51 AM EST] Creating domain key
@@ -150,7 +151,7 @@
[Wed 30 Dec 2022 15:22:51 AM EST] Downloading cert.
[Wed 30 Dec 2022 15:22:51 AM EST] Le_LinkCert='https://acme-v02.api.letsencrypt.org/acme/cert/vsxvk0oldnuobe51ayxz4dms62sk2dwmw9zhuw'
[Wed 30 Dec 2022 15:22:51 AM EST] Cert success.
---BEGIN CERTIFICAT--
+ --BEGIN CERTIFICAT--
sxlYqPvWreKgD5b8JyOQX0Yg2MLoRUoDyqVkd31PthIiwzdckoh5eD3JU7ysYBtN
cTFK4LGOfjqi8Ks87EVJdK9IaSAu7ZC6h5to0eqpJ5PLhaM3e6yJBbHmYA8w1Smp
wAb3tdoHZ9ttUIm9CrSzvDBt6BBT6GqYdDamMyCYBLooMyDEM4CUFsOzCRrEqqvC
@@ -175,7 +176,7 @@
NZFQWYJLNVf2M9CCJfbEImPYgvctrxl39H6KVYPCw1SAdaj9NneUqmREOQkKoEB0
x6PmNirbMscHhQPSC0JQaqUgaQFgba1ALmzRYAnYhNb0twkTxWbY7DBkAarxqMIp
yiLKcBFc5H7dgJCImo7us7aJeftC44uWkPM=
---END CERTIFICAT--
+ --END CERTIFICAT--
[Wed 30 Dec 2022 15:22:52 AM EST] Your cert is in /home/vpsadmin/.acme.sh/二级域名.你的域名.com_ecc/二级域名.你的域名.com.cer
[Wed 30 Dec 2022 15:22:52 AM EST] Your cert key is in /home/vpsadmin/.acme.sh/二级域名.你的域名.com_ecc/二级域名.你的域名.com.key
[Wed 30 Dec 2022 15:22:52 AM EST] The intermediate CA cert is in /home/vpsadmin/.acme.sh/二级域名.你的域名.com_ecc/ca.cer
@@ -191,4 +192,4 @@
至此,Xray所需要的两个基础设施终于全部就位!千呼万唤始出来的Xray马上就要揭开面纱,我们终于要进入最激动人心章节啦!
-> `⬛⬛⬛⬛⬛⬛⬜⬜ 75%` :::
+> ⬛⬛⬛⬛⬛⬛⬜⬜ 75%
diff --git a/docs/document/level-0/ch07-xray-server.md b/docs/document/level-0/ch07-xray-server.md
index 1fbc10b4..99f6a0ce 100644
--- a/docs/document/level-0/ch07-xray-server.md
+++ b/docs/document/level-0/ch07-xray-server.md
@@ -44,9 +44,9 @@
$ rm ~/install-release.sh
```
-::: warning
-**注意:** 使用 `rm` 命令删除文件的时候,默认其实就是删除现在所在的文件夹下的文件。但是,**我依然写了完整的路径**: `~/install-release.sh`,这是我使用 `rm` 时的一个安全习惯、也是我把安装分成几步之后想强调一下的内容。如果你听过一些“程序员从删库到跑路”之类的段子,大概就知道为什么了。
-:::
+ ::: warning 注意
+ 使用 `rm` 命令删除文件的时候,默认其实就是删除现在所在的文件夹下的文件。但是,**我依然写了完整的路径**: `~/install-release.sh`,这是我使用 `rm` 时的一个安全习惯、也是我把安装分成几步之后想强调一下的内容。如果你听过一些“程序员从删库到跑路”之类的段子,大概就知道为什么了。
+ :::
5. 完整流程演示如下:
@@ -102,11 +102,11 @@
echo "Xray Restarted"
```
-::: warning 注意
-经大家提醒,`acme.sh` 有一个 `reloadcmd` 命令,可以在证书更新时自动执行特定命令,那么就可以指定自动给 `Xray` 安装证书,但因为 `crontab` 是 Linux 系统中一个非常有用、非常常用的功能,所以本文保留 `crontab` 的方式来更新 `Xray` 证书。(对 `reloadcmd` 感兴趣的同学可以查看 `acme.sh` 的[官方文档](https://github.com/acmesh-official/acme.sh))
+ ::: warning 注意
+ 经大家提醒,`acme.sh` 有一个 `reloadcmd` 命令,可以在证书更新时自动执行特定命令,那么就可以指定自动给 `Xray` 安装证书,但因为 `crontab` 是 Linux 系统中一个非常有用、非常常用的功能,所以本文保留 `crontab` 的方式来更新 `Xray` 证书。(对 `reloadcmd` 感兴趣的同学可以查看 `acme.sh` 的[官方文档](https://github.com/acmesh-official/acme.sh))
-另外,录制动图时,脚本中没有加入重启 `Xray` 的命令,是因为 `Xray` 计划支持【证书热更新】功能,即 `Xray` 会自动识别证书更新并重载证书、无需手动重启。待功能加入后,我将适当修改 `config.json` 开启此设置,并删除脚本中的重启命令。
-:::
+ 另外,录制动图时,脚本中没有加入重启 `Xray` 的命令,是因为 `Xray` 计划支持【证书热更新】功能,即 `Xray` 会自动识别证书更新并重载证书、无需手动重启。待功能加入后,我将适当修改 `config.json` 开启此设置,并删除脚本中的重启命令。
+ :::
4. 给这个文件增加【可执行】权限
```
@@ -155,9 +155,9 @@
$ touch ~/xray_log/access.log && touch ~/xray_log/error.log
```
-::: warning 注意
-这个位置不是`Xray`标准的日志文件位置,放在这里是避免权限问题对新人的操作带来困扰。当你熟悉之后,建议回归默认位置: `/var/log/xray/access.log` 和 `/var/log/xray/error.log` 。
-:::
+ ::: warning 注意
+ 这个位置不是`Xray`标准的日志文件位置,放在这里是避免权限问题对新人的操作带来困扰。当你熟悉之后,建议回归默认位置: `/var/log/xray/access.log` 和 `/var/log/xray/error.log` 。
+ :::
3. 因为Xray默认是nobody用户使用,所以我们需要让其他用户也有“写”的权限(`*.log` 就是所有文件后缀是`log`的文件,此时`CLI`界面的效率优势就逐渐出现了)
```
@@ -362,9 +362,9 @@
内核的稳定是一台服务器稳定运行的基石。**【BBR测试版带来的细微性能差异绝对不值得更换不稳定的内核。】** 请选择你所在的Linux发行版所支持的最新内核,这样可以最大限度的保持服务器的长期稳定和兼容。
-::: warning 注意
-所谓魔改`bbr`的【领先】是有非常强的时效性的。比如很多 `bbrplus` 脚本,因为几年来都没有更新,到现在还会把你的内核换成 `4.19`,要知道现在稳定如 Debian 已经是 `5.9` 的时代了,那么这个脚本放在2018年1月也许领先了一点,到2018年10月4.19正发布时就已经失去了意义,放在现在甚至可以说是完完全全的【降级】和【劣化】
-:::
+ ::: warning 注意
+ 所谓魔改`bbr`的【领先】是有非常强的时效性的。比如很多 `bbrplus` 脚本,因为几年来都没有更新,到现在还会把你的内核换成 `4.19`,要知道现在稳定如 Debian 已经是 `5.9` 的时代了,那么这个脚本放在2018年1月也许领先了一点,到2018年10月4.19正发布时就已经失去了意义,放在现在甚至可以说是完完全全的【降级】和【劣化】
+ :::
4. `fq`, `fq_codel`, `fq_pie`, `cake`和其他算法哪个好?
@@ -377,11 +377,11 @@
它能解决的也只有丢包率的问题。不太准确的比喻,就是本来你用一辆车送你的货,有时候车半路就坏了(丢包),用了这些以后,你直接派出3份一样的货,让三辆车同时送,只要有一辆没坏就能送到。马路上都是你的车,自然就能把别人挤下去。但可想而知,你挤别人的时候,别人也会来挤你,而整个机房的出口道路一共就那么宽,最终势必就变成集体大堵车了。
-::: warning 说明
-它们的原理不是算法优化、不是提速、大多数是简单粗暴的**多倍发包**。对于【丢包率非常高】的差线路可能有一点作用,但【对丢包率低的好线路没有任何优化作用,反而会成倍的消耗你的流量】,进而造成服务器和你的邻居不必要的压力。
+ ::: warning 说明
+ 它们的原理不是算法优化、不是提速、大多数是简单粗暴的**多倍发包**。对于【丢包率非常高】的差线路可能有一点作用,但【对丢包率低的好线路没有任何优化作用,反而会成倍的消耗你的流量】,进而造成服务器和你的邻居不必要的压力。
-如果你的线路真的丢包率奇高,真正靠谱的解决方案是【换线路】。
-:::
+ 如果你的线路真的丢包率奇高,真正靠谱的解决方案是【换线路】。
+ :::
6. 啰嗦了这么多,就是因为围绕 `BBR` 忽悠小白的错误概念和坑人脚本实在是太多了。我希望你们现在对 `BBR` 有了相对清晰的理解。接下来,我们就动手安装最新的Debian内核并开启`BBR` 吧!(真的很简单)
1. 给 Debian 10 添加官方 `backports` 源,获取更新的软件库
@@ -389,9 +389,9 @@
$ sudo nano /etc/apt/sources.list
```
-::: warning 说明
-本文以 Debian 10 为例,所以使用 `/etc/apt/sources.list` 仍无问题,但如果你并不是根据本文从头开始,或者使用了其他Linux发行版,那么建议你建立 `/etc/apt/sources.list.d/` 文件夹,并在这个文件夹内建立自己的配置文件,形如 `/etc/apt/sources.list.d/vpsadmin.list`,以此保证兼容性,也可避免默认文件在不可预见的情况下被覆盖而导致配置丢失。
-:::
+ ::: warning 说明
+ 本文以 Debian 10 为例,所以使用 `/etc/apt/sources.list` 仍无问题,但如果你并不是根据本文从头开始,或者使用了其他Linux发行版,那么建议你建立 `/etc/apt/sources.list.d/` 文件夹,并在这个文件夹内建立自己的配置文件,形如 `/etc/apt/sources.list.d/vpsadmin.list`,以此保证兼容性,也可避免默认文件在不可预见的情况下被覆盖而导致配置丢失。
+ :::
2. 然后把下面这一条加在最后,并保存退出。
@@ -404,22 +404,22 @@
$ sudo apt update && sudo apt -t buster-backports install linux-image-amd64
```
-::: warning 注意
-如果你的VPS支持,可以尝试【云服务器专用内核】`linux-image-cloud-amd64`,优点就是精简、资源占用低,缺点嘛是有同学反馈不支持的系统强行安装会导致无法开机(Kernel无法识别)。
+ ::: warning 注意
+ 如果你的VPS支持,可以尝试【云服务器专用内核】`linux-image-cloud-amd64`,优点就是精简、资源占用低,缺点嘛是有同学反馈不支持的系统强行安装会导致无法开机(Kernel无法识别)。
-为了避免无法识别的悲剧,请确保:
-- 尝试前做一个系统快照,或者
-- 你有 `vnc` 可以救场(并且你知道怎么用)
-:::
+ 为了避免无法识别的悲剧,请确保:
+ - 尝试前做一个系统快照,或者
+ - 你有 `vnc` 可以救场(并且你知道怎么用)
+ :::
4. 修改 `kernel` 参数配置文件 `sysctl.conf` 并指定开启 `BBR`
```
$ sudo nano /etc/sysctl.conf
```
-::: warning 说明
-本文以 Debian 10 为例,所以使用 `/etc/sysctl.conf` 仍无问题,但如果你并不是跟着本文从头开始,或者使用了其他Linux发行版,那么建议你建立 `/etc/sysctl.d/` 文件夹,并在这个文件夹内建立自己的配置文件,形如 `/etc/sysctl.d/vpsadmin.conf`,以此保证兼容性,因为部分发行版在 `systemd` 207 版本之后便不再从 `/etc/sysctl.conf` 读取参数。使用自定义配置文件也可避免默认文件在不可预见的情况下被覆盖而导致配置丢失。
-:::
+ ::: warning 说明
+ 本文以 Debian 10 为例,所以使用 `/etc/sysctl.conf` 仍无问题,但如果你并不是跟着本文从头开始,或者使用了其他Linux发行版,那么建议你建立 `/etc/sysctl.d/` 文件夹,并在这个文件夹内建立自己的配置文件,形如 `/etc/sysctl.d/vpsadmin.conf`,以此保证兼容性,因为部分发行版在 `systemd` 207 版本之后便不再从 `/etc/sysctl.conf` 读取参数。使用自定义配置文件也可避免默认文件在不可预见的情况下被覆盖而导致配置丢失。
+ :::
5. 把下面的内容添加进去
@@ -435,9 +435,9 @@
7. 完整流程演示如下:
-::: warning
-**啰嗦君:** 因为我做展示的VPS支持云服务器专用内核,所以动图中我用了 `linux-image-cloud-amd64` 。如果你不确定你的VPS是否支持,那请务必按照第3步的命令,使用常规内核 `linux-image-amd64`。
-:::
+ ::: tip 啰嗦君
+ 因为我做展示的VPS支持云服务器专用内核,所以动图中我用了 `linux-image-cloud-amd64` 。如果你不确定你的VPS是否支持,那请务必按照第3步的命令,使用常规内核 `linux-image-amd64`。
+ :::
@@ -531,7 +531,7 @@
恭喜!!到这一步,你已经拥有了可以正常科学上网的服务器、同时也有了可以防止主动探测攻击的伪装网站。接下来,只要给你的客户端装上合适的软件,就可以享受顺畅的网络了!
-> `⬛⬛⬛⬛⬛⬛⬛⬜ 87.5%`
+> ⬛⬛⬛⬛⬛⬛⬛⬜ 87.5%
## 7.11 重要勘误
diff --git a/docs/document/level-0/ch08-xray-clients.md b/docs/document/level-0/ch08-xray-clients.md
index 6d0ba84e..1e9d5c8d 100644
--- a/docs/document/level-0/ch08-xray-clients.md
+++ b/docs/document/level-0/ch08-xray-clients.md
@@ -277,9 +277,9 @@
C:\Xray-windows-64\xray.exe -c C:\Xray-windows-64\config.json
```
-:::warning 说明
-这里的 `-c` 就是指定配置文件路径的参数,告诉 `xray` 去后面的位置找配置文件
-:::
+ :::tip 说明
+ 这里的 `-c` 就是指定配置文件路径的参数,告诉 `xray` 去后面的位置找配置文件
+ :::
2. 相似的,在Linux和macOS下,假设你的 `Xray` 程序位置是 `/usr/local/bin/xray`,配置文件位置是`/usr/local/etc/xray/config.json`,那么正确的启动命令就是
@@ -287,9 +287,9 @@
$ /usr/local/bin/xray -c /usr/local/etc/xray/config.json
```
-:::warning 说明
-每个系统都有系统路径变量,所以写 `Xray` 程序时不一定要写绝对路径。但是写了肯定没错,所以我就如此演示了。
-:::
+ :::tip 说明
+ 每个系统都有系统路径变量,所以写 `Xray` 程序时不一定要写绝对路径。但是写了肯定没错,所以我就如此演示了。
+ :::
@@ -310,7 +310,8 @@
我相信,你现在一定对`Linux`不再恐惧,对`Xray`不再陌生了吧!
-**至此,小小白白话文圆满结束!** `⬛⬛⬛⬛⬛⬛⬛⬛` **`100%`**
+**至此,小小白白话文圆满结束!**
+> ⬛⬛⬛⬛⬛⬛⬛⬛ 100%
@@ -329,8 +330,7 @@
-:::tip
-**不算后记的后记:**
+:::tip 不算后记的后记
希望我陪你走过的这一段小小的旅程,可以成为你网络生活中的一份小小助力。
diff --git a/docs/document/level-0/ch09-appendix.md b/docs/document/level-0/ch09-appendix.md
index 320997ff..ea74e22b 100644
--- a/docs/document/level-0/ch09-appendix.md
+++ b/docs/document/level-0/ch09-appendix.md
@@ -4,37 +4,37 @@
| 编号 | 命令名称 | 命令说明 | 出现篇章 |
|:--:|:--|:--|:--:|
-| `cmd-01` | `apt update` | 查询软件更新 | [《远程登录篇》](../ch03-ssh) |
-| `cmd-02` | `apt upgrade` | 执行软件更新 | [《远程登录篇》](../ch03-ssh) |
-| `cmd-03` | `nano` | 文本编辑器 | [《安全防护篇》](../ch04-security) |
-| `cmd-04` | `systemctl restart` | 重启某个服务 | [《安全防护篇》](../ch04-security) |
-| `cmd-05` | `adduser` | 给系统新增用户 | [《安全防护篇》](../ch04-security) |
-| `cmd-06` | `apt install` | 安装某个软件 | [《安全防护篇》](../ch04-security) |
-| `cmd-07` | `visudo` | 修改sudo权限设置专用编辑器 | [《安全防护篇》](../ch04-security) |
-| `cmd-08` | `sudo` | 用`root`权限运行某个命令 | [《安全防护篇》](../ch04-security) |
-| `cmd-09` | `chmod` | 修改目标文件/文件夹的权限 | [《安全防护篇》](../ch04-security) |
-| `cmd-10` | `mkdir` | 新建文件夹 | [《网站建设篇》](../ch05-webpage) |
-| `cmd-11` | `systemctl reload` | 重新加载某个服务 | [《网站建设篇》](../ch05-webpage) |
-| `cmd-12` | `wget` | 访问(或下载)某个网页文件 | [《证书管理篇》](../ch06-certificates) |
-| `cmd-13` | `acme.sh` | acme.sh证书管理相关的命令 | [《证书管理篇》](../ch06-certificates) |
-| `cmd-14` | `rm` | 删除命令 | [《Xray服务器篇》](../ch07-xray-server) |
-| `cmd-15` | `crontab -e` | 编辑当前用户的定时任务 | [《Xray服务器篇》](../ch07-xray-server) |
-| `cmd-16` | `touch` | 建立空白文件 | [《Xray服务器篇》](../ch07-xray-server) |
-| `cmd-17` | `systemctl` | `systemd`基本服务管理命令 | [《Xray服务器篇》](../ch07-xray-server) |
-| `cmd-18` | `reboot` | 重启Linux系统 | [《Xray服务器篇》](../ch07-xray-server) |
+| `cmd-01` | `apt update` | 查询软件更新 | [《远程登录篇》](./ch03-ssh.md) |
+| `cmd-02` | `apt upgrade` | 执行软件更新 | [《远程登录篇》](./ch03-ssh.md) |
+| `cmd-03` | `nano` | 文本编辑器 | [《安全防护篇》](./ch04-security.md) |
+| `cmd-04` | `systemctl restart` | 重启某个服务 | [《安全防护篇》](./ch04-security.md) |
+| `cmd-05` | `adduser` | 给系统新增用户 | [《安全防护篇》](./ch04-security.md) |
+| `cmd-06` | `apt install` | 安装某个软件 | [《安全防护篇》](./ch04-security.md) |
+| `cmd-07` | `visudo` | 修改sudo权限设置专用编辑器 | [《安全防护篇》](./ch04-security.md) |
+| `cmd-08` | `sudo` | 用`root`权限运行某个命令 | [《安全防护篇》](./ch04-security.md) |
+| `cmd-09` | `chmod` | 修改目标文件/文件夹的权限 | [《安全防护篇》](./ch04-security.md) |
+| `cmd-10` | `mkdir` | 新建文件夹 | [《网站建设篇》](./ch05-webpage.md) |
+| `cmd-11` | `systemctl reload` | 重新加载某个服务 | [《网站建设篇》](./ch05-webpage.md) |
+| `cmd-12` | `wget` | 访问(或下载)某个网页文件 | [《证书管理篇》](./ch06-certificates.md) |
+| `cmd-13` | `acme.sh` | acme.sh证书管理相关的命令 | [《证书管理篇》](./ch06-certificates.md) |
+| `cmd-14` | `rm` | 删除命令 | [《Xray服务器篇》](./ch07-xray-server.md) |
+| `cmd-15` | `crontab -e` | 编辑当前用户的定时任务 | [《Xray服务器篇》](./ch07-xray-server.md) |
+| `cmd-16` | `touch` | 建立空白文件 | [《Xray服务器篇》](./ch07-xray-server.md) |
+| `cmd-17` | `systemctl` | `systemd`基本服务管理命令 | [《Xray服务器篇》](./ch07-xray-server.md) |
+| `cmd-18` | `reboot` | 重启Linux系统 | [《Xray服务器篇》](./ch07-xray-server.md) |
## 2. 小小白白Linux重要配置文件索引
| 编号 | 配置文件位置 | 文件说明 | 出现篇章 |
|:--:|:--|:--|:--:|
-| `conf-01` | `/etc/ssh/sshd_config` | SSH远程登录程序设置 | [《远程登录篇》](../ch03-ssh) |
-| `conf-02` | `/etc/nginx/nginx.conf` | Nginx程序设置 | [《网站建设篇》](../ch05-webpage) |
-| `conf-03` | `/etc/apt/sources.list` | apt软件源列表 | [《Xray服务器篇》](../ch07-xray-server) |
-| `conf-04` | `/etc/apt/sources.list.d/vpsadmin.list` | 用户自定义软件源列表列表 | [《Xray服务器篇》](../ch07-xray-server) |
-| `conf-05` | `crontab -e` | 当前用户的定时任务 | [《Xray服务器篇》](../ch07-xray-server) |
-| `conf-06` | `/etc/sysctl.conf` | 手动设置kernel参数 | [《Xray服务器篇》](../ch07-xray-server) |
-| `conf-07` | `/etc/sysctl.d/vpsadmin.conf` | 用户自定义kernel参数配置文件 | [《Xray服务器篇》](../ch07-xray-server) |
+| `conf-01` | `/etc/ssh/sshd_config` | SSH远程登录程序设置 | [《远程登录篇》](./ch03-ssh.md) |
+| `conf-02` | `/etc/nginx/nginx.conf` | Nginx程序设置 | [《网站建设篇》](./ch05-webpage.md) |
+| `conf-03` | `/etc/apt/sources.list` | apt软件源列表 | [《Xray服务器篇》](./ch07-xray-server.md) |
+| `conf-04` | `/etc/apt/sources.list.d/vpsadmin.list` | 用户自定义软件源列表列表 | [《Xray服务器篇》](./ch07-xray-server.md) |
+| `conf-05` | `crontab -e` | 当前用户的定时任务 | [《Xray服务器篇》](./ch07-xray-server.md) |
+| `conf-06` | `/etc/sysctl.conf` | 手动设置kernel参数 | [《Xray服务器篇》](./ch07-xray-server.md) |
+| `conf-07` | `/etc/sysctl.d/vpsadmin.conf` | 用户自定义kernel参数配置文件 | [《Xray服务器篇》](./ch07-xray-server.md) |
@@ -43,8 +43,8 @@
| 编号 | 配置文件位置 | 文件说明 | 出现篇章 |
|:--:|:--|:--|:--:|
-| `xray-01` | `/usr/local/etc/xray/config.json` | Xray程序设置 | [《Xray服务器篇》](../ch07-xray-server) |
-| `xray-02` | `/home/vpsadmin/xray_cert/xray.cert` | TLS证书 | [《Xray服务器篇》](../ch07-xray-server) |
-| `xray-03` | `/home/vpsadmin/xray_cert/xray.key` | TLS私钥 | [《Xray服务器篇》](../ch07-xray-server) |
-| `xray-04` | `/home/vpsadmin/xray_log/access.log` | Xray访问日志 | [《Xray服务器篇》](../ch07-xray-server) |
-| `xray-05` | `/home/vpsadmin/xray_log/error.log` | Xray错误日志 | [《Xray服务器篇》](../ch07-xray-server) |
+| `xray-01` | `/usr/local/etc/xray/config.json` | Xray程序设置 | [《Xray服务器篇》](./ch07-xray-server.md) |
+| `xray-02` | `/home/vpsadmin/xray_cert/xray.cert` | TLS证书 | [《Xray服务器篇》](./ch07-xray-server.md) |
+| `xray-03` | `/home/vpsadmin/xray_cert/xray.key` | TLS私钥 | [《Xray服务器篇》](./ch07-xray-server.md) |
+| `xray-04` | `/home/vpsadmin/xray_log/access.log` | Xray访问日志 | [《Xray服务器篇》](./ch07-xray-server.md) |
+| `xray-05` | `/home/vpsadmin/xray_log/error.log` | Xray错误日志 | [《Xray服务器篇》](./ch07-xray-server.md) |
diff --git a/docs/document/level-1/README.md b/docs/document/level-1/README.md
new file mode 100644
index 00000000..acdcc092
--- /dev/null
+++ b/docs/document/level-1/README.md
@@ -0,0 +1,18 @@
+# 入门技巧
+
+**这个章节是入门级的Xray使用心得分享,主要分享一些Xray常用功能模块的原理说明。**
+
+[回落 (fallbacks) 功能简析](./fallbacks-lv1.md)
+
+
+[路由 (routing) 功能简析(上)](./routing-lv1-part1.md)
+
+
+[路由 (routing) 功能简析(下)](./routing-lv1-part2.md)
+
+
+[Xray的工作模式简析](./work.md)
+
+
+[通过 SNI 回落功能实现伪装与按域名分流](./fallbacks-with-sni.md)
+
diff --git a/docs/document/level-1/fallbacks-lv1.md b/docs/document/level-1/fallbacks-lv1.md
new file mode 100644
index 00000000..fc6e44aa
--- /dev/null
+++ b/docs/document/level-1/fallbacks-lv1.md
@@ -0,0 +1,401 @@
+# 回落 (fallbacks) 功能简析
+
+在使用Xray的过程中,你一定无数次的听说了【回落】这个功能。本文就稍微说明一下这个功能的逻辑以及使用方式。
+
+## 1. 回顾《小小白白话文》中的回落
+
+如果你用了《小小白白话文》中的[Xray配置](../level-0/ch07-xray-server#_7-4-配置xray),并完成了[HTTP自动跳转HTTPS优化](../level-0/ch07-xray-server#_7-8-服务器优化之二-开启http自动跳转https),那么你已经有了基于 `VLESS` 协议的简易回落:
+
+
+```
+"inbounds": [
+ {
+ "port": 443,
+ "protocol": "vless",
+ "settings": {
+ "clients": [
+ ...
+ ],
+ "decryption": "none",
+ "fallbacks": [
+ {
+ "dest": 8080 // 默认回落到防探测的代理
+ }
+ ]
+ },
+ "streamSettings": {
+ ...
+ }
+ }
+]
+```
+
+这一段配置用人话要怎么解释呢?
+
+1. **`Xray` 的入站端口 `[inbound port]` 是 `443`**
+
+ 即由 `Xray` 负责监听 `443` 端口的 `HTTPS` 流量
+
+2. **`Xray` 的入站协议 `[inbound protocol]` 是 `vless`**
+
+ 只有 `vless` 协议的流量才会流入 `Xray` 中做后续处理。
+
+ ::: warning
+ **注:** `VLESS` 这个轻量协议开发的初衷就是给 `xray` 及 `v2fly` 等核心引入回落功能、并同时减少冗余校验/加密。(当然,到目前为止,`xray` 中的 `trojan` 协议也已完整支持回落功能。)
+ :::
+
+3. **回落目标端口 `[fallback dest]` 是 `8080`**
+
+ `Xray` 接受 `443` 端口的访问流量后,属于 `vless` 协议的流量、由 `Xray` 进行内部处理并转发至出站模块。而其他非 `vless` 协议的流量,则转发至 `8080` 端口。
+
+ ::: warning
+ **问:到底是单数还是复数?**
+
+ 答:一定有聪明的同学发现,配置文件中,明明是复数 `inbounds`, `fallbacks`,为什么我解释的时候都是单数:`inbound`, `fallback` 呢?
+
+ 因为,配置文件中用复数,说明 `xray` 支持 N 个同等级的元素(即N个入站,M个回落等等),上面的示例解析中仅仅是其中一个,所以我用了单数。
+ :::
+
+4. **回落给 `8080` 端口的流量,由后续程序处理**
+
+ 小小白白话文中的示例,就是 `8080` 端口由 `Nginx` 处理,根据配置找到并展示小熊猫的网页。
+
+5. **总结,小小白白话文示例中的最简单回落,完整数据路线如下:**
+
+ ``` mermaid
+ graph LR;
+
+ W(外部 HTTP:80 请求) --> N80(HTTP:80)
+
+ subgraph Nginx 外部监听
+ N80 -.- N301(301转写) -.- N443(HTTPS:443)
+ end
+
+ N443 --> X(Xray 监听 443) .- X1{入站判断}
+ X1 --> |接收 VLESS 流量| X2(Xray内部规则)
+ X2 --> O(Xray Outbounds 出站)
+ X1 ==> |回落 非VLESS 流量| N8080(Nginx:8080)
+ N8080:::nginxclass ==> H(index.html)
+
+ H:::nginxclass
+ classDef nginxclass fill:#FFFFDE
+
+ ```
+
+
+## 2. 重新认识回落 (WHAT, HOW `v1`)
+
+基于上面的示例,你应该就可以明白什么是回落(What)和怎么回落(How)了,简单地说就是下面这几个要素:
+
+1. 回落的时间是流量进入 `Xray监听端口` 后
+2. 回落的依据是 `协议类型` 等流量特征
+3. 回落的目标是某个 `端口`
+4. 被回落的流量由监听 `回落端口` 的后续程序接手
+
+
+
+## 3. 为什么要回落 (WHY `v1`)
+最初,是为了防御 **【主动探测】** (Active Probing)
+
+**主动探测:** 简单粗暴的理解,就是指外部通过发送特定的网络请求,并解读服务器的回应内容,来推测服务器端是否运行了 `xray`, `v2fly`, `shadowsocks` 等代理工具。一旦可以准确认定,则服务器可能受到干扰或阻断。
+
+之所以可以根据服务器回应内容进行解读,就是因为一次完整的数据请求,其实有很多数据交换的步骤,每一个步骤,都会产生一些软件特征。用大白话说就是:
+
+- 正常的网站的回应,一定【会有】类似 `Nginx`, `Apache`, `MySQL` 的Web服务、数据库等工具的特征
+- 正常的网站的回应,一定【不会有】类似 `xray`, `v2fly`, `shadowsocks` 等代理工具的特征
+
+于是,当我们给 `Xray` 提供了【回落】功能后(如上例,回落给 `Nginx`),面对任何用来探测的请求,产生的结果是:
+
+- 探测流量无法掌握你的 `VLESS` 要素,故都会被回落至 `Nginx`
+- 探测流量全都回落进入 `Nginx` ,故VPS服务器的回应一定【会有】 `Nginx` 的特征
+- 因为 `Xray` 本身不对探测流量做任何回应 ,所以VPS的回应一定【不会有】 `Xray` 的特征
+
+至此,【回落】功能就从数据交互逻辑上解决了服务器被 **【主动探测】** 的安全隐患。
+
+
+
+## 4. 重新认识【回落の完全体】 (WHAT, WHY, HOW `v2`)
+
+为什么又要再次认识回落呢? 因为,上面仅仅说清楚了基于“协议”的、抵抗【主动探测】的初版回落。
+
+在 [rprx](https://github.com/rprx) 不断开发迭代 `VLESS` 协议及 `fallback` 功能的过程种,逐渐发现,回落完全可以更加灵活强大,只要在保证抵抗【主动探测】的前提下,充分利用数据首包中的信息,其实可以做到多元素、多层次的回落。(如 `path`, `alpn` 等)
+
+基于这个开发理念,【回落】功能才逐渐成长为现在的完全体,即完成了 `纯伪装 --> ws分流 --> 多协议多特征分流` 的进化。最终版甚至完全替代了以前要用Web服务器、其他工具才能完成的分流的功能。且由于上述的【回落/分流】处理都在首包判断阶段以毫秒级的速度完成、不涉及任何数据操作,所以几乎没有任何过程损耗。
+
+**因此,现在 `Xray` 中【完整体的回落功能】,同时具备下述属性:**
+
+- **安全:** 充分抵御主动探测攻击
+- **高效:** 几乎毫无性能损失
+- **灵活:** 数据灵活分流、常用端口复用(如443)
+
+::: tip 啰嗦君
+这样多轮介绍虽然略显繁琐,但只有这样层层深入展开,才能充分的说明【回落の完全体】独有的强大!
+:::
+
+
+## 5. 多层回落示例及解读
+
+理解了【回落の完全体】是什么,那就可以动手操作配置多层回落了。其实,项目已经提供了非常完整的示例,即官方模板中的 [VLESS-TCP-XTLS-WHATEVER](https://github.com/XTLS/Xray-examples/blob/main/VLESS-TCP-XTLS-WHATEVER/)。
+
+### 5.1 首先,我将服务器端配置的 443 监听段摘抄如下:
+
+```
+{
+ "port": 443,
+ "protocol": "vless",
+ "settings": {
+ "clients": [
+ {
+ "id": "", // 填写你的 UUID
+ "flow": "xtls-rprx-direct",
+ "level": 0,
+ "email": "love@example.com"
+ }
+ ],
+ "decryption": "none",
+ "fallbacks": [
+ {
+ "dest": 1310, // 默认回落到 Xray 的 Trojan 协议
+ "xver": 1
+ },
+ {
+ "path": "/websocket", // 必须换成自定义的 PATH
+ "dest": 1234,
+ "xver": 1
+ },
+ {
+ "path": "/vmesstcp", // 必须换成自定义的 PATH
+ "dest": 2345,
+ "xver": 1
+ },
+ {
+ "path": "/vmessws", // 必须换成自定义的 PATH
+ "dest": 3456,
+ "xver": 1
+ }
+ ]
+ },
+ "streamSettings": {
+ "network": "tcp",
+ "security": "xtls",
+ "xtlsSettings": {
+ "alpn": [
+ "http/1.1"
+ ],
+ "certificates": [
+ {
+ "certificateFile": "/path/to/fullchain.crt", // 换成你的证书,绝对路径
+ "keyFile": "/path/to/private.key" // 换成你的私钥,绝对路径
+ }
+ ]
+ }
+ }
+},
+```
+
+这一段配置用人话要怎么解释呢?
+
+1. **`Xray` 的入站端口 (`inbound port`) 是 `443`**
+
+ 即由 `Xray` 负责监听 `443` 端口的 `HTTPS` 流量,并使用 `certificates` 项下设定的 `TLS` 证书来进行验证
+
+2. **`Xray` 的入站协议 (`inbound protocol`) 是 `vless`**
+
+ `vless` 协议流量直接流入 `Xray` 中做后续处理
+
+3. **非 `VLESS` 协议流量有4个不同的回落目标:**
+
+ 1. `path` 为 `websocket` 的流量,回落给端口 `1234` 后续处理
+ 2. `path` 为 `vmesstcp` 的流量,回落给端口 `2345` 后续处理
+ 3. `path` 为 `vmessws` 的流量,回落给端口 `3456` 后续处理
+ 4. 其它所有流量,回落给端口 `1310` 后续处理
+
+4. **`xver` 为 `1` 表示开启 `proxy protocol` 功能,向后传递来源真实IP**
+
+5. **上述回落结构如下图所示:**
+
+ ``` mermaid
+ graph LR;
+
+ W443(外部 HTTP:443 请求) --> X443(Xray-inbound: 443) .- X1{入站判断}
+ X1 --> |协议 = VLESS 的流量| X2(Xray内部规则)
+ X2 --> O(Xray Outbounds 出站)
+
+ X1 --> |path = /websocket 的流量| X1234(Xray-inbound:1234)
+ X1 --> |path = /vmesstcp 的流量| X2345(Xray-inbound:2345)
+ X1 --> |path = /vmessws 的流量| X3456(Xray-inbound:3456)
+ X1 --> |其它所有流量| X1310(Xray-inbound:1310)
+
+ ```
+
+6. **网页回落不见了!**
+
+ 没错,聪明的同学应该发现了,防御【主动探测】的 `nginx回落` 不见了!!!这是为什么呢?会不会不安全?别急,我们继续分析:
+
+
+### 5.2 后续监听处理的配置段摘抄如下:
+
+1. 后续处理回落至 `1310` 端口的流量,按照下面的配置验证、处理:
+ ```
+ {
+ "port": 1310,
+ "listen": "127.0.0.1",
+ "protocol": "trojan",
+ "settings": {
+ "clients": [
+ {
+ "password": "", // 填写你的密码
+ "level": 0,
+ "email": "love@example.com"
+ }
+ ],
+ "fallbacks": [
+ {
+ "dest": 80 // 或者回落到其它也防探测的代理
+ }
+ ]
+ },
+ "streamSettings": {
+ "network": "tcp",
+ "security": "none",
+ "tcpSettings": {
+ "acceptProxyProtocol": true
+ }
+ }
+ },
+ ```
+
+ 看,神奇的事情发生了, `trojan` 协议这里又出现了一个新的 `fallbacks`。前面已经说过,`xray` 中的 `trojan` 协议也具有完整的回落能力,所以,此时 `trojan` 协议可以再次做判断和回落(这也就是传说中的套娃回落了):
+
+ - 所有 `trojan` 协议的流量,流入 `Xray` 中做后续处理
+ - 所有非 `trojan` 协议的流量,转发至 `80` 端口,【主动探测】的防御,完成!
+
+2. 后续处理回落至 `1234` 端口的流量,仔细看!它其实是 `vless+ws`:
+ ```
+ {
+ "port": 1234,
+ "listen": "127.0.0.1",
+ "protocol": "vless",
+ "settings": {
+ "clients": [
+ {
+ "id": "", // 填写你的 UUID
+ "level": 0,
+ "email": "love@example.com"
+ }
+ ],
+ "decryption": "none"
+ },
+ "streamSettings": {
+ "network": "ws",
+ "security": "none",
+ "wsSettings": {
+ "acceptProxyProtocol": true, // 提醒:若你用 Nginx/Caddy 等反代 WS,需要删掉这行
+ "path": "/websocket" // 必须换成自定义的 PATH,需要和分流的一致
+ }
+ }
+ },
+ ```
+
+3. 后续处理回落至 `2345` 端口的流量,仔细看!它其实是 `vmess直连`:
+ ```
+ {
+ "port": 2345,
+ "listen": "127.0.0.1",
+ "protocol": "vmess",
+ "settings": {
+ "clients": [
+ {
+ "id": "", // 填写你的 UUID
+ "level": 0,
+ "email": "love@example.com"
+ }
+ ]
+ },
+ "streamSettings": {
+ "network": "tcp",
+ "security": "none",
+ "tcpSettings": {
+ "acceptProxyProtocol": true,
+ "header": {
+ "type": "http",
+ "request": {
+ "path": [
+ "/vmesstcp" // 必须换成自定义的 PATH,需要和分流的一致
+ ]
+ }
+ }
+ }
+ }
+ },
+ ```
+
+4. 后续处理回落至 `3456` 端口的流量,再仔细看!它其实是是 `vmess+ws(+cdn)`。
+
+ ::: warning
+ **说明:** 你没看错,这就是 v2fly 曾经的推荐组合之一,并可完整支持 `CDN`。现已加入完美回落套餐哦!
+ :::
+
+ ```
+ {
+ "port": 3456,
+ "listen": "127.0.0.1",
+ "protocol": "vmess",
+ "settings": {
+ "clients": [
+ {
+ "id": "", // 填写你的 UUID
+ "level": 0,
+ "email": "love@example.com"
+ }
+ ]
+ },
+ "streamSettings": {
+ "network": "ws",
+ "security": "none",
+ "wsSettings": {
+ "acceptProxyProtocol": true, // 提醒:若你用 Nginx/Caddy 等反代 WS,需要删掉这行
+ "path": "/vmessws" // 必须换成自定义的 PATH,需要和分流的一致
+ }
+ }
+ }
+ ```
+
+5. 至此,我们就能够完整的画出模板的回落路线了:
+
+``` mermaid
+ graph LR;
+
+ W443(外部 HTTP:443 请求) --> X443(Xray-inbound: 443) .- X1{入站判断}
+ X1 --> |协议 = VLESS 的流量| X2(Xray内部规则)
+ X2 --> XO(Xray Outbounds 出站)
+
+ X1 --> |path = /websocket 的流量| X1234(Xray-inbound:1234)
+ X1 --> |path = /vmesstcp 的流量| X2345(Xray-inbound:2345)
+ X1 --> |path = /vmessws 的流量| X3456(Xray-inbound:3456)
+ X1 --> |其它所有流量| X1310(Xray-inbound:1310)
+
+ X1234 --> X2
+ X2345 --> X2
+ X3456 --> X2
+
+ X1310 --> |协议 = trojan 的流量| X2
+ X1310 --> |其他所有流量| N80(Nginx:80)
+
+ N80:::nginxclass --> H(index.html)
+
+ H:::nginxclass
+ classDef nginxclass fill:#FFFFDE
+```
+
+
+## 6. 结语
+
+至此,`Xray` 的【回落】功能就介绍完了。希望本文能够对你理解 `Xray` 的强大有所帮助。
+
+
+## 7. 附加题
+
+我再无耻的留一个附加题:本文详解的 [VLESS-TCP-XTLS-WHATEVER](https://github.com/XTLS/Xray-examples/blob/main/VLESS-TCP-XTLS-WHATEVER/) 模板?是否有可以优化的地方?
+
+提示:HTTP自动跳转HTTPS
diff --git a/docs/document/level-1/fallbacks-with-sni-resources/cf-api-token-permissions-for-acme.webp b/docs/document/level-1/fallbacks-with-sni-resources/cf-api-token-permissions-for-acme.webp
new file mode 100644
index 0000000000000000000000000000000000000000..4d0fe53ba914bc395a2a6c2eb9e6c405ff93368d
GIT binary patch
literal 7381
zcmch6cT|(xw(m#TB3N*P1(l*0B1J(&ib&ZMg#ZB*=_M#wkQy=c5G<&XCZQ`3VS|X2
z(0fyXYy^o?4AO!G2oM4iN+2QRC3?7uWM$xdpToEZxqC3+N zbG7l$*7j+6lK4YIE0U&vh@Wu3fkG6~1l_bB51My4S&kXlkP&IU27Y3Tl4)H|`TVXV z?7+@*9-3dBo@Cyy`&OwzML2VG%O}<2uq^n9pRT3GLh-~fTK881Ro5GZa}4Eb_M-6k zX`?I+ZHaV|nD>=H*4qvBcAn2=GhsaF)lXm1O!rFwvZ6e;UeA4KVrrajOLE~PEmYHo z{cS^C`d~3pVm%Pw29aL35px#aZfslG64yjo@>0r(3{hTokelL)i!XF&g2mltw4(%0 zFd+agBq69?pKmvM4_8PIIfn6RF|Xmd{=M?8r6@;v+c1_s|LRz%gR@(MV7Y@tGT~Bp zjz~|RT!0^5WBP4b*C5*DZJ_Lu*;>db@@ZIxF#eJO z{4Bu{N_qK(KUG*Q&V(o&YKeVaiAK26v||qJdm2kw73uKF(ZdlAeZYrEoPiE=u3IXG z{2ZM2e#%RS9O=!BJWO(@zkt|lV#*9|5+aVw1M=E-_?SA_YU%K^#7TnM9~#GRzl2MF zY0WYdFTZRQFZnFtMiz>{J8Vk<6mT#l@^23HmY>{Bgdg+>tWj&5z5gL|z -}C5-5xG6`kAvo^R{O>SAt?b-+?W!sAu&?#d~5Ma%K)=y}8js zaHGc6E`a1Pl(P8xx)U!9ToNr+jR6}15n1FeV2yjRL46LbRI%JH3C4eR_ocrXQMhb1 z5b_|LnjtLjG6Om}bA)J>cCe!>*M;VT?Fj{WPNrXHu~3z$XT{#`+6Il6#urDkXjfgc z=# 0<4kCxZB*Ii>)!hm z=Gwg7yoz6D!o;fWGc_^NFFhfPg7sXL5J*_wre4>|o?kVI9BJk;Nq}HTXSXZov7kqE zhVaJFS#)M(*LZC;u8Cz^* p!XAVdqjW?2h(@1mTDXhRw0VdkV z9($}&hmwpcbt|jDox+PiX?WFr+ =}?whiRwvDM~tR4xH(YR1cZy zkMyznfxtsu^`H2wR-jqcMThxW!buW*AdfbtAtCD 0#=fVz~emCx%%Psk+o zVsDPs>S-7+r{$R<6v&|-uVQV3dNdSnb?*9x9aPfJNsnMZ;H4gWo0y+|R(VSG)^G(1 zD!cEhWJ7D7sL<5jA(^13QkXy|hqc}-c?;Bv)8gmfbgq5+6j{S&6POlo*>AGi4>+T6 zDxBPeUV!?B65eWO%|BCG$i2jo^SIG7VwlpsvJxlU2Gx)#G|m5)(Evsjj9B=Ng2ou^ z>3!_ipCZh+*w_J%%YrSG--&k)lEto?eqVny*33d}eG9Dac3;{y?JO971gc5sF)Sqb zHW~WJqJAA~5WM#St(;gPz4UA~BvJ8>i_24zXaxPc@xx@J@LMWZY9E-%&NjDQKKf#F zt5e0TIhRvdwGQKiumi_aT8#2}%j>m5AKIrkdFfuDg~u*vvhAnMmHfcanB%RrP#yDg zx)Z^l9L*mkkw85}NrtK}kKV$+5XbMU*URVE(3OvHif5``&7^ce52-`G?OH9=J{9R( z`&*ljrPn<$6 oI1&Q(F=)Qyirav=$E;sRAC?0G!)2bc>v3t>)x;}=5^<; zl<~xb=V5OxS|2f3Q(+Z(LwATJZ77X6Xj`EL;H%kh|M)TFL`;NWCQIeW*nx-kxqV)C zMG$i%pCf@+FB DyviV6xrT1f1AkMFb z%UO&LZrg~xg=y$Gb6F4RsP~nk5cBcjbNptjqSY*Vt5j$2>({^;>YlQ$?qQ-=2Jch% z^963QsiM<#f+;mphO7T()UoK3*cIC1i*g}l;$Q&;*G~Mf#YSc8S{93;D+|3kXT0Mg z_Etk^MgHIBm#Ez~vW(mFJJ22_z8G|YX$8x0YsX!cdYzYND2R>94zaDBdwE7iRx&v7 zvduTmwwqeZl{sO4ujN$s`9qas?U(hD%7*Q#2U@-LnbElj<`Nd^FzxlK3sbj1KBwGE zq3pD++{2=@^9yb;SXoR?%LtR-109aX*sTo7k#op{h?j q z1G<@%Aa_v=+a$4oee&(!{60XiO+%-qcN)!|`>p@efVxKwWwD3}nu#$T#(yh3kQ=c& z#plQi 5^D|kjd#bzh<5Azk9p}oK1oEoy?@(- z>ngyNvk%}fau *8jPtqVw(va3>8H2% zbZQBH%6MW!j^87|Opa0QQvkQJBVRXz=d;p!-yw>^$Nv^1Rs?#{Ca-)RH&|lC9sEUP z1TnJLPRv|pd+`>I=@ig5l11cEFv03)9dLHHLiFO@ow9F^KM^ice{SD$Vc;PYFZLgB zd}{jMG*LDX5&lg}l5i?R-EO8A@7_rGc*S7Y-2fO%`?+KDJ`1z(kEPokelfD$)#=rK z?{W61^&OPJ)?nU1*NwcM5mwv!Fi&jqRn8R0q;bFh>gJqa^3p#GZL(zEn_OX }CYRUvXC~zgGa;25AfK%u4oAw0sKl6JRb_poD zZ*) -%zfg s~#lcBQF&G)-L9=4Kmj%iLaf! zUi+O*K?6Fnhtv?KJK@Ig4{f)Qp#?dK@Apu?E@%yN`gr%Y_NCv0mW@tT^U@XB?|GUg z=d?SLD~vk@I$W*NdczpJ9L74OU)l#z#?a<_1TYk9sfEb8sYS}=cixCQSXfH)2|F-B zP`{(nq%r}F@U7h8q|%_b{U5V9{o)nm%+^!2CnWk!ikes*4J!JV9X2NU6Ykk;BuA2q zz(7&mmCz&qHlN0 A zMp^mc1uO140;zvs)$z_UH8`R|%>Q~m?c&P1iyWitq^{Y5xUNDA_foNhnfEC2bwohG z9ee#%07qAty_;=gKR2+WblOZj8^iv nseeyV3*J=KUh#`^WWM zm!VJxSmB=95UJJA?D5ShB>|hqhDHu^cEousITfzfnR5$}^dU(AP5849j9IdL>xXj+ z1<(qC;cVlmIonW;g8tnEnh|QGrW{U+uRHv!_U&U26K!-I*!WR~Fbd@ ek-QDr;?1M6a$u?C$vmHwTX_=0L zCP>nb_jso ?i@;#h_U|1 zmOYK@Qp$d8ZucI)XQn %Dk*!)hy{nfwl%HabTCKm`PKHa0Nzr#PL-p!dtKf{RHZN??Jr r=aB!l&v|62SG0r+jOrGYErFRT33TNu-r zzq*v@95|D`1m2D^tihvsLxDYxo11-CD}c W4#u9d@i6=etWUuWXH!ikewI?D_180j4qRwqNfa|47sH~3y1tH{;8Dcy-r&(Bk1 zE-nd@yPp$^#fs-s2M~!8=63fv_81_($bWP<87A!;8QY0R5uebf@MAN;MssZ);vB%V zils^a(9CuxJmUb;m>FE i0NI;#h=EFM=vReT@V`J)KcgI6n6zWsik&E{D4uF3 zzFRW^5!{Kl$o?w#+T!-{i?tcCi{;JIkrwaOyh>!63ls6G?}cBoH@|(h1V6l>c>wCE zTMs*Wd?r*04g6*jtyFu^1ARiyR@=8mPJU-(-Xff=DhW>*?97Vd2gM+gv`;jx=ikJ6 zCv;p(u2k$g3Clm ?CFcmPFFOH6QuxGwCgsukzP zCocn*7n5hZxHkuO_6dmXFTTxpjSF?2v3WLKYXF;h-W1yeb( F0L9$5zKlD+S$Iusnj5&?+i~oRuN`d3T_x!(7P5LRzFBZ$p zaT2i5-#;|?7?+N5G2~Mx <#xe`)rw&|GUCaQ)_a98 zSJk)&7_!8r?q|;gA8QP=dQgc@-jP*nxyW!|s(BrXaH7FG#l&Y@*yC9Cbg+}qPN+i= zyn(@DL@i6Hs}AL8Mlo9@L}O#mzISPJ)iY&Xa5vrVSNHkt1(fl&B0VLw9m|nmlsw~# zG!d^iKWbpWpOZTLD6PuXR(tk&yxJR*o!ZAY_e>0$QewsbV_|gDGkp^HA2Q2RSxzvY zzVvHlcV7QBvT*eCaS}h>SO?{+*1h=qOamqvH{n~A9^VN#Qq~mxB0u;ww5B*8SYx!$ z%<;+?PZ>4|EDL0}oX6iPgmdyjzKflgg2dmPmO~ulr{tmx``a11qhDZJ*`+1yx0mN- z?iE!R`l3*;8GPa_ICqL)t77rZROpWocZ?wrehXll+TB^}VaH9{+0EB$({>QbErN=r zU!K^=Ck-m*&&{kvxM@o-$Q|%;*Dd_kOwp2^epS8BrxS$A*ttBJPA ujbNWZI@{a{i&6T_9fAPj*P#T^LM5w-wY$B=%*)p{9?D}K}rt7(=3 ?*FLguzq%SQRBa5P;gVu5sX4VTW<{sAJ( Wfc};IQ8PYX&yfDWGUkTI{FSX0DOBI24f;BpsN(+J(lqAtvUafJIbS#Kl73;mQ z*g4|(Vy-RIUp>pyT`*)z)OUwo5XL8O`=!sPf<}?VqX+Q>h8f0t&AQ7Q$CFXjzdV!l z`EaR?3NN1nkEcuTl%I4O^lrLm1{3C5*IE1~k}9y4e;=pDjyG2LI9X=bfhR()03wWr zd+uqk2aUq+)2WdGwblfOgLu4crP!HcWYP`);AHT6!fe!CH{3b1RqZ?+rNHTqzV##( z`)lP=ihNE0-=r IwRSD^Guy&$-9R7qyCQO<-)IyP*A z(Cw$~KF|aR5lx(TA8FV;)jFri!`fAWCR^E(G7xxC{&^WCdNdw+%QK+x7v`Oncq)sX zn#dczfvu$N Ip>MzZjovB-!Zk5ic9NUl#OE~^&We+@gcv0&%$=+ zFbR!>xF2AYS=Et1w4~CGPw2SBsbH_+M*VkeO%in*`%`T7UsCbyt2z34F^e~4Xg1;`6>0J(z5eL| zIb2+|jG _62Vk*`ZxKBY-Qng$^4VUyzB%G7Tbr2#R$>Q(WxxwySE zlA3O4Dj7O+a~UB)_bZzJ6DLD`{zFcVY6(vzc5a9=uT=nR3~e(|*HbN4avKgCIOjPx zTr%aGV-@GtbvDX7v4J*cN(@+5i#j`awrcxG@AHMT@7vy9qsY8WwTSBdnSHZ$Yf5+7 zbzlYZta!2nod>1GU{i#MII^OFccfkK=@Yg5$!Ru|cfc&_&P@3v=ev2x0$&X}>P?@G z>Mkz5A8HqyeGIzz!Bflc0vW-@*4)l9AL^?_*_$eccMgSTz v%=_0uSIdhS}Veit+4hr(>8zvg^FE}5%o3r&@&}%d5&V}f^EsF_0y34imy_jE~ zo!FK|zxql@HJI>p_0e5t&HyyMAvGaVX1X4irOQXb=e(mDZ`+XFH+!_k3YlE0*dbJ& zh(| q;>?$y;_52|r6oY%2mx~yM+ee>5kd2=5ocZ%5N7UP_$ zOU=ufcXIxz!~gQ}iJv83=B35sKtNep+w(|~)*A2%?)~2b-t>P1Z?yXRkAC|*@qZV} zws;LvqgdesPGq(^duT!VD(4NFPnk*rO}Hbh_JUSJ$Qa_SqIrl18RE3Q@tzB~$?3@v zzw5sCvNz0)E_UKg50y&SSy&&!fS<2_)V>qS+*2Knv rGFK3PnIwD>v~$(NGj9W x~wQ_h5m1i>y;e 7lL?5VPCPKWW!;Q|s-ui&7jn*jK1G)Knb8J}8aIBfD?9r|@#Od9S65?t9i5Gd zW`gW|-2vVNP8s(&l_ENBh+o)yl<2~__q%y!exxE(=k{qLyl6d`^dFL`0bvX<(d%$s zqmQEjG^|nfddsE^; m8m}`$O0`H;2=W#_P99C|+>{M?dE?z+r z=uT@Q90P;&IdfmePLi*7NRi}ZnKypwju_-?HcJ;hFVK|Qn5n(1+rNm|nb5SzJoDl5 z5I==-4NRbx%V`NDT9%oeusq@T09sX?nfJAxjk;zPdgDTHAwwgSAgRz!i1CGbBJt1*K>+3as_>cGmHZq7WPaZ4 za(MaQ1$ZZpJV}Yr%DPp{pa_`1S=eA=?OTSd?8n^_9c!ycC)|EMNW`D`BtyT0>6e-9 z`?>k#A*Ark^a`VO94}{!XPE6MEUaYB(MCx>LnJA!FH5--?Ha60_a|ayz(AA7{aNP= zg-`KrKbWlF6ek`6TXD_DGHNuQS%N45P9YK1Xv1DYw&)U}V>wfJ2VcyTZZ!A*V)@Am zl391^;;#dZu*sf~1wWUpq?E*1TxIWu$dC6VHR{n2B_u3LYFEEWShHY#i{;M3<~R4y zw{f>mb|GaXK=|V!m;k8Fu;Hzzf71$bgD6L}i37BG5{+I>SlF*~Hs>#;T`G1eJHjU( z?&{h1?YyWz))W*!Nu2&2NFeVP8lFXQ6or>*Yc*rHxyH}B@Z(!X0`JF+eTnh?KagS$ zA?5!X6a~T0H;*p(?^9n1mkx+ #1S3OM_K@@wpN-Bab+3?fJ#YD-swt zw`iUrw0VlJ`B}+Q*c~TTl1{+WjiSc4AVWVbqmxwIGw$^kOg>1*YJABgR#P5v cv13rEvc~<_Iy``E`E+^yKzU) zj0hf;`q8SIGLe%rsmnjT=#-j&gs?h)8pC-teu{AeYFYfhqdS4i8r@BHzaOa^Z*#jE zO4f5HEu0&?u$(2FGh`9Lx!Y+VP9CK^C*7U8K^f0*y1G=>k_7`wt(U#nu94rd?rF we`XJ^^6o(?gJqhq_8pANhVq_msYg(4M%T zx0lDi+$t>rw>OkCl5M H?YdWu878W}3k6eq@&NXoi5@N>e|mAyW;$l5p HrALq*l%yu9e`+?q2vo-NVbXEH?@J zy$q1Yy8S5bz9l*#p8NXv@{rsi{?OkIg!60v>-Rg54#^Abt-mPlkFRPcLtvEn`9|4L u=APGl{&j(s@-4)lRP}$7vJSTj5cxm#n_fl#SXv8b+MIPfQ+~?#{(l38tgi$B literal 0 HcmV?d00001 diff --git a/docs/document/level-1/fallbacks-with-sni-resources/xray-fallbacks.svg b/docs/document/level-1/fallbacks-with-sni-resources/xray-fallbacks.svg new file mode 100644 index 00000000..df126025 --- /dev/null +++ b/docs/document/level-1/fallbacks-with-sni-resources/xray-fallbacks.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/docs/document/level-1/fallbacks-with-sni.md b/docs/document/level-1/fallbacks-with-sni.md new file mode 100644 index 00000000..1d410702 --- /dev/null +++ b/docs/document/level-1/fallbacks-with-sni.md @@ -0,0 +1,330 @@ +# 通过 SNI 回落功能实现伪装与按域名分流 + +VLESS 是一种很轻的协议,和 Trojan 一样,不对流量进行复杂的加密和混淆,而是大隐隐于市,通过 TLS 协议加密,混杂在其他 HTTPS 流量中,在墙内外穿进穿出。为了更好的伪装以应对主动探测,Fallbacks 回落功能随 VLESS 同时出现。这篇教程将演示如何使用 Xray 中 VLESS 入站协议的回落功能配合 Nginx 或 Caddy 在保证伪装完全的前提下实现按域名分流。 + +## 应用情景 + +由于 XTLS,Xray 需要监听 443 端口,这导致如果之前有网站运行在服务器上,那么此时网站无法运行或需要运行在其他端口上,这显然是不合理的。有以下三种方案可以解决这个问题: + +- Xray 监听其他常用端口(如 22、3389、8443) + + 这个方案是最简单的,但不够完美。 + +- Nginx 或 HAProxy 监听 443 端口,通过 SNI 分流做 L4 反向代理,实现端口复用 + + 这个方案比较复杂,需要对 Nginx 或 HAProxy 的使用有一定了解,此处不作过多解释。 + +- Xray 监听 443 端口,通过 Fallbacks 功能 SNI 分流将网站流量回落到 Nginx 或 Caddy + + 这个方案难度适中,也是此教程接下来想要演示的方案。 + +## SNI 简介 + +服务器名称指示(英语:**S**erver **N**ame **I**ndication,缩写:**SNI**)是 TLS 的一个扩展协议。熟悉反向代理的朋友都知道,如果想要通过域名将流量代理到正确的内容上,需要以下配置: + +```nginx +proxy_set_header Host 主机名; +``` + +这句的作用是将名为 “Host” 的 HTTP Header 设定为某个主机名。为什么要这样做?一般而言,一台服务器对应一个 IP,但却运行多个网站,访问者通过域名查询到 IP 以访问服务器,那么问题来了,如何确定访问者想要访问的是哪一个网站?这需要“基于名称的虚拟主机”。 + +当 Web 服务器收到访问请求后,它会查看请求的主机头,使访问者访问正确的网站。然而当 HTTP 协议被 TLS 协议加密后,这种简单的方法就无法实现了。因为 TLS 握手发生在服务器看到任何 HTTP 头之前,因此,服务器不可能使用 HTTP 主机头中的信息来决定呈现哪个证书,更无法决定访问者的访问目标。 + +SNI 的原理也很简单,它通过让客户端发送主机名作为 TLS 协商的一部分来解决此问题。所以在使用 Nginx 对 HTTPS 协议进行反向代理时,需要在配置中加入 `proxy_ssl_server_name on;`,此时 Nginx 会向被代理的服务器发送 SNI 信息,解决了 HTTPS 协议下虚拟主机失效的问题。另外,使用 SNI 时,即使不指定主机头,也可以正确访问网站。 + +## 思路 + + + +从 443 端口接收到流量后,Xray 会把 TLS 解密后首包长度 < 18、协议版本无效或身份认证失败的流量通过对 name、path、alpn 的匹配转发到 dest 指定的地址。 + +## 添加 DNS 记录 + + + +请按实际情况修改域名和 IP。 + +## 申请 TLS 证书 + +由于要对不同前缀的域名进行分流,但一个通配符证书的作用域仅限于两“.”之间(例如:申请 `*.example.com`,`example.com` 和 `*.*.example.com` 并不能使用该证书),故需申请 [SAN](https://zh.wikipedia.org/wiki/%E4%B8%BB%E9%A2%98%E5%A4%87%E7%94%A8%E5%90%8D%E7%A7%B0) 通配符证书。根据 Let's Encrypt 官网信息[^1],申请通配符证书要求 DNS-01 验证方式,此处演示 NS 记录为 Cloudflare 的域名通过 [acme.sh](https://acme.sh) 申请 Let's Encrypt 的免费 TLS 证书。使用其他域名托管商的申请方法请阅读 [dnsapi · acmesh-official/acme.sh Wiki](https://github.com/acmesh-official/acme.sh/wiki/dnsapi)。 + +首先需要到 [Cloudflare 面板](https://dash.cloudflare.com/profile/api-tokens)创建 API Token。参数如下: + + + +权限部分至关重要,其他部分任意。 + +创建完毕后,你会得到一串神秘字符,请将其妥善保管到安全且不会丢失的地方,因为它不再会显示。这串字符就是即将用到的 `CF_Token`。 + +::: tip 注意 +以下操作需要在 root 用户下进行,使用 sudo 会出现错误。 +::: + +```bash +curl https://get.acme.sh | sh # 安装 acme.sh +export CF_Token="sdfsdfsdfljlbjkljlkjsdfoiwje" # 设定 API Token 变量 +acme.sh --issue -d example.com -d *.example.com --dns dns_cf # 使用 DNS-01 验证方式申请证书 +mkdir /etc/ssl/xray # 新建证书存放目录 +acme.sh --install-cert -d example.com --fullchain-file /etc/ssl/xray/cert.pem --key-file /etc/ssl/xray/privkey.key --reloadcmd "chown nobody:nogroup -R /etc/ssl/xray && systemctl restart xray" # 安装证书到指定目录并设定自动续签生效指令 +``` + +## Xray 配置 + +```json +{ + "log": { + "loglevel": "warning" + }, + "inbounds": [ + { + "port": 443, + "protocol": "vless", + "settings": { + "clients": [ + { + "id": "UUID", + "flow": "xtls-rprx-direct" + } + ], + "decryption": "none", + "fallbacks": [ + { + "name": "example.com", + "path": "/vmessws", + "dest": 5000, + "xver": 1 + }, + { + "dest": 5001, + "xver": 1 + }, + { + "alpn": "h2", + "dest": 5002, + "xver": 1 + }, + { + "name": "blog.example.com", + "dest": 5003, + "xver": 1 + }, + { + "name": "blog.example.com", + "alpn": "h2", + "dest": 5004, + "xver": 1 + } + ] + }, + "streamSettings": { + "network": "tcp", + "security": "xtls", + "xtlsSettings": { + "alpn": [ + "h2", + "http/1.1" + ], + "certificates": [ + { + "certificateFile": "/etc/ssl/xray/cert.pem", + "keyFile": "/etc/ssl/xray/privkey.key" + } + ] + } + } + }, + { + "listen": "127.0.0.1", + "port": 5000, + "protocol": "vmess", + "settings": { + "clients": [ + { + "id": "UUID" + } + ] + }, + "streamSettings": { + "network": "ws", + "wsSettings": { + "acceptProxyProtocol": true, + "path": "/vmessws" + } + } + } + ], + "outbounds": [ + { + "protocol": "freedom" + } + ] +} +``` + +以上配置针对于 Nginx,以下是需要注意的一些细节。 + +- 有关 Proxy Protocol + + Proxy Protocol 是 HaProxy 开发的一种旨在解决代理时容易丢失客户端信息问题的协议,常用于链式代理和反向代理。传统的处理方法往往较为复杂且有诸多限制,而 Proxy Protocol 非常简单地在传输数据时附带上原始连接四元组信息的数据包,解决了这个问题。 + + 凡事皆有利弊,Proxy Protocol 也是如此。 + + - 有发送必须有接收,反之亦然 + - 同一端口不能既兼容带 Proxy Protocol 数据的连接又兼容不带数据的连接(如:Nginx 同端口的不同虚拟主机(server),本质是上一条)[^2][^3] + + 在遇到异常时,请考虑配置是否符合上述条件。 + + 此处,我们使用 Proxy Protocol 让被回落到的目标获取到客户端的真实 IP。 + + 另外,当 Xray 的某个入站配置存在 `"acceptProxyProtocol": true` 时,ReadV 将失效。 + +- 有关 HTTP/2 + + 首先,`inbounds.streamSettings.xtlsSettings.alpn` 有顺序,应将 `h2` 放前,`http/1.1` 放后,在优先使用 HTTP/2 的同时保证兼容性;反过来会导致 HTTP/2 在协商时变为 HTTP/1.1,成为无效配置。 + + 在上述配置中,每条回落到 Nginx 的配置都要分成两个。这是因为 h2 是强制 TLS 加密的 HTTP/2 连接,这有益于数据在互联网中传输的安全,但在服务器内部没有必要;而 h2c 是非加密的 HTTP/2 连接,适合该环境。然而,Nginx 不能在同一端口上同时监听 HTTP/1.1 和 h2c,为了解决这个问题,需要在回落中指定 `alpn` 项(是 `fallbacks` 而不是 `xtlsSettings` 里面的),以尝试匹配 TLS ALPN 协商结果。 + + 建议 `alpn` 项只按需用两种填法:[^4] + + - 省略 + - `"h2"` + + 如果使用 Caddy 就大可不必如此繁杂了,因为它**可以**在同一端口上同时监听 HTTP/1.1 和 h2c,配置改动如下: + + ```json + "fallbacks": [ + { + "name": "example.com", + "path": "/vmessws", + "dest": 5000, + "xver": 1 + }, + { + "dest": 5001, + "xver": 1 + }, + { + "name": "blog.example.com", + "dest": 5002, + "xver": 1 + } + ] + ``` + +## Nginx 配置 + +Nginx 将通过官方源进行安装。 + +```bash +sudo apt install curl gnupg2 ca-certificates lsb-release +echo "deb [arch=amd64] http://nginx.org/packages/ubuntu `lsb_release -cs` nginx" \ + | sudo tee /etc/apt/sources.list.d/nginx.list +curl -fsSL https://nginx.org/keys/nginx_signing.key | sudo apt-key add - +sudo apt update +sudo apt install nginx +``` +删除 `/etc/nginx/conf.d/default.conf` 并创建 `/etc/nginx/conf.d/fallbacks.conf`,内容如下: + +```nginx +set_real_ip_from 127.0.0.1; +real_ip_header proxy_protocol; + +server { + listen 127.0.0.1:5001 proxy_protocol default_server; + listen 127.0.0.1:5002 proxy_protocol default_server http2; + + location / { + root /srv/http/default; + } +} + +server { + listen 127.0.0.1:5003 proxy_protocol; + listen 127.0.0.1:5004 proxy_protocol http2; + + server_name blog.example.com; + + location / { + root /srv/http/blog.example.com; + } +} + +server { + listen 80; + return 301 https://$host$request_uri; +} +``` + +## Caddy 配置 + +安装 Caddy 请参阅 [Install — Caddy Documentation](https://caddyserver.com/docs/install)。 + +为了使 Caddy 能获取到访问者的真实 IP,需要编译带有 Proxy Protocol 模块的 Caddy。建议直接在 Caddy 官网上在线编译。 + +```bash +sudo curl -o /usr/bin/caddy "https://caddyserver.com/api/download?os=linux&arch=amd64&p=github.com%2Fmastercactapus%2Fcaddy2-proxyprotocol&idempotency=79074247675458" +sudo chmod +x /usr/bin/caddy +``` + +直接替换即可。 + +::: tip +建议先通过官网文档安装 Caddy,再替换二进制文件。这样做无需手动设定进程守护。 +::: + +编辑 `/etc/caddy/Caddyfile`: + +```Caddyfile +{ + servers 127.0.0.1:5001 { + listener_wrappers { + proxy_protocol + } + protocol { + allow_h2c + } + } + servers 127.0.0.1:5002 { + listener_wrappers { + proxy_protocol + } + protocol { + allow_h2c + } + } +} + +:5001 { + root * /srv/http/default + file_server + log + bind 127.0.0.1 +} + +http://blog.example.com:5002 { + root * /srv/http/blog.example.com + file_server + log + bind 127.0.0.1 +} + +:80 { + redir https://{host}{uri} permanent +} +``` + +## 参考 + +1. [服务器名称指示 - 维基百科,自由的百科全书](https://zh.wikipedia.org/wiki/%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%90%8D%E7%A7%B0%E6%8C%87%E7%A4%BA) +2. [Home · acmesh-official/acme.sh Wiki](https://github.com/acmesh-official/acme.sh/wiki) +3. [HTTP/2 - 维基百科,自由的百科全书](https://zh.wikipedia.org/wiki/HTTP/2) + +## 引用 + +[^1]: [常见问题 - Let's Encrypt - 免费的SSL/TLS证书](https://letsencrypt.org/zh-cn/docs/faq/) + +[^2]: [Proxy Protocol - HAProxy Technologies](https://www.haproxy.com/blog/haproxy/proxy-protocol/) + +[^3]: [proxy protocol介绍及nginx配置 - 简书](https://www.jianshu.com/p/cc8d592582c9) + +[^4]: [v2fly-github-io/vless.md at master · rprx/v2fly-github-io](https://github.com/rprx/v2fly-github-io/blob/master/docs/config/protocols/vless.md) diff --git a/docs/document/level-1/routing-lv1-img01-trio.png b/docs/document/level-1/routing-lv1-img01-trio.png new file mode 100644 index 0000000000000000000000000000000000000000..3f3e27ae8f3b19d5b78adf3143e06191bbb36fe9 GIT binary patch literal 1326500 zcmV(#K;*xPP) Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D|D{PpK~#8N%>CK2 zWy`jv2d#)15&I-BCnb_lk(`uLsS2KoJ8m${xZ)OWWQJje!PB6#R}_5T|2OyUeT*?< z#oA{dBmd~rd-GO%*^4pej1T|M|KtDtx8HvI5S+xvj~`pzOaNW{`0-;C#fR^5AijV9 zUe1 Fva&eK-fzf3Pv9uiqhlECHI|54z>Y#4J;j02)n+&_6z={E(o_1FpaR z_Tl?)KR5vTY1@Zyr1{|k)Hj<8e(UL*!tZqp)RmDFN< N`G`(ya1*{EjV37=6}tz1{ad&!7zhYt^NL?BY2@or}A!;$V}c?4Id!C%1k6E z%I`nEhS_ XFH>W82fHZ}*XcL$(=(DZ8P$Uv=iBA3A5wX;|gr zV>D4~sx3j=djh>5zd311gc8k pRjHt`L& mHLG+Ozf%(ujWux#dQ#HE8? z^5GE1?pwDa5#I1T-@2~XUV07L&42o>=(tphH;H5Zu$M}t=jaCaeHKhaXVad6wAYkg zO^T64$|y*1Cqmp~&i|I{!c+#1*q0BVhob!6JO!6BN}}jD+hV&5K);c7P>xo|H3fc? zEU}ph!Xj2&7fsID`i(VTE(_i6Asa}HkV(x z@TX02G?nC^3%8@1aZy$_cYpy*fKGvEIhmHS1ygK3%~YRje1-rfw{+aieWQ=K`S}9< z_T%lNH+X;f^5q}?^7i>Nw|pPoxOMV=&s0J3S2K{Y`h@hjAKTl-5R4$ n7v1h%MNQL(_?_iM3n~uN``x*6AA^V^oQ?Xv-Fs{9ivKdP5F^FC2qYzbQO@s zM;-y*zA%5JoF#M~z1M}I{KH4@vG gyA38Zxbs!!&63IFSNhpPJZ-gb4iv|XHb**-)KviXxS zW$#!%(#Ve=Kfl?x(CTmt?n3(qN@%9yU;gqJq V8E3gJ THEy@w}x)na`-GIwv};EJBuI>FSsHfGyp4*~7RU>Q%&I#Qy={*C)w;P?&yv)sw%{ zq71bdF9)iyi4!lGCmt03Q2##!{K*OMxCG7~`$bg$89x#I2aA_EKQL|czW~PjuVL#y z7`Cdrcdn1cGv`lX``p9>o+shv{Bt&_UySt 3tJ5KLG4&W0eQ`6lai89N{{QlsCxJX) zyutCopmY?XH}~yvFb#YlE+p=jmIpRxqn;lCAGP=}`D$)d)GOmgl>yRyBXsgXZ8vrm z(Iz$xCYvCU2Z*Y ekeUoZMrqS&jfI>q@$^#RqaNl|{4w^a#n(x8ofW j0g;`Px8p2IClx z6Ta NR%g63?hw(Q3 KKZc&-V$zi1d z#<(xlN*Bxns#~*GVEcTCTbRuge|y-(-vx~Y=+Yj{qQBwL7AH8uCq2Gs%PQ<@6g-yU zE`Q}XlWde83@V4;&G`21_itanGQte+;dTdNZ9zPsy$YsY_$`CS=fDGP#~-5!oY*t} zC6+W(H+U}+-I*S};YCCKJeu>b9r-%OFW|I#g=z0|i++OkzytQWt`0cq6VLo`%%r0C z3} 6sjdPe0$@w43)$(+|TC9h?~{nKv*Tu8RYmfwcW4 z9(1f6ZmF9}q$;e>Sc*!)IYl@9Ja6BhEf< `^|Me~6CAubB8TqR)3c!<2CwRxhNPelPcmHCG>T%RiXP>b)HT zAZrx?N$eR|{E0Td!Yz~c=j0h>n{bcdZNe+0XY@tFKK$i-tKr>H eWmW-ngTN5CZq(~3rSoLyh3H <%@S%GHg=fiJ)H%FV!x;H~q zTK#f5MoH%pm~Nu@3B9T>_Me}iI&&pm2y=FrmvHjjALvH#$|{+CJN>UzhiEyDewuTo zRRa&qR>4Vwhj1IMl2$+TFB7D;_K?H28%wLiC}kc&YPV!I^MtC0axpY>CvOtF#F!*4 zJ6iyg=K*i)nX4FX=2**ZRfWdgI60+vd%?3lQoRIJAIgF)U`K@C6~_YH<%u1xwwtE3 z^VhXt@@GM Tur=-kHW$ZhvS`($_N)+te)!KXK0TVzl^eew0~=f8X@(M=D2 z%ZD+-k3M^Yx*+Gw=YRN5|J|+>n|{zPF`ka;xC!Z=j=_7tcK9BUotj1I$e)leH4xA8 zvbYi}koJpwnnaV5YL(dj#x|YCS)H8RlNjvk#4XPd4ET)t5hx-n4EzadNO1w((rUu! zp4qj7_6r&*iVh^(HUFSLF>UgNPnofn?!2te1rrLO8xfRvC=10VVD6l@htt&q45PRT zda!1>38>>MLhWL0M9G6Ot4p0FDjw*rys6*Nw5PqhQO&Km8(um85v~p?(q};8z6DI^ z&}``qeI)>&m?6huI7K)N!6Pp76Dy-f=}L5+PwI|yy}YmWh<3&95Qt4bVofAU7EM@Y zTlHo0j_n`ux98S(HMI@GF`wz=sUH}-lqYT+{oj4Ix|uA$A@2MJd|-y{b>T9X*wP36 z&g2)V{|xs*#lsQ(3?;fBUCh~k#9cA`fNZi|DQ|fX7~D8#{xQs8KY|)RSr#Jn6>eu(V$J7ARH=?mckc5~Owq}ZJ+nE~!vqVS z8ohCMC7wAN>$bmV!Sm-d Y{#%?UsHkaoo6v z( ^ zDp=*XEVNo*kPe2x1NV$*aXo^yZ;a5KaS7cEZt0?%8N@@mq0(J?A}U3ty;5KNs==F+ ztOyRQ#)*@z&Hi !Ri?FarVNZAoJET_lbmw(ynEL$8G%KQ`V-1m z=Yt=@rPi3a!F%)0-CKDcw7z`#l$-mHaJZL;`0TH!K$CxQ%Qj^ !rNmlIDX)=gSz>Y8d!o$At3BPKi579N zcLR(e2*7NMptiBf>sw&6>L}2^z3|4ALzgP;)TnmaLrb>LL3u@b;HuNs_DOK+3$n4E z4ye; 9C9u1v7-_Xy@Ul&(4 >pa#ix$>WifXK0pIFzvNgt%SYy@dE+xn%<>;7N zOw{;eG-7kWu$+{efSS!ZsQRGw;RerBjt(rb`N73$Cl{kK?VElUY1qbgxO8fE;-(*< zgN4_dv&2KT5s@qVyge-ekSCn!70cVkL3bo3_;U`ASY7g{xjbH;=@O5q4xQtU$NGCf zk49|_a}hUWXZ7st?$y+6tGf(d8H&j_$Dz|+(zA5S9I2{t8q&;^8d9Q`3G30B8;b+w zZrH-4TLP5coV2TR?^bqo?dl@%ZmP-0P!j8g29&S1M{|kFFJtzR?IUi=$=tdf?VLmj ze*DG;QgZV)P}Ng<*^XWx%$~6NXqgZ}R*mwt5P)g;i@c=wa3G>Fdb5W|TmB7?(eCI- zZKNuvnJh$yhKVqO&?|1j?zAP^bx+vb`r01XnBSOSiE}>6vttkP0r=!N<>h$Ti`Rg7 ze<(4(2mH >W~AdRXiOcbYw55Bml_ksB)X22ibZs=z`wYM@W zy?mVG%GC#LxRAZL6sG3kYl!wy+L&Hj2Yw}1C-x}x5b0`Td=Bb=E@biJG_FATJJ{0Q zb`f3$3CA%mEo+hv3YV<75zvLTjDmvIvgt8%w^KOgwgFnE8 k!{IUZ{=ZUNSx4A^< zR(hZ6a?CR)n0XSqfp4=b=tyl43hW9By^{ghio75=G2%Pm*FSv)wfqI^ P zxF~AaQ>vn~k{_67#yBxb#-i4S;F&6V9&rvFEQZgo9yLKHP9*J`7^j;WC0;KmT`4`3 zC5q;mwpeaJM(&BKQ$0E)DmRn3>T6f2{?NdVN+0b0RMj?;DE?wy=S~8&dWh9b*Eqei zcx#v(B1Ls+jQD9j_&7L?G80LsT)HDV(cFN3!?7B*@sm=ij^ZX=F9ph8KpE+nY+^cY zs$fpxl;5(OhW(VOmcl>T(C4YXIz%D!alU8(p>6o-b2k}Eq!|NZn_eS_Um+*QOM}#h zyEqQjs&
PNH%$!bA?vs??zWNT&H{4!B8(#iU zLtnFNY=fy3Noya*ID~jNTE@=SC8cgw0QYvOJ3tc7VpQXB0pq**(Ki3S2E%%l4jEia zY~3p2cp9(}CnhodI8~7(mPWDZDBS2`dx0qZzyYoP9QFJXqw$W;Peeb#gGpUb_`QsD zpUj!c19euT{N ~IBD$0lI?`Le^WZ}>NISa~p2$ZTRV zI(@w64(j0n4gFl6L~ZM&DF094Csq$Wf1(MV(|Z8?2c6A1t0z=Fq`UeOm7W;EJ9uav zDCc2HfDtb|SdG#XM*RP8v{4Tj*?)-ON`D*i^yQ8C34Xn4r>oMN^FX}h7rR=bsOV3j zRy7AF{S&Z_%&Xidbd&*9H%aNg6+6R?@}Du{U~@{mhv&qaZLv8eHgNmQe2L`pnEwN+ zSqv*^b(hb?F8{^QKZ@4!XLwfVJ_ewX7U|UKx2l!c<==p97{c{?K+%r4qi+uAooGR| z MM*!bar!wwNU29Gw1Ju?Y6|PM|sw4Lmry5iTAL(?zBqZ`|V)v>HPY}hF{sp$DX-0 z1+{uWe27*_smM39X0?Xl-C=c#GK*myE!t4LoKS6`#q)0gg7dSSVk;NkUF+=TAG%eh z<*honc9=TZMA3e0SMh)fr^+Y41ZDNh1m#p;Uk55Wflf2o`4ne*ElWJ3q6eI!(%|Gj z5MZYP+R5$hUk4_5z~}ChI2LCh=;EYLlz*1b{Z=4-K++c{U7QMiyeg+j^lUYuBo-d3 z;M7<93DJ6i2CYsT^_Ii;Be^wVW$hcJs`>PIcWCMXbVX5oHz=rn$0)x8G9Qta{}S5} zzx7{`b|?8pnMHL#&B1ncGQmUjC6b8dE#p}9x6gLCtqC#{ZRQEui4GSjlv{QsQ__}} zefgAK@v(IqxWdng^56ca|INQIwOIv|iF#kp+>T(oGe=5N w71U=2iak z_lT${yfp796ZARXR0)?0d20Da6Lb!nvG`N+6MBf0^R7;A68^34HQaGKER??gO{2>B z_S<*A1oXoLMJA{Jp-OHl`q6HZ;_jJq?liQux(+3uGE{i8lluCQGR(IRevhN0>RbIe zkRqa0apmT2l@XiQem#i(KsPIsnA{*}7KC}I5MGHt0_lkvLrsREH<^~}9bqK42&!+C z_I!ZTgJq#~G0kt&dFj^}{UE0zhAAT@VRxvb=$vo8!f*3U?+*tr&Kz(SvjcV>IJe8z ztiV4%ChxarZvLa3Pdrp4k~2oav9>D~!UW+s94~O{7j)uE^A39~|Nac@zF)(i@SC@V zp6!;l%WT_}?I-W0pO0&XI1207?b@Ets;)U-M>}Uacz1is5WXS2pu)j9L##1+g2J2+ zWq>2Fs~0gnaPo%+Cw~QGWL&eqez;aFzjv{7Bna-JaFnyEP%v0}x|->GMd2VGCVhkE zs=hdu)p49i>vVmMBcQP_;j$*4DQ#a54yVVi(V?0(SpEZGn!ch_D(y!+DufZ#acQta z3}KKLD7VokhYVjG!x`qn^n+PnN)$r}H-i@-ChCvJH7HlA M6+KgX{;sE%@~ zFds5cHM_coDU0x%)$IArq5Qe@ygYg_YMH|t9eAZAlsd@ECuJ1m5Kpt1<`gv#?-Wii zl{&xSb}dMFI6u7@RcBy~z>Aml{HQ MW!f8#<~f{}Ac$g<2S*nc|{JCLBNd zl%IS5boJ=ZPpuSGxQ-D!Zv4ZMNyZ;sPfVa*SRpFvtg>5jXXq0+%5#@EM|HxCw1#%U z_?*(uoVVvh$x$?iNXr<&FLt%1nn$%b>4H0`vM6Jaep?*N!Q@gNKl}21K;<$=uoP<3 z8A4+8`Y<;f2$6d_e_!MC=P!P1<5Pag{IkD*&Mh9}rS$VBry@D5Tc&+u)7d$3R|)dn z60td}96nGKK$FO3HnA-#`m6<~&nNw(V?8FH-hCy#nI5z;H>rS$K=IqB5B;Q$`&1uN zyj#s(Yi?vS2XJGQ_Vxqd iK%Vp0yX6geF%%BR_{seuwfKn;wAmEh z$WjA|yE;UlPKIH^PC3%jqFy5%vY5*32HC e zC9w|^RUv+2CIc(GkoDPba7eq `l5 Ka!IBDQxRVE=GIveSAj^QMK;B<4g_(vrn+Nd_H3PmQE zQ*0wDgNN#Y@7DkvXsStHNc)G?T&pa~&s-KA{71y}v6&k?hxd~K%)+dgzbl#&We00l zclkHqxfL(l_0z@*6n-5Y *>!{OaF5^`4QLk=t|@Czv;gr z=#N(xyA>zu9R1VeAtGi-xvw~{pnrHZ{gt#|rc~7Y*$JH9-kk6@cVSp}RFsh%v|9dF zs4{5vCwSH==T~h1F8Fz%Kb6KqZ#)23&v@XURqy@tP*lRFf`uw{_~QEoP}n7KsDg*; zd#KLVjM2@i)$=AND#I+FvP^)&WS_R|=IlS;c*2LM;Jjfj>iGd>)`UPiR*8lKcqUv? zwOUne>qjEW1XF*71}%0D;6e0&Ej`tA_fxC)U>5`@y|Krl)%Q?W8!wY76O=9!JaabG zKCqc3iihaW$!t`##qOoc)82UN{2|0kJnL-RjkDUB0H sCSy$LReasJv^@7&Ivpko?R^#IUEuUo z%OVyRcuL>QPMXW_!nUdAB(U(TKflZr{r&+beufAjZ~{vA^;DOQ%sg_hQk}2)14R9u z6ld9dk3*t=8`>{%#6NnnS0Ir6+W&R9%$99wUO-KBvtbBr+V{`CWAeWXb{OfQA3r{2 zM17snZ*8m@<4f>-B`>+_BxeEr`J?|&@>G3Uc1Z!EN_Y8C-K8CR*C}0xn?tpnPai+i z33gbPYnbCfdVb$8`m{b1wQppl;-P4DdALa>_Vy;?Wl7C)vg%lzn#JuVa~s-CAo|P0 zt$`(ej_RAiL2M9$5pU;g$k+e$%maRW`~LDBQ(oylVKiUpJL3*CDCmqW+Qumvot3|` z_t8AIT8Wod{f`VP_>n)My;7BjA5Ji@H}t=ROZk@nQJ!#7TDEqepHkd=iKY56{qV}q z<>HKG8`meycfMtD^0{=C-ptN~RyPuk+}d5&kb!ER`Migp>r{H`v@g0Wis!|2O5elI zFwU<({**0t_TkO^Mbxk}>cmg-QU4xA2ea;uanDTXC7@m1{PQt 0*Ab>FBNVdFTRT_?u^KA*h?V*7sbfM+8fQJeFc%LQcWz| z&ky+k=7Zwrd6l;8W^Cx$A?*b*Gv~W;m;Rg5-~2;>#moP+1ysMefnNB)<`~Fg(EO)2 zj-+UB6`;pMZ;QE(z+q={PZJMKsSZW0ev3XxMX0cn*@$ji`iLsf?X>0Nhfk@sjUy_e zncQN+{Z!Zkm|cn8CwC4z6K;n})SPm!6zFGQ$m1?n5VY3Ra;x?I$5(B7zj0iE=p{Mz zpD#C{+2}0=vn&&=bIdR?fzEaz2vRAiv K`cm zf=s>yfeCk^G=Y1+uS~Vv>0$fz>(_cg+ xwX;1~{aK3AC@uN?3==SmfhP`d(2A7g5<&}*y z-`Z^_3_abQ>}aWpEe>5o+UUT7pbGozUnTsk63w&@f&}_e!fy!Hd^Mv3&2s~J%0Zi^ zAl828QSPCT-6 4&WAq zG|ui)G74%PR+`XTH0zh*;-KHQu|R)A^K1AVk~VmVKynbEnr z9N@?4l>w4Yb87gBCscRi?EiUa?Q*3%)03I-?NWdB#7@RFsi(h%hT#L9FF?1->UsO{ z37V{SS^U#K{jS0j-u`$0`G2
pCfI1ULc6;o-(l=xW2-H)^j&r3Q!P!;&c=E)T*Bx#Fkt=S96_v>8$h!f z5KMLHWc%_@ic (kj|z zQO$jXttEif!{;b0oXk~9fOx(oP-F<2`J-s@FO2ypdfE;lO4H18eu6#j?}Fy4a;Y6A z6Y&YR4dudYP ROvce2?IZxMULwXO$e$;onIn9I-B4AJvVKTzbBlTLf3@H6~E4?Lm)ZegBc z{yYhSHqRs5%i`xPID6(@+-8*csrDn{ycVaOG@DA2FQ=Nsa;vBMsxx1AFV~0?M?>UL zIhzJu)J<)k%i^igw|sPRNA>Ugvd+Cl&UT|ie^H6k+%&*E+p_ziqB2D*2g-A+Pc7wz zXZ;6k|G{;wPH7I~|BO6qHvA*WQ +dNHh7VBzo2SJ84#~ zy>uRRo?z%(O9v-&Qz$1A@#Njwux{~NUWgy=F%du_duVxdEP&M&cge&-4wQyj;zSjI zcL*yQ)raeKXk%^WDFw~r)(;20e2S?)4(Wv|kWa7Xc#-RUR%@#RyepX;dYWp-E@e5I zOWm%O!(0PO+3HDy=pGLYNsI>z{~w1>xoc;#%=Z!Wj{#Obi|4%zC7V&(D(!m%M<1eT zLa<`F7C|%$e2F~xeaj=zMs+APTGhpwRscA RY~-&m3!cp#f=tp54g0Y2~-I8p>=aI)V~G38hk@SGApqpEf8g3!13qVcW8Z z?-_Jxf1c2OuFWcwRc)5Ha3m6K0+m2O52#tryg~BCUlk}PaH@T 0wUy6ip ze>n=2uq31@QytYcjb) ~|^y=xytvkMbk zy2H(V2XnyWGes<~NyRi_HuMDt^q03!opCZhz8NhIs^O*q`PkrWbyU+hDfmMN57kFx z qH6V$w$piI5*?U5I#o?S zPOhVK;prfo5G&}4Uiz&1*2=#>kO;=L>JiV)>Lku1m<~UCp1BkL -gir>u9+E^ z)BmG6N>AR1^XstpnG~1X-5cXR*vySn*>$|=bB4f62?yd=4<}~Q!eb97?W-em+(pn* z!nVJw?;?0#x{oKHs|8llpvPuTHNm4SuGO)(*7oxwYV~wboUj`PB~H2Ya_zawDM)Q3 zkHpJlV!vZSg!W+eZf1!=*p)q(#Tm+kRwm08BSQ((&jAw%m51%6C?RJ%kqWIv82*%# z5EG?);xN2MaVS}Sf~#qZ@;n|2KNrR17mxZ0kzkh2MEF&x+_E|QnAE;T)%m)xF2fvN zlNU0vU~2IIq!aOgQI~&gA-ZF5`Qe;t56iOqS1f)8(oP~1rPZM)2g^i^<2?@kDBd@7 z*cRwIKHOBOj)FG*=Vy<-l3|(F*H8Q-nQ#&BW)2c9r=aw8oC>+W8S{r;P}#U}qTo>? z7jn@iwA^TQLIiE~9!xkT$}iG4QCs3P5jxI?Gq#p Cgjo)>I~C6PkJ+rjpC(A z*^HY_^XI-1j?84mt)A=1p>kBHw%_{kI)}_GHrvnhVUT;$%#(Ie@4oFmFOYt6+s9Y$ zWaqK}_rL!2YrfGyStNpY?vx?KGKx){w=4lzU$%|hbC|z}Z)!^WDO_j?iZ3~R&f^b9 zhoU_~`swVsflDCT-*BM)Sxnz14LfL(3Xyj-HX)xX4^}HsnUS#9KYZtrN-~|FF|xXP zGV5Z7rZFH+AS!6 2$W(TiuPg=C@E2F;xDY-RF^U`@Kz9taX5wHlJ1Z3;6@bzkka zpAo7KmPv-i|4ef$c&yRU)B-YB=2@7~qr!vlrH= zm5%4ReC&M;S>55R7gK1fMw _o B7;XJKp18Sj~J9 zPGm1BxrtX$^lO^$McTN_-GzXA%M%`1JF49mlrHmG|Aouof#2r5Zq%*kJ1sBHd;SM6 zM~x2G?q+&4;l+qn_A0wdZmxhEUWwD~VSn#8(z!m-Iz`*yLAr4$Q`|%gRd_V~13c;e zim@4hB>kR#r`jKS!_6)wZl}3kNIefpbVl(U$;B$R=bz)H5<$Iaic>D#oxB;!vV_)T zr@9HiUBgfh*bTq@q#FOv$uqn?f%b55(x=UtLvgxf1gl`uLHP@ X3hry{A4&2w z)tx-ZWr(|mGE&0lhUj#0=np-d3%!4Qf)=lE^qUJ!f=!Qd!p7?CtZAAY?u|AoDpqc> zn`wQv;zI4VxnJ!pnY)fgnLRi 6TM#?y!Kpl6zcyWNimMa5b-v*^$JZq^0Cbb z=GHEsm_d237x+JOIEeKlB&6pWEj{fTT>N0uC$refOLScKr^`;9eIng{I8hE|QDzbU z7g~Sj1DI_)fX0i=Nz9HKzwzNY;)GM;&2<=Cs d#LHyk6cuZdFseVe7l)HP zb63G_W?pf;eex^zB+}2=`b}~k=9gtgJk5w)yS%Ru+>Cmg8h-!VNU9Z;=)EpwtLg=K zt4O~A^l*~-M*9|g{`{G;x2_~fS$;mAQ$SIZdO*R`Vip9NE_niGo{~~qZB<;qN;AKx z(i`~RpC3(VT>2-G(%Z+NFp%M2W6e3`)y8L30ZbiE@|>%Q13L*cZkDTalK7^8eirP6 ziso%S&VIWP3vJu9s1YE|HqiLU>RT9Q%G8VO_MT1P9tFKgzh%rrw^ #%7iL*GQ;mxAbsXzGn11(bed+ic4ii+ z7_@1bkTnSTlNxzKs}UmCvbMB2jN0U#swx}tD0oh+!UJG#ofF;j!D+P;oE?^#A>)|; z-2v7%Cy*T;B&gc2r{vlz{JK>%T1x-5xHW5D{HEwp|Zv|D5>qZd7UIzVKA173gNN zN)S6?i_$F=r614~iqpw_g9A$?L9?;XF8?~E!?MFUyd0ZGc5RMJI^6(WKRL>2?wxke zh{}bNvlTWWZ7^A9sWfz=FV#ZMkVuoVZDAgunW-^fNa?PT*G}rliLx)moP^iJX@rTh zCig~L8Xv3e9RSWBysnk$Vhex0;BaPH27RGu1#hbnsfOA}hJ~*amwc;~_*t1o)$zuz zrr90&VZMC9QIRFBUz)RVkEg{ `E9n z%u)y-9*$E#sivXzyS>dx`PrZO3nq3^?iFlqM@-LCzkp9~edx4zqTk?nYfaf?R@_<~ zc6b59PzQZYGGtyCF53&a9=^b%-h#=lJ^>8@YEY}^vdAoX1z)bIsv|E-kl)mv&CA2c zBHc^Pqr|SF(aa{HxI~a2O6qWPg5v~^pna0(vW93W;-;k9UIRCtda_tf9x<+W7wq4% zIsALJ)sG$s3~#QW2VA$7f^_Vxr1j#!ZDRKj2_mhr6{l}%3VNH!da9c9bL?IsDLkfq z;Sg1`jCKY^&fX!KRr|>M3U4r`)e#r&3u&}k-dwb1ig@f*l~ZySqZx#8 bg3%-*9 #@I~Akc5Ap&YBlW|k<(q?{@^bEeydFw1#voEIGBlu&=> z;zEW)QMzRVHCWkSUZKg@*8E&Z?Q6cik;dpDJ=VNqATkV|8%*pDR2tC5*d9upqAGUN zHZy8BWEhsaaVm&znMDYkLgn{5l4QrIbdrtk1xyG!(*~qT9Y92*1S|X=8}dy~#W1pO zjj!@)dM+q%&wO$&jh5ZjD1kvjhj$R^Jt|Z0h67MoDR35R9hC_|)ln%ki|&M}DUx== zEY#i*F>48C0}MUmm!&n&S$SjFPyFo |JhdZCt^a>%lTSw1 zte{TS)M&I;7xB%%0fY-2HeQKZjY*H(4#OU%{>!l=A*pnWvLBPwBuUx%J!>j~Lq%KI z7wv}rPt|sf+`ItFn@VD)zYLq097cnw7b**H{y#~a#ul %{PrfTTJk zHAm(`#@{~z!Na#lzh;oCO>w#hHqB;DoBT;)EsMt&91vBHzSv&y2Z0WBnMF6qsho&P z_3D|QiLu RokGVU7 O}WqyG4e zpK9(V{}iKh_D`6z4mW=8?QGC )k2g% zC|^uVFXtz2nkVl4^I&*Z5Jfr{$l=~~il;8W;XzoZDN =&k=P!Y*blz+4uK>%s-3j0= zaa&80$K6ecxldS9(_rKjs3J;MbF=q&$&aVfo4Gj;gmd8F5Hy@&g4<*)(ttIcp2cEG zB{mJ}HlY@dJFYTLG(9lJ5JOsy-|&It%=3 ER$qY{f~iL~tOFwp4ma}cZ>>hH zx16X@f%=x;ynxT3@EFE(2rari#9I@D@P5_*$5nVw-e=$Z^$q_Qzy+CkJa|U^P*y>| zL93K|<18P7d;oW_r6U~V_2-N3s7dYPCQ#FFs!TPEor7(IwlI$rlc5AZDdnhPpAbkx zE0aPzN$>>MIzkL(H%@31iBO$@Y|mTtVEB=X(tWD4A*}?EHFjymf-nvE{DPyGM3uxf zw?$ZO4w<)_j`6Rzq$YNI!5A)RH8VUtlUOHe(w(iwHfGTzt!-ak#6v?tdpZdE%c_)B zOs2iuz^x6erJ^WOoy0;^`jp_LQh(j4K-oj&G~BI|(Il5lRP*l(j*oBtIphvhqSC^c zH5q=KSk5u$3E9wjI*$h3gwOQ+EW#$&=mE5Tf=vKcHDx(R$#MNL;9^28Y>rs-gEm^t z3ymb`dQlR(sf|^f*jix^_^`?2<}thNl>p|UEUeCm3Mk92j=b6UoL@<+&$s>`84`HE zCIjg%Z_eSg`s#!Y0|bp0%ir>=b>cy1W*2P(4I||-LZ7|DOnRtZ)!ePiA6Be zZ*Q{w)9tJo-Kdn*=$!harLc0$)L;NSGNb0*Vdn%Tta-DTc|~28G3+tuEO}FNg;TRl z9_38v#ZfdHkya=1?vV_!DQxw^Nk=Pi5$RSk{3xm!VR|K)Td~e8t7loFq8>NVq_#Dc z)ThyoGSX4ohoXH{^XbrPMGvQAC9%q)(sdls-3>#RPwD*Hk8tgimOsU*kY>l HT `^G z*#OqtC%xWH+2TFV7l!qWB<^{kdG6bKz#T+Y(^WZEM8!#>x4- 0?bb&RSUoq`5& zjMd0RY08t>h>C#bwxz^k-1OUu(*74T3Fkf4y{jH(RI9bx1UE;eHs?L)B06no8LOvy ziifGpmL}(ru7qS&5Csvwa5|9Ka=NADznc)r$T-25@}t?@PJi t2Zw=`V2tbQ>tI{zbb4|9OT)}4R=r{02)#0WGF_#L`8VkyiLuG>&XXJ zWF98`pcnmKr;7BLgi7oUfz@ynfM(Yml5=X@dgrD*Eh^zFlJ;k8<@*QPI^#3063LdH z3(y%4z1&V*LnL37OBC8JPU#Cxzw9Nv^q3Z*NJH;31djmLO7m|uT-8M=t43+gb=5W+ zSROyLB=W+xr4KsXZRqqKbd@$H9Bp?pE{~Qu$4}#i-A;PS6QXZGq{3`_*Iu-o1<<=8 zVMsK^trP5d0-QbxmLla+Enj3Bbb}xQ45q0ShTjJ(7ZgRMVLKo2Bk49dXhKM(;tu1e zOE!QlBPoNlN{MHfXA5-MGETQ<%m(&b!DHnl7Qk_JR909qvtgQ}y9vrJ1W$>Q6r6 YK04MotCSShzUse@)cAdY@!(2;%gg`Yw zC2`|-!GssFVUGo0^Z)*ICXXy=Ta1@hT;>1tU;KA=5AHnLWieQ *cP1~^?)&6Gyg0 m2Kg zDcBAVx8D-yQ@r9N8jC4RJt8HgrI}ZYP!Vn_FBnEH)!Us&+4duRH^_r zr?q;XaJKP1+K7uYW#+Z_4rW5>?U8CmTW}oae=9&j0TnX`GD8% XCQY$eg zt2_~v%{01c344edea`jOl|>~Re)=tC^^VsZF~4TiLvA4VO1Y7mhSsIKZ@PtuG?zsu zje5R%p8qt`IWzOTPR(W=%!jg7kcHY*5iC$^#9P@UmF?EiTHW+M( g{)$X$h&O_r7pY^Cxh~@;{qGn^V1P zteIT)RhC^{ZH7-gGvOya#}B3X=SB{1+{07)9Fc3Mot2P4=N@M>1Gu z1&6HA%$ZgCO321JN#t!@v8K#9C-+QfGmz)%s&YnL=0%txnDs(6d66E|h`{v#bXH|5 zAN?wdS;2IItB58d-3IYelC$%NrZBAKL|quWL`%EKKf0{5T#HGBuJVb?Zx)c0Dzzd$ zPJuINxlE2Z^ucJZ`H(m%T(IWpFgw#ya@LVv>gy=+gcuJk)mJv^ddv)>G@HiQf(^sb z5sOdm rSP7AXIRQ_ zZUyNFA65r>^1OQcJ|$*FSZ1rgszv-<)dezPE@iX4fv!Ti>+!_aJm+xXc>WrgfoFPN zYC^>4)!ttjh3~6R&P-ctcS+zUF{Ed{X~8T?wVY_)+$> ZOBC$RJ~n3+SQDvwS;^~|>IYK$B9%s|~T`J_+6)&Ga@Y&59_?hrv|AR1TD z)tRk6AZiRNQuo@h;(zIPH_F&?12{c-mX7tBEia=yEs9C?!l4oB=HxVQl-)FBCui}u z|9+ilXDgav+miAzy((M{=_M~%vBM xwHg_J)t2V2t%!RUG#oiu8kXKsLq^z7+y#X_;6{+9u^&lPoBVYJTM zc2>z*2JMes3Z%}yg)#vVH)lsL!5Yt)>h(&iCgE6)iLp+%8{6lJmzu!40DYY%X}f&8 z4s 2bgdyCyfy6r=9?N{|N8sauV26CzfAe@?RPjljO1q7KOEQV zV>`Ib>9t08 $&ZsgD<|v>6Wl`YMD+B{^NOovHc_ z44Ovk=fH=rLsZ1i-z|+j9BG)F6&i$L3cv6R9+zy `6{?URVOdrw #%t&XX-wQ?kW4 ziIv_I&?ot|1^uiJgoqF7xG}NxX2N9@&}qqB-$0~7Q|xsocTHI-(iG!1Xkx|;(HJ#1 z@pfXWEo-`H_sLc_K}lBs^t*s2rSk0xIv`WgZy@P95wy!SU_G^gp4uV^8X1OY!t%K? z^K3;|=YLCO#kg={ly^w3uYdT5fB08_`HTEaTV)JLpeqxaCqp~{ba*=V1%W%sf{)eO zs>TT8!w|;sUeLO&_?Xr)3upyN9-TZhgeE&ne|-3T?MsyU2hrwiIel;eLlS_{B(|pA zRgme8TS{s~*BR{Zzcb6Qaw_KU7W)^1Kap=55PX{_9$QTb>cNm5N9UX~mbyD`V7u4f z^2nIt&;GD|Gs@Etyus0!Fi|QKFafrx=q_1lvjQkohggkh-q}Jw&=#sl*;D_=|MI`* zq o_kY@S$mZNc}tf;f3Bl+N$>N*U`4iN7- zXb!VlS~Wau8iyQoE)1C8;2F`j!L%9)})!g9*_xeoUain$**tb(k@Y=`9FdYdw7C z9Rw3v>H6!T5O03a=OuwT#Z55IG9Ye75dPI{Cy)*c+)|Q!J6->Qm7OMy4RHcarw#(? zRf>3}6VB2T$MXCViF_&8f+31FS}Mfmzd|?JfEs19tqrAgM%J9=#ASx>tp0P3x_a=> zK>_45ZPI7_a4bntc@drI-R{h(p11EeT;o-uJ-`M!ZO^3I$l%;!7n=jo>9Jw$+29GC zw ZC!lJYjxfQwt6vJT?d(_i8}G%Izz3v=6O!p z3Pm@^B8qbrv~M}B373>RlP~4n jQOg~a_BD1_0c`^DmkIroMIwMcK1I~{=5~M zeya|pT^U;J^guZaQ+PGJ|0S!;CamLvNIxvX-|pyw0j!=E!8d%FIk#<$lm3 z!FohCoQ~xtKK4oA5w|1@9XzAWp`Xuowc7=2ZN?`xb)*v;^zsV7IY8^D*;a!RPP*aZ z$cje&sNm)Iz+!^(x7vx`NA7Z?Ri8He&^QRwk4^N%q_djzNx>| Y>2_Nt@|FB6SS<1{w@Q1to;L|3pk@DwrE#@ljpub5+mo8 $magJ$2le|mo-3#mk;ZWeQOAb*;4z+i{~BlldinE`!!;)l3`xCL!*qAP z+u)-l4?qbJw{_%wejAwQL82Hu_1vy5q_;Z{yq68l;U(67^SOr~%y1g9K1=W@GQ
0AJsfN@iZx{6}4DBUJq|2@EYi=OGIBuXzoL|*K`-&T;(UImK$=cU}Pn}32< zXlA}M3sXxOhbqlUqyxgpPJ(%TO&~aoMjyf6-gv6d*9oSILT!t5j!jOhJREs9mKCer zM!Ayd39X^2U8S8He_Gj=41{A3Kcz-)SzTzUmT-C`7Fg#EZI>n$LuV?w1JrHrt-|*= z1wOk%-#)*6{#RcdyxLN zL4VBz2VdyO&z4_4zy0O&$Il=AGKk;FurFMImLI#tBn#1eLuH4tb3N=KJL-188p4)9 zh&T}OCw3*bJp#42|LMP+|0dRQ5nx>CS3;KuaUy$;Kw5LCAz(rzcd7-Vpfmdbm8c<$ z51`vrH{e$UlsIvg{FK!dXkt2wK|6YwqmSxZgjub?xRj1@l3(8NkarX1<) KzRLAdZbo+M6^`%BWZO~!M=nJYkSb#Gb`jdP-tjiCvs%gU_(onJcq1BB?{y4Nl z_ECo~4;oN?j&{VE+jPy-QDws|FwFRAOKor Suc+o;w>DmqVvUQxW`ojJdXgiusw*Am+l6)CGqVb0ZKP_L! z_BXDF#Q)VZwJlZ(*S21Q858%=BWM)co>P-oIpSK`4=iE*371)^aPX??D#O7}gfpNT z(F>gX(po0@XLv`VLhjWBEn1qX513^>ft9Uf%QwO0YXo;waBv_vdhdUteA&}kMJA1R zr<`a5xpiM`8TM=stG;p4#iUWe5yZ9`R)Ih2A)e!T=H&It*xyG%KKhsO90q=m^Na`n z?!6KZ)esp(!jes=(V*!$*HlfJ151>19hmMzbrC@f^~u~&DOQo_;NB WB3mq DpoqfhaiLZWNoy(H0J)Fqy~KsS7#)Kh=yu<7 z?opwP>CZ$@CLC@0Es?o8Y~VH~8YEzCONw|}7@mN3PA0LUnM;siR= l>E-M=JRp6FUTgmU8x2PTWt)%}%l(EJ@SOKsV|dYLSli z vWV-}0;%GOV{l8up;o z-O{tkKf&2Q%Vfq;Dk%LP$g%n+w1|i515O>v!JU7J7O^>hn9@u9iq$PdE*3*?COYR9 zGppqCyy#)39O+hDqSh{c;qBVO5$T5a_&5BLl9*PnELz=N@n_NXNawZsfNV<(i*7Hq z9}@S_8EK&?$t}Ysnd0n4mL?^xb}O*hm9ZXuhtM@ASu4qn%fnr;tIYmZ%Q?#j$n+8f zd9|pmqx2?z(RR~@yV~L(WzO#o@`wk??Zy$4WV)mJ=6Cnm@shv#97ic*K0I-=I%65x zMz;*3@LbJvN#S>hjg{dfe4$aE^v|>g&zwip`ObV3#hov`t~-ZX`)bX-T`t@>&jc8c zIqmBjI9Jon {tr%#(OVGr#9E*j9#H8l%73 zvVURi1sv)+=XAf1|7l8p7MXb0e!J1=&j|mu=){@fZtq5&S7!%0daUJj-7jWdX>sTG zh9LCpMJh{e{?OD;g%Pg%lVT);M`^I{Np@MH*!q5#o9TxnLT-;M+c(`UkMvjU(CmA1 zLZ9%aX<_tpCpKnjz!t&SdrPY=C3*^{fOgd^HGpji!0 |FY^J_ z>BAmXeoi&$R_BqM7Pa3zd<^TORrR`ZYsf4KXI^l~&r5-7XzT-C?mdI$BXl{d_e3 R?CDWiB{S QD&;@XFLGAFV3ZpxSc1O$ZYRbTFz)j9%O$jTo-XwNl{Ud-6@l} zJ<(>jF{2XPoW|RfhjX|1g;H~6sma=PU*bWq`*VAYhoJ%T%i9&izQ7h7(u<~{O_Eii zKl;*6*S2f(h%o+lIcVJI(YXftk=GL$Hl`-$zToJufcXG6!UTvy=`J~$u=1N>ol;d0 z>kQhcGd%zU(WaSYr3 B47yR*3+nH=e6nBM-!|6=|Z70Va^jP+|U-DeNZiwtMpt$MB* zkXVni5O9K7|K&`hoR2t)Bst`Lo~m`Ot4`OtT{MJiKPLE^u??hcnyln_L+gs`#4@yN zJp@w$B5ET_$KkREbdO5W+y_9hziHxHA`eQ(-CsZP-I Gc-NP|q OE3+8-T*fuPC#ylW=~8Wt^C$T+@rN&wA1xJ|BkU z@?_^UIG51G%27w<+uIWBXQP{nTJznF$VbJV%#cMPEtqN`IT((SF0OQZZYfyw!Lt$L zEa%(7&&Jv qE86HYcM5Ve2qCS`iWvUNL8g3}QK;RndL&TkNZrPU z(;U=?>1|E`(-e^mXX}i4XotW%AFGp09|jtWPQ*SyIk(r|!fNihp0~O@z2hZri)xHs zQZlP}F3K#OZFn@xu?OyeY1v9p&Nc+Bi(%%zR42Lm07%MSo~(8;CIPD3%G=1?YEC3u z<~Q=vb(B6!=m}HK_93vE#{%!*^^B~2Xo0DBo>C$Pou$=G4rVJ6wX2iYAi)#ia}&!G zPUXYBbohZV#_pfsWL|s;X_9d>Tn{!8MM~$a6s$(ijMtzWGY2W<>6QK=0eU5?!;?CV zh-aUl)(Z}sZ*L7SGXKOX+A}g^egUl@{8MDG>f$gQ;fxP(l`uBR;qNpvUpFO6I5{M8 z73c&Q+niTE(J$x3N=-LsYP8mF?mbAHrfaN5E^1LWu7 q3cz5YO_`wx{B3+X~TG*K>le2$A$cT*ZnOWS}|Jpf}C1Qol?b}cY1)+XS$HX!nS zx1x^rq^C}4GtIz`p#Jth{OA9^_8`4+gUp5TascKgiqSdf8*%W9FyMEcrJ5NpA>PX; z-p08^+lo}?GCvdBxUtZ#eNcuaGc5#zFSRxfIiV>lwW(B{L3t=Wx_e-}#Qfg(!8!pI zLNFW<@GF&$aO;434_^_6bw`!A$$M(=VfyeLY|$p#6#&j=f?uI)v&olbM?m6V7!Oh2 z3prCQI3LmPxH#1*wq}TTBDC#KF3 *g)!b*+r@uSO{q_gF7;2Cb&7+29r~3I+5Mt?Nr)ZM?#HKM>WygY&-& ze870ZWcU)V1_Qir^2q<0bEPfkDlaW#IIWdmK<;YSqe_dly!7N5F`ancW2_&mh-!FA z)8&c-D*^PnVHu)j1fKHHl&fWo;PRluseCn;|I${E+X OhclaL&Lg@bfq=?;#45`})#{y92#Q$$#hGm8TFN z)acuM#G01-OHzo@r&{H$zn7Gp{&X5dUoSqV QHOKJ_AwAj}^7JAp*MdsDRn4gWbyT0Vz-Vs#@GB^F zOZoVMqdEbtV9IrV*3a7WA5k-i+NCU#e1@dbs6+I8aUlI!omLho?T9_03LANhc!8~l z^IK|VdUUeWw(=f5mpxVoW@wh tlG+D0HVU}yz8NREOD?mIq zxy5pNUVK_2kuNVWDdG5#?mprd4R{)t-xn5oQQ7D@#?qz11oNx*^m*N$fKzC-CRI7b zXyjB;jq0s!S%yB!=LN^IYPeYuskb~aqoxI|=){m88$i|Rl7 m#xDM+M-H(Ctv0ELubx# zR8e_SO%K@Gq@n1?Z}WnqfERBUaCdqHySh0W36auhjV@BNib3*Hp+`AA%gD|cWjPJ; z!~eUElDIpjQWT;3Tm7m=NI{>dfv{I+{f>5Y $N#lxZ1h;>4}F{N?0Rzvj^c(b$9;V_Qmz7XtV<$+xyUlSdlc!}o}HrVi5Z zU2Y`VTM7DCwl62k4@{3MS9L=8@=w2I)+E&jx(c^L-o(A7VU#gE6^e)IFQQgI!J`f} zv$#+Nhif52E3-8~4{v(Gc6eHyzlcY@qMx0_>UKD9cGWT3hk3p@-ho*w9ak59_vtbT zy%kQYpB_RNuW(y^PjtEt!{y|0(ke=IDJ04gPec`*Z*GTjlXqoqeO-4j`8Sgpo9JZs z`SH<3H1Fdh;h1Gr&N>psEw~%`+KL66Bm-8pZbuslvQmxC9p<)TVL5UWo}d-2T44G% z#N!7m*lHf!BupLEhMX-W$0%s*%h_~G`X`Rk;xVHV#e_{6_LN0w+McsWRyUo#0xse+ zsp&BJ+%i4jH@%{RN&4Z0`+t4?+VSLlQ2v?!i926 PX<95(Y$L`J`a0(x8qTbe^ohuq1uK z!DR(`ban=Dl@B}z31kN7AxsDA0lVFqUImO}^%x+GDEs)4ptDT+8yjK3S7%JxY2mL% ztH-I$ET;rG>4B*l77}SP*RaOb&cI*uwx83sgWzw3VZzX{Yfr?}55FwXqul JEz@6{WFiB@&=5bPyYJJTYgui-`D8z`Sa)g^$mB|{B|L*joup4mBf}v zM`pgjupex@3#o_SK!(L8 tShK2yO8ZNnD~O)bS$c8w zaN(PlYy@k7b&51S_zGXYe*OJ-|F5Y{ {xfKLCt%iL6;6~7TCH*kx~tXA{8RYbtbUH4_&h}qYOTJseb3?U zkpIx|+_cSk5dGb8&XeM~m#PD%-uue~BR&?g%ktyL&VMlC0DVLchT!Mbjo6K7ydQY) z0}AkC<$Utv=2ji*z-B&3wS3ZtGhMI-?pbGxss>v9L;Q;7L%8SYpnlHsZ^8@De=~NT z@8y5;JJ!z_@jH0g6`=f=fqoI&!v+iF`mgo=yu-g4jb5UhjfxKVnuAlN"p3ja*} z-TgMzJ*)S`-gF62I>HMNd)kR- R4W3b9HR6tdw1jw)w)|qMDJ%`Vo#M~IC