在 Traefik 中使用现有的 LetsEncrypt 证书
Use existing LetsEncrypt certificates in Traefik
是否可以在 Traefik 中使用现有的 LetsEncrypt 证书(.pem 格式)?
我已经 Traefik/Docker 设置生成 acme.json - 我可以为一组域导入我现有的证书吗?
尽管可能有人想知道为什么你实际上 want/need 这个并且任何人都会建议你反对这个,因为 traefik 很好地处理自动重新挑战,这是 acme.json
的样子:
{
"Account": {
"Email": "acme@example.com",
"Registration": {
"body": {
"status": "valid",
"contact": [
"mailto:acme@example.com"
]
},
"uri": "https://acme-v02.api.letsencrypt.org/acme/acct/12345678"
},
"PrivateKey": "ABCD...EFG="
},
"Certificates": [
{
"Domain": {
"Main": "example.com",
"SANs": null
},
"Certificate": "ABC...DEF=",
"Key": "ABC...DEF"
},
{
"Domain": {
"Main": "anotherexample.com",
"SANs": null
},
"Certificate": "ABC...DEF==",
"Key": "ABC...DEF=="
}
],
"HTTPChallenges": {}
}
现在由您编写一个导入脚本或模板解析器来遍历您的 certificates/keys 并将内容放入括号中,或者只生成您自己的 json 格式的文件。
请注意,它的格式与经典 pem 样式略有不同(即没有换行符)。
最终我找到了正确的解决方案——不使用 Traefik 的 ACME 集成,而是简单地挂载一个网络卷 (EFS),其中包含 certbot 在手动模式下颁发的证书。
为什么这是我选择的方法?因为我正在 两个 服务器(蓝色和绿色)上安装持有证书的 NFS 卷。这些服务器是 Web 服务器的实时和暂存服务器。在任何时候,一个将是 "live",另一个可以是 运行 发布候选者或以其他方式担任 "hot standby" 角色。
出于这个原因,最好分离关注点并拥有第三台服务器 运行 作为专用 "certificate manager"。这个 t2.nano 服务器基本上永远不会被触及,并且全权负责每周 运行ning certbot 一次,将证书写入由两个网络共享(以只读模式)的 NFS 挂载服务器。
通过这种方式,蓝色和绿色服务器上的 Traefik 运行 会处理其主要关注的代理网络流量,并简单地指向 certbot 颁发的证书文件。对于那些找到此页面并可以从相同解决方案中受益的人,这里是我的 traefik.toml 文件中的相关摘录:
defaultEntryPoints = ["https","http"]
[docker]
watch = true
exposedbydefault = false
swarmMode = true
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.http.redirect]
entryPoint = "https"
[entryPoints.https]
address = ":443"
[entryPoints.https.tls]
[[entryPoints.https.tls.certificates]]
certFile = "/cert.pem"
keyFile = "/privkey.pem"
这是我的 Docker 群堆栈文件中的相关部分:
version: '3.2'
volumes:
composer:
networks:
traefik:
external: true
services:
proxy:
image: traefik:latest
command: --docker --web --docker.swarmmode --logLevel=DEBUG
ports:
- "80:80"
- "443:443"
- "8080:8080"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./traefik.toml:/traefik.toml
- "./certs/live/example.com/fullchain.pem:/cert.pem"
- "./certs/live/example.com/privkey.pem:/privkey.pem"
networks:
- traefik
最后是在专用证书服务器上每周一次的 cron 运行s 命令,配置为使用 ACME v2 进行通配符证书和 Route 53 集成以进行挑战自动化:
sudo docker run -it --rm --name certbot \
-v `pwd`/certs:/etc/letsencrypt \
-v `pwd`/lib:/var/lib/letsencrypt \
-v `pwd`/log:/var/log/letsencrypt \
--env-file ./env \
certbot/dns-route53 \
certonly --dns-route53 \
--server https://acme-v02.api.letsencrypt.org/directory \
-d example.com \
-d example.net \
-d *.example.com \
-d *.example.net \
--non-interactive \
-m me@example.org \
--agree-tos
文件夹certs
是三台服务器共享的NFS卷
我只想补充一点,我在需要使用 HAProxy 的同时找到了另一种方法:
- 运行 一个 traefik 仅用于 HAProxy 后面的端口 81 上的 acme
acl acme path_beg -i /.well-known/acme-challenge/
use_backend acme if acme
- 有一个小型网络服务器提供 acme.json(即 shell2http)
- 有一个 cronjob(我使用 gitlab ci)下载 acme.json 并提取证书 (https://github.com/containous/traefik/blob/821ad31cf6e7721ba231164ab468ee554983560f/contrib/scripts/dumpcerts.sh)
- 将证书附加到 traefik.toml 模板
- 构建一个 docker 映像并推送到私有注册表
- 运行 这个私有 traefik 实例在 80/443 上以只读模式在 HAProxy 后面的任何后端服务器上作为主 traefik
- 编写一个文件观察器脚本,当 acme.json 更改并触发 dumpcert-script
时重新启动所有 ro-traefiks
正在完成 sgohl 回复:
重要:确保私钥长度为 4096 位。 2048 位 NOT 工作,traefik 将尝试向 Letsencrypt 请求新证书。
- 确定您的(在此示例中为 certbot)证书。示例:
/etc/letsencrypt/live
├── example.com
│ ├── cert.pem -> ../../archive/example.com/cert6.pem
│ ├── chain.pem -> ../../archive/example.com/chain6.pem
│ ├── fullchain.pem -> ../../archive/example.com/fullchain6.pem
│ ├── privkey.pem -> ../../archive/example.com/privkey6.pem
│ └── README
- 检查私钥是否为 4096 位长:
openssl rsa -text -in privkey.pem | grep bit
预期结果类似于:
writing RSA key
RSA Private-Key: (4096 bit, 2 primes)
- 生成包含所需证书的字符串。
3.1。证书
_IN=/etc/letsencrypt/live/example.com/fullchain.pem
_OUT=~/traefik_certificate
cat $_IN | base64 | tr '\n' ' ' | sed --expression='s/\ //g' > $_OUT
3.2。私钥
_IN=/etc/letsencrypt/live/example.com/privkey.pem
_OUT=~/traefik_key
cat $_IN | base64 | tr '\n' ' ' | sed --expression='s/\ //g' > $_OUT
- 准备包含以上字符串的代码片段:
...
"Certificates": [
{
"domain": {
"main": "example.com"
},
"certificate": "CONTENT_OF_traefik_certificate",
"key": "CONTENT_OF_certificate",
"Store": "default"
},
...
- 将上面的代码片段放在 traefik 的
acme.json
文件中的正确位置('Certificates' JSON 键下方):
vim /path/to/acme.json
无需重启 traefik 容器即可选择新证书。
是否可以在 Traefik 中使用现有的 LetsEncrypt 证书(.pem 格式)?
我已经 Traefik/Docker 设置生成 acme.json - 我可以为一组域导入我现有的证书吗?
尽管可能有人想知道为什么你实际上 want/need 这个并且任何人都会建议你反对这个,因为 traefik 很好地处理自动重新挑战,这是 acme.json
的样子:
{
"Account": {
"Email": "acme@example.com",
"Registration": {
"body": {
"status": "valid",
"contact": [
"mailto:acme@example.com"
]
},
"uri": "https://acme-v02.api.letsencrypt.org/acme/acct/12345678"
},
"PrivateKey": "ABCD...EFG="
},
"Certificates": [
{
"Domain": {
"Main": "example.com",
"SANs": null
},
"Certificate": "ABC...DEF=",
"Key": "ABC...DEF"
},
{
"Domain": {
"Main": "anotherexample.com",
"SANs": null
},
"Certificate": "ABC...DEF==",
"Key": "ABC...DEF=="
}
],
"HTTPChallenges": {}
}
现在由您编写一个导入脚本或模板解析器来遍历您的 certificates/keys 并将内容放入括号中,或者只生成您自己的 json 格式的文件。
请注意,它的格式与经典 pem 样式略有不同(即没有换行符)。
最终我找到了正确的解决方案——不使用 Traefik 的 ACME 集成,而是简单地挂载一个网络卷 (EFS),其中包含 certbot 在手动模式下颁发的证书。
为什么这是我选择的方法?因为我正在 两个 服务器(蓝色和绿色)上安装持有证书的 NFS 卷。这些服务器是 Web 服务器的实时和暂存服务器。在任何时候,一个将是 "live",另一个可以是 运行 发布候选者或以其他方式担任 "hot standby" 角色。
出于这个原因,最好分离关注点并拥有第三台服务器 运行 作为专用 "certificate manager"。这个 t2.nano 服务器基本上永远不会被触及,并且全权负责每周 运行ning certbot 一次,将证书写入由两个网络共享(以只读模式)的 NFS 挂载服务器。
通过这种方式,蓝色和绿色服务器上的 Traefik 运行 会处理其主要关注的代理网络流量,并简单地指向 certbot 颁发的证书文件。对于那些找到此页面并可以从相同解决方案中受益的人,这里是我的 traefik.toml 文件中的相关摘录:
defaultEntryPoints = ["https","http"]
[docker]
watch = true
exposedbydefault = false
swarmMode = true
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.http.redirect]
entryPoint = "https"
[entryPoints.https]
address = ":443"
[entryPoints.https.tls]
[[entryPoints.https.tls.certificates]]
certFile = "/cert.pem"
keyFile = "/privkey.pem"
这是我的 Docker 群堆栈文件中的相关部分:
version: '3.2'
volumes:
composer:
networks:
traefik:
external: true
services:
proxy:
image: traefik:latest
command: --docker --web --docker.swarmmode --logLevel=DEBUG
ports:
- "80:80"
- "443:443"
- "8080:8080"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./traefik.toml:/traefik.toml
- "./certs/live/example.com/fullchain.pem:/cert.pem"
- "./certs/live/example.com/privkey.pem:/privkey.pem"
networks:
- traefik
最后是在专用证书服务器上每周一次的 cron 运行s 命令,配置为使用 ACME v2 进行通配符证书和 Route 53 集成以进行挑战自动化:
sudo docker run -it --rm --name certbot \
-v `pwd`/certs:/etc/letsencrypt \
-v `pwd`/lib:/var/lib/letsencrypt \
-v `pwd`/log:/var/log/letsencrypt \
--env-file ./env \
certbot/dns-route53 \
certonly --dns-route53 \
--server https://acme-v02.api.letsencrypt.org/directory \
-d example.com \
-d example.net \
-d *.example.com \
-d *.example.net \
--non-interactive \
-m me@example.org \
--agree-tos
文件夹certs
是三台服务器共享的NFS卷
我只想补充一点,我在需要使用 HAProxy 的同时找到了另一种方法:
- 运行 一个 traefik 仅用于 HAProxy 后面的端口 81 上的 acme
acl acme path_beg -i /.well-known/acme-challenge/
use_backend acme if acme
- 有一个小型网络服务器提供 acme.json(即 shell2http)
- 有一个 cronjob(我使用 gitlab ci)下载 acme.json 并提取证书 (https://github.com/containous/traefik/blob/821ad31cf6e7721ba231164ab468ee554983560f/contrib/scripts/dumpcerts.sh)
- 将证书附加到 traefik.toml 模板
- 构建一个 docker 映像并推送到私有注册表
- 运行 这个私有 traefik 实例在 80/443 上以只读模式在 HAProxy 后面的任何后端服务器上作为主 traefik
- 编写一个文件观察器脚本,当 acme.json 更改并触发 dumpcert-script 时重新启动所有 ro-traefiks
正在完成 sgohl 回复:
重要:确保私钥长度为 4096 位。 2048 位 NOT 工作,traefik 将尝试向 Letsencrypt 请求新证书。
- 确定您的(在此示例中为 certbot)证书。示例:
/etc/letsencrypt/live
├── example.com
│ ├── cert.pem -> ../../archive/example.com/cert6.pem
│ ├── chain.pem -> ../../archive/example.com/chain6.pem
│ ├── fullchain.pem -> ../../archive/example.com/fullchain6.pem
│ ├── privkey.pem -> ../../archive/example.com/privkey6.pem
│ └── README
- 检查私钥是否为 4096 位长:
openssl rsa -text -in privkey.pem | grep bit
预期结果类似于:
writing RSA key
RSA Private-Key: (4096 bit, 2 primes)
- 生成包含所需证书的字符串。
3.1。证书
_IN=/etc/letsencrypt/live/example.com/fullchain.pem
_OUT=~/traefik_certificate
cat $_IN | base64 | tr '\n' ' ' | sed --expression='s/\ //g' > $_OUT
3.2。私钥
_IN=/etc/letsencrypt/live/example.com/privkey.pem
_OUT=~/traefik_key
cat $_IN | base64 | tr '\n' ' ' | sed --expression='s/\ //g' > $_OUT
- 准备包含以上字符串的代码片段:
...
"Certificates": [
{
"domain": {
"main": "example.com"
},
"certificate": "CONTENT_OF_traefik_certificate",
"key": "CONTENT_OF_certificate",
"Store": "default"
},
...
- 将上面的代码片段放在 traefik 的
acme.json
文件中的正确位置('Certificates' JSON 键下方):
vim /path/to/acme.json
无需重启 traefik 容器即可选择新证书。