AbpVnext 阿里云ssl证书多个生产环境自动更新
一个站点对应多个域名,所以要有多个证书
打开Host下面Program.cs,加入代码,如下图
Kestrel 的证书支持热更新机制,新的证书文件覆盖后会自动更新
//下面代码作用是证书文件更新后,自动更新证书,不需要重启应用builder.WebHost.ConfigureKestrel(serverOptions =>{serverOptions.ConfigureHttpsDefaults(httpsOptions =>{httpsOptions.ServerCertificateSelector = (connectionContext, name) =>{return name?.ToLower() switch{"域名1.com" or "www.域名1.com" => new X509Certificate2("证书1.pfx", "密码"),"域名2.net" or "www.域名2.net" => new X509Certificate2("证书2.pfx", "密码"),_ => throw new NotSupportedException($"No certificate available for {name}")};};});});
如果你只有一个域名,代码如下:
httpsOptions.ServerCertificateSelector = (ctx, host) =>{// 可用代码动态读取最新的证书return new X509Certificate2("/path/to/your/cert.pfx", "your_cert_password");};
自动更新算法
1、程序启动时判断证书过期,程序启动后每天定时检查证书过期
2、过期后从阿里云自动下载文件覆盖本地文件即可。
自动下载证书参考我上次的文章,参考地址如下
net9阿里云自动申请ssl证书,下载证书pfx格式-CSDN博客
判断证书是否过期代码
var cert = new System.Security.Cryptography.X509Certificates.X509Certificate2("证书文件", "密码");DateTime expirationDate = DateTime.Parse(cert.GetExpirationDateString());if (expirationDate.AddDays(-1).Date <= DateTime.Now.Date){//下载证书}
多个证书过期判断
// 搜索所有.pfx文件string[] pfxFiles = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "*.pfx", SearchOption.AllDirectories);foreach (var filePath in pfxFiles){var cert = new System.Security.Cryptography.X509Certificates.X509Certificate2(filePath, "密码");DateTime expirationDate = DateTime.Parse(cert.GetExpirationDateString());if (expirationDate.AddDays(-1).Date <= DateTime.Now.Date){//下载证书}}
完整的代码如下:
接口IOpenSSLAppService,目的是为了兼容其它云平台域名证书
/// <summary>
/// 检查证书是否过期
/// </summary>
/// <returns></returns>
public async Task IsCertificateExpiredAsync()
{// 搜索所有.pfx文件string[] pfxFiles = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "*.pfx", SearchOption.AllDirectories);string password = _configuration["Aliyun:password"];foreach (var filePath in pfxFiles){var cert = new System.Security.Cryptography.X509Certificates.X509Certificate2(filePath, password);DateTime expirationDate = DateTime.Parse(cert.GetExpirationDateString());if (expirationDate.AddDays(-1).Date <= DateTime.Now.Date){//更新证书await GetPfxAsync(filePath.GetFileNameWithoutExtension(), password);}}
}
/// <summary>
/// 获取域名证书
/// </summary>
/// <param name="domain"></param>
/// <param name="password"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public async Task GetPfxAsync(string domain,string password)
{var akConfig = new Aliyun.Credentials.Models.Config{Type = "access_key",AccessKeyId = _configuration["Aliyun:accessKeyId"],AccessKeySecret = _configuration["Aliyun:secret"]};var akCredential = new Aliyun.Credentials.Client(akConfig);AlibabaCloud.OpenApiClient.Models.Config config = new AlibabaCloud.OpenApiClient.Models.Config{Credential = akCredential,RegionId = _configuration["Aliyun:regionId"]};AlibabaCloud.SDK.Cas20200407.Client client = new AlibabaCloud.SDK.Cas20200407.Client(config);try{var request = new CreateCertificateRequestRequest{Username = _configuration["Aliyun:mail"],Phone = _configuration["Aliyun:phone"],Email = _configuration["Aliyun:mail"],Domain = domain,ValidateType = "DNS"};var runtime = new RuntimeOptions();var certificateResponse = await client.CreateCertificateRequestAsync(request);DescribeCertificateStateResponse certificateStateResponse;if (certificateResponse.StatusCode == 200 && certificateResponse.Body != null){var orderId = certificateResponse.Body.OrderId;certificateStateResponse = await client.DescribeCertificateStateAsync(new DescribeCertificateStateRequest { OrderId = orderId });while (certificateStateResponse.Body.PrivateKey == null){Thread.Sleep(30000);//休息30秒certificateStateResponse = await client.DescribeCertificateStateAsync(new DescribeCertificateStateRequest { OrderId = orderId });}if (certificateStateResponse.Body.PrivateKey != null){//保存证书string certPem = certificateStateResponse.Body.Certificate; // 公钥证书 PEM 字符串string keyPem = certificateStateResponse.Body.PrivateKey; // 私钥 PEM 字符串 CryptorHelper.PemToPfx(certPem, keyPem, $"{domain}.pfx", password);}}}catch (TeaException ex){throw new Exception($"阿里云API错误: {ex.Message}", ex);}
}
添加程序启动更新代码
加入到hangfire定时任务,每天1点检查,定时更新