关于 dotnet-devcert-trust
面向 .NET 开发者的 Linux 开发证书信任诊断与修复指南,涵盖证书存储检查、发行版专属恢复步骤及 Aspire TLS 问题排查。
主要功能
- 01五步证书信任诊断
- 02验证系统 CA 证书包
- 03检查环境变量与符号链接
- 04按 Linux 发行版恢复信任
- 05排查 Aspire TLS 问题
适用场景
- 01修复 Aspire Redis 的 UntrustedRoot 错误
- 02恢复 localhost HTTPS 证书信任
- 03配置 Linux .NET HTTPS 开发环境
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ aaronontheweb/ dotnet-skills --skill dotnet-devcert-trust安装后在 Claude Code 中输入/dotnet-devcert-trust确认已加载。
详细介绍
Linux 上的 .NET 开发证书信任
何时使用此技能
在以下情况下使用此技能:
- Aspire 中的 Redis TLS 连接因
UntrustedRoot或RemoteCertificateNameMismatch而失败 dotnet dev-certs https --check --trust返回退出代码 7- HTTPS localhost 连接因证书验证错误而失败
- 运行
dotnet dev-certs https --clean后需要恢复信任 - 为 .NET HTTPS 开发设置新的 Linux 开发机器
- Aspire 仪表板或服务间 gRPC 调用因 TLS 错误而失败
- 从 Aspire < 13.1.0 升级(该版本默认不会在 Redis 上使用 TLS)
问题所在
在 Windows 和 macOS 上,dotnet dev-certs https --trust 会自动处理所有事情——生成证书、将其安装到用户存储区,并将其添加到系统信任存储区。在 Linux 上,它几乎毫无用处。该命令会生成证书并将其放入用户存储区,但:
- 它不会将证书导出到系统 CA 目录
- 它不会运行
update-ca-certificates来重建 CA 捆绑包 - 它不会将证书添加到浏览器信任存储区(NSS/NSSDB)
--trust标志会静默地成功,但证书仍不受信任
这意味着 .NET 应用程序、OpenSSL、curl 和浏览器都会拒绝该开发证书——即使 dotnet dev-certs https --check 报告证书存在。
为什么此问题会在 Aspire 13.1.0 及更高版本中出现
在 Aspire 13.1.0 之前,Redis 连接使用明文。从 13.1.0 开始,Aspire 默认在 Redis 上启用 TLS。如果你的开发证书未在系统级别受信任,Redis 连接会立即失败,并显示:
System.Security.Authentication.AuthenticationException:
The remote certificate is invalid because of errors in the certificate chain: UntrustedRoot
Linux 证书信任的工作原理
了解其架构可避免盲目照搬的调试方法:
┌─────────────────────────────────────────────────────┐
│ Application (.NET, curl, OpenSSL) │
│ reads: /etc/ssl/certs/ca-certificates.crt │
│ (consolidated CA bundle) │
└──────────────────────┬──────────────────────────────┘
│ built by
┌──────────────────────▼──────────────────────────────┐
│ update-ca-certificates │
│ reads from: │
│ /usr/share/ca-certificates/ (distro CAs) │
│ /usr/local/share/ca-certificates/ (local CAs) │
│ writes to: │
│ /etc/ssl/certs/ca-certificates.crt (bundle) │
│ /etc/ssl/certs/*.pem (individual symlinks) │
└─────────────────────────────────────────────────────┘
重要提示:将 .crt 文件放入 /usr/local/share/ca-certificates/ 是必要的,但还不够。必须运行 update-ca-certificates,以重建 /etc/ssl/certs/ca-certificates.crt 中的整合捆绑包。应用程序读取的是捆绑包,而不是单个文件。
5 点诊断步骤
按顺序运行这些检查。遇到第一个 FAIL 时停止,先应用对应的修复,再继续。
检查 1:开发证书是否存在
dotnet dev-certs https --check
echo "Exit code: $?"
| 退出代码 | 含义 | 操作 |
|---|---|---|
| 0 | 用户存储区中存在证书 | PASS — 继续 |
| 非零 | 没有有效的开发证书 | 运行 dotnet dev-certs https |
检查 2:系统信任存储区——单个证书且权限正确
ls -la /usr/local/share/ca-certificates/ | grep -iE 'dotnet|aspnet'
| 结果 | 含义 |
|---|---|
仅有 dotnet-dev-cert.crt,权限为 -rw-r--r--(644) | PASS |
存在多个证书文件、权限不正确或过期的 aspnet* 文件 | FAIL |
之前操作遗留的常见过期文件:
| 文件 | 问题 |
|---|---|
aspnetcore-dev.crt | 通常以 0600 权限创建(update-ca-certificates 无法读取) |
aspnet/https.crt | 旧版命名约定,指纹可能与当前开发证书不同 |
权限为 0600 的 dotnet-dev-cert.crt | 名称正确,但权限不正确 |
修复:
# Remove ALL stale cert files
sudo rm -f /usr/local/share/ca-certificates/aspnetcore-dev.crt
sudo rm -rf /usr/local/share/ca-certificates/aspnet/
# Ensure correct permissions on the dev cert (if it exists)
sudo chmod 644 /usr/local/share/ca-certificates/dotnet-dev-cert.crt
检查 3:CA 捆绑包中是否包含证书
这是最常见的失败项。证书文件存在,但从未添加到捆绑包中。
openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt \
/usr/local/share/ca-certificates/dotnet-dev-cert.crt
| 结果 | 含义 |
|---|---|
dotnet-dev-cert.crt: OK | PASS — 证书位于整合捆绑包中 |
error 20 at 0 depth lookup: unable to get local issuer certificate | FAIL — 从未重建捆绑包 |
error 2 at 0 depth lookup: unable to get issuer certificate | FAIL — 同一问题,不同的 OpenSSL 版本 |
修复:
sudo update-ca-certificates
# Expected output includes "1 added" or similar
# Re-verify
openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt \
/usr/local/share/ca-certificates/dotnet-dev-cert.crt
检查 4:环境变量覆盖
SSL 环境变量可能会将证书查找重定向到系统捆绑包之外:
echo "SSL_CERT_DIR=${SSL_CERT_DIR:-<unset>}"
echo "SSL_CERT_FILE=${SSL_CERT_FILE:-<unset>}"
echo "DOTNET_SSL_CERT_DIR=${DOTNET_SSL_CERT_DIR:-<unset>}"
echo "DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER=${DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER:-<unset>}"
| 结果 | 含义 |
|---|---|
全部为 <unset> | PASS |
| 任一变量已设置 | FAIL — 可能会重定向证书查找 |
**修复:**从 shell 配置文件(~/.bashrc、~/.zshrc、~/.profile)中移除有问题的变量,然后启动新的 shell。
检查 5:符号链接完整性
以前删除的证书留下的过期符号链接可能会让 OpenSSL 产生混淆:
find /etc/ssl/certs/ -xtype l 2>/dev/null | head -5
| 结果 | 含义 |
|---|---|
| 没有输出 | 通过 |
| 列出失效的符号链接 | 失败 |
修复方法:
sudo update-ca-certificates --fresh
# Rebuilds ALL symlinks from scratch
完整恢复流程
如果有多项检查未通过,或你想从头开始,请运行以下完整流程:
#!/usr/bin/env bash
set -euo pipefail
echo "=== .NET Dev Certificate Trust Recovery ==="
# Step 1: Remove ALL stale certificate files
echo "--- Removing stale certificate files ---"
sudo rm -f /usr/local/share/ca-certificates/aspnetcore-dev.crt
sudo rm -rf /usr/local/share/ca-certificates/aspnet/
sudo rm -f /usr/local/share/ca-certificates/dotnet-dev-cert.crt
# Step 2: Clean and regenerate dev cert
echo "--- Regenerating dev certificate ---"
dotnet dev-certs https --clean
dotnet dev-certs https
# Step 3: Export as PEM and install to system trust store
echo "--- Installing to system trust store ---"
dotnet dev-certs https --export-path /tmp/dotnet-dev-cert.crt --format PEM --no-password
sudo cp /tmp/dotnet-dev-cert.crt /usr/local/share/ca-certificates/dotnet-dev-cert.crt
sudo chmod 644 /usr/local/share/ca-certificates/dotnet-dev-cert.crt
rm /tmp/dotnet-dev-cert.crt
# Step 4: Rebuild CA bundle (CRITICAL — most commonly missed step)
echo "--- Rebuilding CA bundle ---"
sudo update-ca-certificates
# Step 5: Verify
echo "--- Verifying ---"
openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt \
/usr/local/share/ca-certificates/dotnet-dev-cert.crt
echo "=== Done! Restart your .NET application. ==="
将其保存为 ~/fix-devcert.sh,需要时运行 bash ~/fix-devcert.sh。
特定发行版说明
Ubuntu / Debian
上述流程针对 Ubuntu/Debian 编写,可直接使用。
- CA 目录:
/usr/local/share/ca-certificates/ - 证书包命令:
sudo update-ca-certificates - 证书包输出:
/etc/ssl/certs/ca-certificates.crt - 证书格式: 必须使用带
.crt扩展名的 PEM 格式
Fedora / RHEL / CentOS
Fedora 使用 update-ca-trust,而不是 update-ca-certificates:
# Export cert
dotnet dev-certs https --export-path /tmp/dotnet-dev-cert.pem --format PEM --no-password
# Install to Fedora trust store (different directory!)
sudo cp /tmp/dotnet-dev-cert.pem /etc/pki/ca-trust/source/anchors/dotnet-dev-cert.pem
sudo chmod 644 /etc/pki/ca-trust/source/anchors/dotnet-dev-cert.pem
rm /tmp/dotnet-dev-cert.pem
# Rebuild trust bundle
sudo update-ca-trust
# Verify
openssl verify /etc/pki/ca-trust/source/anchors/dotnet-dev-cert.pem
主要区别:
| Ubuntu/Debian | Fedora/RHEL | |
|---|---|---|
| CA 目录 | /usr/local/share/ca-certificates/ | /etc/pki/ca-trust/source/anchors/ |
| 重建命令 | update-ca-certificates | update-ca-trust |
| 证书包路径 | /etc/ssl/certs/ca-certificates.crt | /etc/pki/tls/certs/ca-bundle.crt |
| 扩展名 | .crt | .pem(可使用任意扩展名) |
Arch Linux
Arch 使用与 Fedora 相同的 update-ca-trust 方式:
sudo cp /tmp/dotnet-dev-cert.pem /etc/ca-certificates/trust-source/anchors/dotnet-dev-cert.pem
sudo chmod 644 /etc/ca-certificates/trust-source/anchors/dotnet-dev-cert.pem
sudo update-ca-trust
WSL2
WSL2 运行独立的 Linux 内核,并拥有自己的证书存储区,与 Windows 主机分开。标准的 Ubuntu/Debian 流程适用,但请注意:
- 共享文件系统(
/mnt/c/) — Windows 文件系统中的证书文件具有 Windows 权限,可能不是 644。请务必先将文件复制到 Linux 原生路径。 - systemd 未运行 — 某些较旧的 WSL2 配置没有 systemd,而
update-ca-certificates钩子可能依赖它。如果命令卡住,请改试sudo dpkg-reconfigure ca-certificates。 - Docker Desktop 集成 — 如果使用 Docker Desktop 的 WSL2 后端,容器会继承 WSL2 发行版的 CA 证书包。在 WSL2 中修复信任问题也会修复容器中的问题。
Aspire 特定注意事项
Redis TLS(Aspire 13.1.0+)
Aspire 13.1.0 默认在 Redis 上启用 TLS。如果你看到:
UntrustedRoot
出现在 Redis 连接错误中,说明系统级别不信任开发证书。请运行上述完整恢复流程。
Aspire Dashboard HTTPS
Aspire Dashboard 使用开发证书进行 HTTPS 连接。如果浏览器中出现 Dashboard 证书警告,说明证书不在浏览器的信任存储区中。开发期间可以点击警告继续访问——优先处理系统级信任(Redis、gRPC 等所需)。
ASPIRE_ALLOW_UNSECURED_TRANSPORT
设置 ASPIRE_ALLOW_UNSECURED_TRANSPORT=true 是一种权宜之计,并非修复方法。它会禁用服务间通信的 TLS,因此:
- 掩盖底层信任问题
- 与生产环境行为不一致
- 可能导致与生产环境中不同的问题
请改为修复证书信任问题。
证书生命周期
开发证书自创建之日起有效期为 1 年。证书过期时:
dotnet dev-certs https --check会报告没有有效证书- 运行完整恢复流程以生成新证书
/usr/local/share/ca-certificates/中的旧证书文件会被替换update-ca-certificates会在证书包中用新证书替换旧证书
无需重启系统。 应用会在下一次 TLS 握手时使用新的证书包(请重启应用)。
自动化:CI/CD 管道
在 Linux 运行器上的 CI/CD 中,通常很少需要开发证书(一般会使用真实证书进行测试,或在测试框架中禁用 TLS 验证)。不过,如果集成测试需要受信任的开发证书:
GitHub Actions
- name: Trust .NET Dev Certificate
run: |
dotnet dev-certs https
dotnet dev-certs https --export-path /tmp/dotnet-dev-cert.crt --format PEM --no-password
sudo cp /tmp/dotnet-dev-cert.crt /usr/local/share/ca-certificates/dotnet-dev-cert.crt
sudo chmod 644 /usr/local/share/ca-certificates/dotnet-dev-cert.crt
rm /tmp/dotnet-dev-cert.crt
sudo update-ca-certificates
Azure DevOps
- script: |
dotnet dev-certs https
dotnet dev-certs https --export-path /tmp/dotnet-dev-cert.crt --format PEM --no-password
sudo cp /tmp/dotnet-dev-cert.crt /usr/local/share/ca-certificates/dotnet-dev-cert.crt
sudo chmod 644 /usr/local/share/ca-certificates/dotnet-dev-cert.crt
rm /tmp/dotnet-dev-cert.crt
sudo update-ca-certificates
displayName: 'Trust .NET Dev Certificate'
常见问题
1. 已放置证书,但从未重新生成证书包
症状: /usr/local/share/ca-certificates/ 中存在证书文件,但 openssl verify 验证失败。
原因: 放置文件后没有运行 update-ca-certificates。
修复方法: sudo update-ca-certificates
这是最常见的错误。CA 目录是生成证书包过程的输入,而不是证书包本身。
2. 证书文件过期且权限错误
症状: 运行 update-ca-certificates 后报告添加了 0 个证书。
原因: 权限为 0600 的证书文件无法被 update-ca-certificates 读取(该命令以 root 身份运行,但可能通过会检查文件是否对所有用户可读的进程读取文件)。文件权限必须为 644。
修复方法: sudo chmod 644 /usr/local/share/ca-certificates/*.crt
3. 不同会话留下了多个证书文件
症状: update-ca-certificates 添加了多个证书,但应用仍然失败。
原因: 先前运行 dotnet dev-certs https --clean 并重新生成证书后,旧证书文件仍留在 CA 目录中。旧证书的指纹与当前开发证书不匹配。
修复方法: 删除所有 dotnet* 和 aspnet* 文件,然后重新导出当前证书。
4. 清理并重新生成后指纹不匹配
症状: openssl verify 验证通过,但 .NET 仍报告 UntrustedRoot。
原因: /usr/local/share/ca-certificates/ 中的证书是从之前的开发证书导出的。运行 dotnet dev-certs https --clean && dotnet dev-certs https 后,生成了指纹不同的新证书。系统信任的是旧证书,而不是新证书。
修复方法: 重新导出并安装:
dotnet dev-certs https --export-path /tmp/dotnet-dev-cert.crt --format PEM --no-password
sudo cp /tmp/dotnet-dev-cert.crt /usr/local/share/ca-certificates/dotnet-dev-cert.crt
sudo update-ca-certificates
5. 使用 --trust 并假定其生效
症状: dotnet dev-certs https --trust 返回退出代码 0,但实际上没有信任任何证书。
原因: 在 Linux 上,--trust 会尝试将证书添加到 OpenSSL 信任存储,但不会调用 update-ca-certificates。从 dotnet 的角度看,此操作“成功”了,但证书包并未改变。
修复方法: 在 Linux 上不要依赖 --trust。请按照此技能中的手动流程操作。
快速参考
# Generate dev cert (if missing)
dotnet dev-certs https
# Export as PEM
dotnet dev-certs https --export-path /tmp/dotnet-dev-cert.crt --format PEM --no-password
# Install to system trust (Ubuntu/Debian)
sudo cp /tmp/dotnet-dev-cert.crt /usr/local/share/ca-certificates/dotnet-dev-cert.crt
sudo chmod 644 /usr/local/share/ca-certificates/dotnet-dev-cert.crt
sudo update-ca-certificates
# Verify trust
openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt \
/usr/local/share/ca-certificates/dotnet-dev-cert.crt
# Check cert details
openssl x509 -in /usr/local/share/ca-certificates/dotnet-dev-cert.crt -noout -subject -dates -fingerprint
# Nuclear option: full clean + rebuild
dotnet dev-certs https --clean && dotnet dev-certs https
相关技能
dotnet-skills:aspire-configuration— Aspire AppHost 配置,包括 TLS 设置dotnet-skills:aspire-service-defaults— 服务默认设置,包括 HTTPS 配置