---
url: /article/bvixslcm/index.md
---
## 前言

之前在开发机(Ubuntu)上安装了[Caddy](/article/7uov7swb/#_3-4-3-caddy-推荐)、在 R2S(OpenWrt)上安装了[Caddy](/article/7dobd88o/#_3-安装-caddy)，每安装一次 Caddy 都会自动生成根证书，客户端设备想访问站点就得导入两个根证书，不如这些 Caddy 都使用相同的根证书，那客户端设备也就只需要导入一个根证书即可。

## 1. 统一服务器根证书

证书所在目录如下：

:::tabs

@tab Ubuntu

```bash :no-line-numbers
# 使用 apt 安装时目录属于 caddy 用户的，需要切换到 root 才能查看
sudo -i
# 根证书路径
cd /var/lib/caddy/.local/share/caddy/pki/authorities/local/
# 站点证书路径
cd /var/lib/caddy/.local/share/caddy/certificates/local/
# 退出 root
exit
```

@tab OpenWrt

```bash :no-line-numbers
# 根证书路径
cd /.local/share/caddy/pki/authorities/local/
# 站点证书路径
cd /.local/share/caddy/certificates/local/
```

:::

我打算统一为 OpenWrt 上 Caddy 生成的根证书，那么在 Ubuntu 系统的操作如下：

```bash :no-line-numbers
# 停止 Caddy
sudo systemctl stop caddy
# Caddy 根证书
sudo -i
# 删除根证书
sudo rm -rf /var/lib/caddy/.local/share/caddy/pki/authorities/local/*
# 删除站点证书
sudo rm -rf /var/lib/caddy/.local/share/caddy/certificates/local/*
# 复制证书(假设已经把 OpenWrt 上 /.local/share/caddy/pki/authorities/local/* 放在了 Ubuntu 的 ~/crt)
sudo cp -r ~/crt/* /var/lib/caddy/.local/share/caddy/pki/authorities/local/
# 设置权限
sudo chown -R caddy:caddy /var/lib/caddy/.local/share/caddy/pki/authorities/local
# 启动 Caddy
sudo systemctl start caddy
# 退出
exit
```

\==注意==：当 Caddy 启动时会自动将根证书安装到服务器中，由于 Caddy 用户不是 root 用户，这个操作会失败，使用`sudo systemctl status caddy`查看时会看到提示`failed to install root certificate`。我们就需要手动安装根证书到系统：

```bash :no-line-numbers
# 手动复制证书
sudo cp /var/lib/caddy/.local/share/caddy/pki/authorities/local/root.crt /usr/local/share/ca-certificates/Caddy_Local_CA.crt
# 更新系统 CA 信任库
sudo update-ca-certificates
```

## 2. 统一 Windows 根证书

先把之前导入的证书都删掉，按`Win+R`然后输入`certmgr.msc`打开证书管理器，找到之前导入的证书，右键删除即可。接着再重新导入根证书。

以前导入到浏览器中的证书，也可以再在浏览器中找到并删除。浏览器不会将系统中的证书导入到浏览器中，它会直接信任系统中的证书。

## 3. 统一代理软件证书

由于 ios 系统是信任用户导入的证书，因此 ios 上的代理软件通常都会有 MitM(Man-in-the-Middle Attack，中间人攻击) 功能，这就需要导入一个根证书并信任，代理软件就会使用这个根证书签发站点证书，从而实现 MitM。这个根证书一般是由代理软件自动生成，有效期为一年，当然可以手动导入已有的证书，所以我们也可以将前面的根证书导入进来。

支持手动导入证书的代理软件有：Surge、Loon、Shadowrocket、QuantumultX，这里我们以 Surge 为例，其他软件类似。

```bash :no-line-numbers
# 要安装 openssl 命令。 pass:123 表示安装证书时的密码，若不想要密码则留空 pass:
openssl pkcs12 -export -in root.crt -inkey root.key -out root.p12 -name "dev" -passout pass:123
# 需要安装 base64 命令。 将 p12 证书转为 base64 字符串。
base64 -w 0 root.p12 > root.p12.b64
```

然后将`root.p12.b64`中的内容复制到 Surge 配置文件的中的`ca-p12`字段值，`ca-passphrase`字段值为 123。之后安装证书到系统并信任即可。

虽然我们在上面导出导出 p12 证书时指定了 name 为 `dev`，但是安装到手机时会发现证书名并不是 dev，而是`Caddy Local Authority - 2025 ECC Root`，这显示的其实时根证书的 Subject，可以通过命令查看`openssl x509 -in root.crt -noout -subject`。

如果一定强迫症想要显示指定的名字，只能重新生成根证书：

```bash :no-line-numbers
openssl req -new -x509 -key root.key -out root.crt -days 3650 -subj "/CN=dev"
```

这里`-subj`的值是有格式要求的，`/C=国家代码/ST=省份/L=城市/O=组织/OU=部门/CN=主机名或用户名/emailAddress=邮箱`，但不是所有值都必须。

## 4. 同一代理软件使用自定义证书

生成一个具有自定义标识的证书，然后导入代理软件中使用。\
首先在 Surge、Loon、QuantumultX 中自动生成证书并安装，然后对比差异，发现在证书的约束方面各有不同，其中 Surge 的最为宽松，故按照 Surge 的标准来生成一个证书。

首先创建一个证书配置文件`rootca.cnf`:

```cnf:no-line-numbers title="rootca.cnf"
[ req ]
distinguished_name = req_distinguished_name
prompt = no
x509_extensions = v3_ca
default_bits = 2048

[ req_distinguished_name ]
O  = Mayee
CN = Mayee Long-term support

[ v3_ca ]
basicConstraints = CA:TRUE
keyUsage = keyCertSign
subjectKeyIdentifier = hash
```

接着执行如下命令:

```bash:no-line-numbers
# 创建一个私钥(无密)。如果想要私钥加密则: openssl genpkey -algorithm RSA -aes256 -out RootCA.key -pkeyopt rsa_keygen_bits:2048
openssl genpkey -algorithm RSA -out RootCA.key -pkeyopt rsa_keygen_bits:2048
chmod 600 RootCA.key
# 使用私钥签发证书。-days 设置证书有效期(单位:天)。如果使用的加密私钥需输入私钥密码
openssl req -x509 -new -key RootCA.key -sha256 -days 3650 -out RootCA.crt -config rootca.cnf -extensions v3_ca
# 生成 p12 证书，需要设置一个导入密码
openssl pkcs12 -export -in RootCA.crt -inkey RootCA.key -out RootCA.p12 -name "Mayee Long-term support" -passout pass:123
# 将 p12 证书用 base64 编码，方便复制到代理软件中
base64 -w 0 RootCA.p12 > RootCA.p12.txt
```

在`rootca.cnf`中也就`[req_distinguished_name]`节下的内容自定义，其他不用动。

将 base64 后的证书及导入密码复制到代理软件中，然后在软件内安装证书会下载描述文件安装。注意，当前只有 Surge 支持自定义的证书安装描述文件，Loon 和 QuantumultX 安装描述文件时会提示错误，这并不是证书有问题，是因为它们只认自己生成的证书来作为描述文件安装。解决方法：证书只需要安装一次即可，如果有 Surge 就用它安装，安装好后其他软件只需要配置好就能用了；如果没有 Surge 就把 p12 文件传到手机中，然后点击文件安装，输入安装密码即可。
