Docker环境UI与API通信遇RemoteCertificateNameMismatch证书错误求助
解决Docker环境下UI与API通信的SSL证书验证错误
你遇到的RemoteCertificateNameMismatch和RemoteCertificateChainErrors错误,分别是证书域名不匹配和自签名证书未被信任导致的,以下是针对性的解决方案:
一、修正证书域名匹配问题
API证书的CN(通用名称)是api.example.com,但UI调用API时用的是host.docker.internal:9000,域名不一致触发名称验证失败。需要生成包含host.docker.internal的证书,同时添加SAN(主题备用名称)(现代HTTPS验证要求必须包含SAN)。
修改证书生成Dockerfile(Dockerfile.cert_generator)
FROM alpine:latest RUN apk --no-cache add openssl # Create certificates directory RUN mkdir /certificates # Generate API certificate with SAN matching host.docker.internal RUN openssl req -newkey rsa:2048 -nodes -keyout /certificates/api.key -x509 -days 365 -out /certificates/api.crt -subj "/C=GB/ST=London/L=London/O=Dummy Corp/OU=Engineering/CN=host.docker.internal" \ -addext "subjectAltName=DNS:host.docker.internal,DNS:api.example.com" \ && openssl pkcs12 -export -out /certificates/api.pfx -inkey /certificates/api.key -in /certificates/api.crt -password pass: \ && if [ -f "/certificates/api.pfx" ]; then echo "API Certificate Generated Successfully"; else echo "Failed to generate API Certificate"; fi # Generate UI certificate (可选添加host.docker.internal到SAN) RUN openssl req -newkey rsa:2048 -nodes -keyout /certificates/ui.key -x509 -days 365 -out /certificates/ui.crt -subj "/C=GB/ST=London/L=London/O=Dummy Corp/OU=Engineering/CN=ui.example.com" \ -addext "subjectAltName=DNS:ui.example.com,DNS:host.docker.internal" \ && openssl pkcs12 -export -out /certificates/ui.pfx -inkey /certificates/ui.key -in /certificates/ui.crt -password pass: \ && if [ -f "/certificates/ui.pfx" ]; then echo "UI Certificate Generated Successfully"; else echo "Failed to generate UI Certificate"; fi
注:删除原Dockerfile中复制到
/host_certificates的步骤,因为通过volume挂载./certificates:/certificates已经将证书同步到主机目录。
二、挂载证书到API和UI容器
修改Docker Compose配置,将生成的证书挂载到容器内,并修正Kestrel的证书路径:
version: '3.4' services: integrationtestingbase: image: ${DOCKER_REGISTRY-}api build: context: . dockerfile: api/Dockerfile ports: - "9000:443" - "9001:80" volumes: - ./certificates:/app/certificates # 挂载证书目录 environment: - ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_URLS=https://+:443;http://+:80 - Kestrel__Certificates__Default__Path=/app/certificates/api.pfx # 修正证书路径 - Kestrel__Certificates__Default__Password= integrationtestingwebappbase: image: ${DOCKER_REGISTRY-}ui build: context: . dockerfile: ui/Dockerfile ports: - "9002:443" - "9003:80" volumes: - ./certificates:/app/certificates # 挂载证书目录 environment: - ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_URLS=https://+:443;http://+:80 - Kestrel__Certificates__Default__Path=/app/certificates/ui.pfx # 修正证书路径 - Kestrel__Certificates__Default__Password= sqlserver: image: mcr.microsoft.com/mssql/server:latest environment: MSSQL_SA_PASSWORD: "Password123!" ACCEPT_EULA: "Y" ports: - "1433:1433" volumes: - ./path/to/appsettings.json:/app/appsettings.json certificate_generation: build: context: . dockerfile: Dockerfile.cert_generator volumes: - ./certificates:/certificates
三、配置UI的HttpClient信任自签名证书
原代码中重新实例化HttpClient会覆盖依赖注入的配置,且未处理证书信任问题。修改Razor页面代码,通过IHttpClientFactory配置信任自定义证书:
1. 在UI项目的Program.cs中配置HttpClient
var builder = WebApplication.CreateBuilder(args); // 添加HttpClient并配置证书验证 builder.Services.AddHttpClient("ApiClient", client => { client.BaseAddress = new Uri("https://host.docker.internal:9000/"); }) .ConfigurePrimaryHttpMessageHandler(() => { var handler = new HttpClientHandler(); // 加载API的自签名证书 var certPath = Path.Combine(builder.Environment.ContentRootPath, "certificates", "api.crt"); var trustedCert = new X509Certificate2(certPath); // 自定义证书验证逻辑 handler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => { // 验证证书是否为我们生成的可信证书 if (cert.Thumbprint == trustedCert.Thumbprint) return true; // 开发环境下可临时允许所有证书(生产环境禁用) // return sslPolicyErrors == SslPolicyErrors.None; return false; }; return handler; }); // 其他配置... builder.Services.AddRazorPages(); var app = builder.Build(); // 中间件配置... app.Run();
2. 修改Razor页面的IndexModel
namespace IntegrationTestingWebAppBase.Pages { public class IndexModel : PageModel { public List<Tenant> Tenants { get; private set; } private readonly HttpClient _httpClient; private readonly ILogger<IndexModel> _logger; // 注入IHttpClientFactory而非直接注入HttpClient public IndexModel(ILogger<IndexModel> logger, IHttpClientFactory httpClientFactory) { _logger = logger; _httpClient = httpClientFactory.CreateClient("ApiClient"); } public async Task OnGetAsync() { try { var response = await _httpClient.GetAsync("/api/tenant/getall"); if (response.IsSuccessStatusCode) { Tenants = await response.Content.ReadFromJsonAsync<List<Tenant>>(); } else { // 处理请求失败逻辑 } } catch (HttpRequestException ex) { if (ex.InnerException is System.Security.Authentication.AuthenticationException authEx) { _logger.LogError("SSL/TLS验证错误: {Message}", authEx.Message); } else { _logger.LogError("HTTP请求错误: {Message}", ex.Message); } } catch (Exception ex) { _logger.LogError("未知错误: {Message}", ex.Message); } } } }
四、运行步骤
- 先生成证书:
docker-compose up --build certificate_generation - 启动所有服务:
docker-compose up --build
这样就能解决证书名称不匹配和证书链信任问题,实现UI与API的正常HTTPS通信。
内容的提问来源于stack exchange,提问作者Paul Daniels
相关产品推荐
相关产品推荐

