SSL 证书部署工具,支持 Nginx、Apache,支持 Docker 容器。
# 安装最新稳定版(参数传域名,脚本自动拼接 https://<host>/sslctl)
curl -fsSL https://release.example.com/sslctl/install.sh | sudo bash -s -- release.example.com
# 安装测试版
curl -fsSL https://release.example.com/sslctl/install.sh | sudo bash -s -- release.example.com --dev
# 安装指定版本
curl -fsSL https://release.example.com/sslctl/install.sh | sudo bash -s -- release.example.com --version 1.0.0
# 强制重新安装
curl -fsSL https://release.example.com/sslctl/install.sh | sudo bash -s -- release.example.com --forceWindows (PowerShell 管理员):
# 安装最新稳定版(一行命令)
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; (New-Object Net.WebClient).DownloadFile("https://release.example.com/sslctl/install.ps1", "$pwd\install.ps1"); powershell -ExecutionPolicy Bypass -File install.ps1
# 或者分步执行
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
(New-Object Net.WebClient).DownloadFile("https://release.example.com/sslctl/install.ps1", "$pwd\install.ps1")
powershell -ExecutionPolicy Bypass -File install.ps1 -ReleaseHost release.example.com
# 更多参数
powershell -ExecutionPolicy Bypass -File install.ps1 -ReleaseHost release.example.com -Dev # 安装测试版
powershell -ExecutionPolicy Bypass -File install.ps1 -ReleaseHost release.example.com -Version 1.0.0 # 安装指定版本
powershell -ExecutionPolicy Bypass -File install.ps1 -ReleaseHost release.example.com -Force # 强制重新安装注意:
- 第一行
SecurityProtocol用于启用 TLS 1.2(PowerShell 5.1 默认未启用),Server 2019+ 可省略- 使用
WebClient.DownloadFile而非irm -OutFile,避免 PowerShell 5.1 编码转换导致中文乱码-ExecutionPolicy Bypass绕过脚本签名限制,仅影响当前执行- Windows Server 2012 R2 等老系统若 PowerShell 中看到空白或中文乱码:这是 PowerShell 默认 Raster Font(点阵字体)无法渲染 CJK 字符导致的,改字体即可修复——右键 PowerShell 窗口左上角图标 → 默认值 → 字体 → 选 Consolas 或 Lucida Console,关闭后重新打开窗口。cmd.exe 一般不受影响
手动安装: 从 Releases 下载解压,重命名为 sslctl。
sslctl setup --url https://api.example.com --token your-token --order 12345自动完成:
- 检测 Web 服务器(Nginx/Apache)
- 获取证书信息并匹配站点
- 为未启用 SSL 的站点安装 HTTPS 配置(需确认,备份原配置,失败自动回滚)
- 部署证书到匹配的站点
- 安装守护服务(自动续签)
选项:
--local-key: 使用本机提交--key <path>: 私钥文件路径(隐含--local-key)--file-validation: 启用文件验证(隐含--local-key)--webroot <path>: 文件验证的 Web 根目录(隐含--file-validation)--yes: 跳过确认提示--no-service: 不安装守护服务
sslctl scan # 扫描所有站点
sslctl scan --ssl-only # 仅扫描 SSL 站点# 部署本地证书文件到站点
sslctl deploy local --cert cert.pem --key key.pem --site example.com
# 带 CA 证书链部署(Apache 配置了 SSLCertificateChainFile 时需要)
sslctl deploy local --cert cert.pem --key key.pem --ca chain.pem --site apache-site.com选项:
--cert: 证书文件路径(必需)--key: 私钥文件路径(必需)--ca: CA 证书链文件路径(Apache 配置了证书链路径时必需)--site: 目标站点名称(必需,需先运行sslctl scan)
站点信息优先从 config.json 获取,回退到 scan-result.json。
sslctl rollback --site example.com # 回滚到最新备份
sslctl rollback --site example.com --list # 查看备份列表
sslctl rollback --site example.com --version 20240101-120000 # 回滚到指定版本回滚前会自动备份当前文件,包含符号链接防护。
其他命令:
sslctl deploy --cert example.com-12345 # 部署指定证书
sslctl deploy --cert example.com-12345 --site example.com # 绑定站点并部署
sslctl deploy --all # 部署所有证书
sslctl status # 查看服务状态(含证书过期详情)
sslctl upgrade # 升级到最新版本
sslctl upgrade --check # 检查更新
sslctl service repair # 修复 systemd 服务
sslctl --debug scan # 调试模式
sslctl uninstall # 卸载(交互确认是否清理配置)| 平台 | Nginx | Apache | 服务管理 |
|---|---|---|---|
| Linux (systemd) | ✅ | ✅ | systemd |
| Linux (OpenRC) | ✅ | ✅ | OpenRC |
| Linux (SysVinit) | ✅ | ✅ | SysVinit |
| Windows | ✅ | ✅ | Windows Service |
CI 覆盖 linux/amd64、linux/arm64、windows/amd64 三平台交叉编译验证。
支持 Docker 容器 Nginx(挂载卷/docker cp 双模式),自动检测本地或容器环境。
# 启用调试模式
sslctl --debug deploy --site example.com- 详细日志输出(请求/响应、配置解析、文件操作)
- 日志写入文件:
/opt/sslctl/logs/debug/
/opt/sslctl/
├── config.json # 统一配置文件
├── certs/ # 证书存储
│ └── {server_name}/
│ ├── cert.pem
│ └── key.pem
├── pending-keys/ # 待确认私钥(本机提交)
├── logs/ # 日志文件
├── backup/ # 证书备份
└── scan-result.json # 扫描结果缓存
- HTTPS 强制:远程 API 必须使用 HTTPS(仅 localhost 允许 HTTP)
- SSRF 防护:阻止访问内网 IP(10/172.16/192.168)、未指定地址(0.0.0.0/::)和云元数据地址(169.254.169.254)
- DNS Rebinding 防护:自定义 DialContext 在 TCP 连接时二次校验目标 IP
- 命令白名单 + 超时:统一的 executor 包,只允许预定义命令,默认 30 秒超时,支持 Context 取消
- 日志脱敏:自动过滤私钥、Bearer Token、Basic Auth、JSON 敏感字段、URL 参数;错误消息使用相对路径
- 并发安全:配置读取返回深拷贝,mtime + SHA256 哈希检测外部修改自动重载,防止并发修改污染
- 配置保存安全:拒绝写入符号链接目标,防止任意文件覆盖
- 路径验证:Docker 容器路径参数严格验证,防止命令注入;挂载路径精确匹配防止误匹配
- 备份 TOCTOU 保护:使用文件哈希校验检测并发修改,确保备份一致性;恢复时内部备份跳过清理,防止目标备份被删除;备份源文件符号链接检查,拒绝备份符号链接目标;
siteName/timestamp路径穿越防护 - 扫描防护:Nginx/Apache/Docker 扫描器文件数量限制(1000)+ 深度限制(100)+ 文件大小限制(10MB),防止恶意配置耗尽资源
- 升级安全:gzip 解压大小限制,防止 gzip 炸弹攻击;Ed25519 数字签名验证(按文件名索引签名,密钥环支持多公钥 + key ID,空密钥环拒绝验证,已配置公钥时拒绝未签名版本防止降级攻击),防止供应链攻击;先停服务再替换二进制,失败时恢复服务;Windows 上 rename 策略替换运行中 exe;安装时符号链接防护;临时文件保持 0600 仅在最终路径设置 0755;通道白名单防止路径遍历;密钥不匹配时提示用 install.sh 重装
- 临时目录安全:临时目录权限设置为 0700
- 日志目录安全:日志目录权限设置为 0700
- 配置文件锁:文件锁在操作前获取,确保原子性和一致性
- 部署回滚:部署失败自动回滚到备份(通过抽象层接口),回滚失败时提供手动恢复命令
- 私钥保护:本机提交下,新私钥先保存到临时位置,签发成功后再替换;所有私钥写入统一使用 AtomicWrite
- SELinux 兼容:部署后自动恢复文件安全上下文(restorecon),非 SELinux 环境静默跳过
- IDN/Punycode 支持:域名匹配器自动转换国际化域名
- 证书过期告警:守护进程周期检查证书过期时间,7 天/13 天阈值输出告警日志
- 环境变量:支持通过环境变量配置敏感信息,避免明文存储
| 变量 | 说明 |
|---|---|
SSLCTL_RELEASE_URL |
Release URL(安装脚本使用,完整 URL 含 https://) |
SSLCTL_API_TOKEN |
API Token(覆盖所有证书的 API 配置) |
SSLCTL_API_URL |
API URL(覆盖所有证书的 API 配置) |
SSLCTL_LOG_FORMAT |
日志格式:json 启用 JSON 输出 |
使用示例:
export SSLCTL_API_TOKEN="your-secret-token"
sslctl statusconfig.json:
{
"release_url": "https://release.example.com/sslctl",
"schedule": {
"renew_before_days": 13,
"renew_mode": "pull"
},
"certificates": [
{
"cert_name": "example.com-12345",
"order_id": 12345,
"enabled": true,
"domains": ["*.example.com", "example.com"],
"api": {
"url": "https://api.example.com",
"token": "your-deploy-token"
},
"renew_mode": "pull",
"bindings": [
{
"server_name": "www.example.com",
"server_type": "nginx",
"enabled": true,
"paths": {
"certificate": "/opt/sslctl/certs/www.example.com/cert.pem",
"private_key": "/opt/sslctl/certs/www.example.com/key.pem"
}
}
]
}
]
}注意:API 配置在证书级别,每个证书可以使用不同的 API 来源。
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
renew_before_days |
int | 13 | 提前续期天数,最大 13,0 使用默认值 |
renew_mode |
string | pull |
全局续签模式,证书级别可覆盖 |
保存配置时自动创建的文件锁(flock),防止多个 sslctl 进程同时写入 config.json 导致数据损坏。无需手动管理。
两种模式统一:renew_before_days 最大 13 天,默认 13 天。
| 模式 | 说明 | 默认值 |
|---|---|---|
local |
本机提交,本地生成私钥和 CSR | 13 天 |
pull |
自动签发,从服务端拉取已签发证书 | 13 天 |
- 本机提交:由本地控制私钥,通过 POST 部署接口提交本地生成的 CSR
- 自动签发:查询已签发的证书直接部署
- 定时检查:每天一次,随机选择明天 09:00
23:59 的时间点执行;多证书续签间随机延迟 3090 秒 - 已过期证书不再触发续签
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /api/deploy?order_id=xxx |
按订单 ID 查询(推荐) |
| GET | /api/deploy?domain=xxx |
按域名查询(首次获取 order_id) |
| POST | /api/deploy |
更新/续费证书(需要 order_id) |
| POST | /api/deploy/callback |
部署结果回调 |
认证方式:Authorization: Bearer {deploy_token}
sslctl scan # 自动检测本地或 Docker
sslctl deploy --site example.com # 根据配置选择部署方式Docker 站点配置添加 docker 字段:
{
"docker": {
"enabled": true,
"compose_file": "/opt/app/docker-compose.yml",
"service_name": "nginx",
"deploy_mode": "auto"
}
}部署模式:volume(挂载卷)、copy(docker cp)、auto(自动检测)
# 运行单元测试
go test -v ./...
# 运行测试并查看覆盖率
go test -coverprofile=coverage.out ./...
go tool cover -func=coverage.out | grep total
# Linux 发行版服务管理测试(需要 Docker)
bash build/test-linux.sh# 运行全部 E2E 测试(构建 + 全矩阵)
bash docker/test/scripts/run-tests.sh
# 指定发行版和服务器
bash docker/test/scripts/run-tests.sh --distro ubuntu --server nginx
# 指定测试文件(不含 .bats 后缀)
bash docker/test/scripts/run-tests.sh --test scan
# Docker-in-Docker 测试
bash docker/test/scripts/run-tests.sh --dind
# 跳过构建(已构建过镜像)
bash docker/test/scripts/run-tests.sh --no-build测试矩阵:Nginx/Apache × Ubuntu/Debian/Alpine/Rocky + DinD,使用 Mock API 离线运行。
测试用例:setup、deploy、deploy-local、scan、status、rollback、daemon、upgrade、uninstall、docker-scan(共 10 个 bats 文件,docker-scan 在 DinD 容器中运行,uninstall 自动排最后执行)。
MIT