C#更新Nginx SSL证书
现在免费的SSL证书三个月就到期了,为了方便写了一个更新SSL证书的程序,把程序和xxx_nginx.zip的证书放在同一目录下,先解压ssl文件,然后上传到服务器,最后复制到nginx的路径下。一台服务器有多个ssl证书,最好ssl有效期控制在同一天这样方便更新,只需要将多个ssl压缩包和程序放在一起即可。
代码如下:
Install-Package DotNetZip -Version 1.16.0
Install-Package SSH.NET -Version 2024.2.0
using Ionic.Zip;
using Renci.SshNet;
using System;
using System.IO;
class Program
{
static void Main()
{
Console.WriteLine("即将启动SSL证书更新,按任意键继续。");
Console.ReadKey();
string currentDir = Directory.GetCurrentDirectory();
var result = UnzipFile(currentDir);
if (!result)
{
Console.WriteLine("文件提取失败");
Console.WriteLine("按任意键退出");
Console.ReadKey();
return;
}
Console.WriteLine("文件提取完成");
Console.WriteLine("按任意键继续");
Console.ReadKey();
SSHClient(currentDir);
Console.WriteLine("按任意键退出任务");
Console.ReadKey();
}
public static bool UnzipFile(string currentDir)
{
var files = Directory.GetFiles(currentDir, "*nginx.zip");
if (files.Length == 0)
{
return false;
}
foreach (string zipFile in files)
{
try
{
using (ZipFile zip = ZipFile.Read(zipFile, new ReadOptions { Encoding = System.Text.Encoding.Default }))
{
foreach (ZipEntry entry in zip)
{
if (entry.IsDirectory) continue;
string ext = Path.GetExtension(entry.FileName).ToLower();
if (ext == ".key" || ext == ".pem")//根据自己要求,也可以把所有文件都解压出啦
{
entry.Extract(currentDir, ExtractExistingFileAction.OverwriteSilently);
}
}
}
var path = Path.Combine(currentDir, Path.GetFileNameWithoutExtension(zipFile));
foreach (string file in Directory.GetFiles(path))
{
string destFile = Path.Combine(currentDir, Path.GetFileName(file));
File.Copy(file, destFile, true); // true表示如果文件已存在则覆盖
}
Directory.Delete(path, true);
}
catch (Exception ex)
{
Console.WriteLine($"解压失败:{zipFile}\n错误信息:{ex.Message}");
return false;
}
}
return true;
}
public static void SSHClient(string currentDir)
{
string host = "host"; // 服务器地址
string username = "username"; // 登录用户名
string password = "password"; // 登录密码
string remoteFilePath = "/home/username/ssl/"; // 远程服务器上的目标文件路径
string sudoPassword = "sudoPassword"; // sudo 密码
try
{
// 上传文件到服务器
using (var sftp = new SftpClient(host, username, password))
{
sftp.Connect();
Console.WriteLine("成功连接到FTP服务器");
var allFiles = Directory.GetFiles(currentDir)//根据自己要求过滤文件
.Where(file => file.EndsWith(".key", StringComparison.OrdinalIgnoreCase) ||
file.EndsWith(".pem", StringComparison.OrdinalIgnoreCase));
foreach (var item in allFiles)
{
using (var fileStream = File.OpenRead(item))
{
sftp.UploadFile(fileStream, $"{remoteFilePath + Path.GetFileName(item)}");
Console.WriteLine($"{Path.GetFileName(item)}文件上传成功!");
}
}
sftp.Disconnect();
Console.WriteLine("FTP服务器断开连接");
Console.WriteLine("按任意键继续");
Console.ReadKey();
}
// 执行sudo命令
using (var sshClient = new SshClient(host, username, password))
{
sshClient.Connect();
Console.WriteLine("成功连接到SSH服务器");
// 通过 SSH 执行需要 sudo 的命令
string sudoCommand = "echo " + sudoPassword + " | sudo -S /home/username/update_ssl.sh"; // 这里用 echo 将密码传递给 sudo
var command = sshClient.RunCommand(sudoCommand);
if (!string.IsNullOrEmpty(command.Error))
{
Console.WriteLine("命令执行消息:"+command.Error);
}
Console.WriteLine("命令执行结果: " + command.Result);
sshClient.Disconnect();
Console.WriteLine("SSH服务器断开连接");
}
}
catch (Exception ex)
{
Console.WriteLine("错误: " + ex.Message);
}
}
}
update_ssl.sh 代码如下
#!/bin/bash
# 复制证书文件(需root权限)
sudo cp /home/username/ssl/* /etc/nginx/conf.d/ssl/
# 检查配置语法并重载
if sudo nginx -t; then
sudo nginx -s reload
echo "SSL证书更新成功!"
else
echo "Nginx配置检查失败,请排查错误!"
exit 1
fi
配置免密sudo
echo sudoPassword | sudo -S ./update_ssl.sh #替代安全方案
#在/etc/sudoers中添加NOPASSWD规则,允许特定命令无需密码:
username ALL=(ALL) NOPASSWD: /home/username/update_ssl.sh