Docker (docker-compose) 应用程序容器中的 LetsEncrypt 无法正常工作
LetsEncrypt in a Docker (docker-compose) app container not working
我正在为 rails 应用程序使用 docker-compose 来拥有应用程序和数据库容器。为了测试某些应用程序功能,我需要 SSL...所以我将使用 LetsEncrypt 与自签名。
应用使用nginx,服务器ubuntu 14.04 lts,以phusion passenger docker镜像为基础镜像(轻量级debian)
通常使用 LetsEncrypt,我 运行 通常 ./certbot-auto certonly --webroot -w /path/to/app/public -d www.example.com
我的服务器 运行s nginx(将应用程序传递给容器的代理),所以我跳进容器到 运行 certbot 命令没有问题。
但是,当我尝试转到 https://test-app.example.com 时,它不起作用。我不知道为什么。
现场错误(Chrome):
This site can’t be reached
The connection was reset.
Curl 给出了更好的错误:
curl: (35) Unknown SSL protocol error in connection to test-app.example.com
服务器 nginx app.conf
upstream test_app { server localhost:4200; }
server {
listen 80;
listen 443 default ssl;
server_name test-app.example.com;
# for SSL
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_dhparam /etc/ssl/dhparam.pem;
ssl_prefer_server_ciphers on;
ssl_ciphers 'ECDHE-RSA-blahblahblah-SHA';
location / {
proxy_set_header Host $http_host;
proxy_pass http://test_app;
}
}
容器的nginx app.conf
server {
server_name _;
root /home/app/test/public;
ssl_certificate /etc/letsencrypt/live/test-app.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/test-app.example.com/privkey.pem;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_dhparam /etc/ssl/dhparam.pem;
ssl_prefer_server_ciphers on;
ssl_ciphers 'ECDHE-RSA-blahblah-SHA';
passenger_enabled on;
passenger_user app;
passenger_ruby /usr/bin/ruby2.3;
passenger_app_env staging;
location /app_test/assets/ {
passenger_enabled off;
alias /home/app/test/public/assets/;
gzip_static on;
expires +7d;
add_header Cache-Control public;
break;
}
}
在我的 Dockerfile 中,我有:
# expose port
EXPOSE 80
EXPOSE 443
在我的 docker-compose.yml 文件中我有:
test_app_app:
build: "."
env_file: config/test_app-application.env
links:
- test_app_db:postgres
environment:
app_url: https://test-app.example.com
ports:
- 4200:80
docker ps
显示为:
Up About an hour 443/tcp, 0.0.0.0:4200->80/tcp
我现在怀疑是因为服务器的 nginx - "front-facing" 服务器 - 没有证书,但我不能 运行 没有应用程序位置的 LetsEncrypt 命令。
我尝试了 运行在服务器上使用手动 LetsEncrypt 命令,但因为我可能暴露了端口 80,所以我得到了这个:socket.error: [Errno 98] Address already in use
我错过了什么吗?
我该怎么办?
有趣的一个。
我倾向于同意这可能是因为没有获得证书。
首先阅读我最后的免责声明。我会尝试使用 DNS authentication.,恕我直言,对于 Docker 之类的东西,这是一个更好的方法。我想到了一些想法。最简单的回答你的问题的方法是 docker 入口点脚本,它首先获取证书然后启动 nginx:
#!/bin/bash
set -ea
#get cert
./certbot-auto certonly --webroot -w /path/to/app/public -d www.example.com
#start nginx
nginx
恕我直言,这是“不错”的解决方案,但并不是真正的“自动化”(这是让加密目标的一部分)。它并没有真正解决以后更新证书的问题。如果这不是您关心的问题,那么您就可以了。
您可以真正参与并创建一个入口点脚本来检测证书何时过期,然后重新运行命令以更新它,然后重新加载 nginx。
一个更复杂(但也更具可扩展性的解决方案)是创建一个 docker 生活中唯一目的是处理 lets_encrypt 证书和续订的图像,然后提供一种分发方式这些证书到其他容器,例如:nfs(或共享 docker 卷,如果你 真的 小心)。
对于将来阅读本文的任何人:这是在 compose hooks 成为一项可用功能之前编写的,这将是迄今为止处理此类问题的最佳方式。
请阅读此免责声明:
Docker 并不是最好的解决方案,恕我直言。 Docker 图片应该是静态数据。因为 lets encrypt 证书在 3 个月后过期,这意味着您的容器的保质期应为三个月或更短(或者,如我上面所说,用于更新)。 “没关系!”我听到你说。但这也意味着您每次启动容器时都会不断获得颁发的新证书(使用入口点方法)。至少,这意味着以前的证书每次都会被吊销。我不知道使用 Lets Encrypt 执行此操作会产生什么后果。他们可能只会在他们认为有可疑的事情发生之前给你这么多撤销。
我最常做的实际上是使用配置管理并使用 nginx 作为主机系统的“前端”。或者依赖一些其他机制来处理 SSL 终止。但这并没有回答您关于如何让 Lets Encrypt 与 docker 一起工作的问题。 :-)
希望对您有所帮助或为您指明更好的方向。 :-)
我知道我错过了一件小事。如问题中所述,由于服务器上的 nginx 是 'front-facing' nginx,容器的 nginx 专门用于应用程序,因此服务器的 nginx 需要了解 SSL。
答案非常简单。将证书复制过来! (感谢我客户的运营主管)
我在 docker 容器中 cat
fullchain.pem
和 privkey.pem
并在服务器上的 /etc/ssl
中创建了相关文件。
在服务器的 /etc/nginx/sites-enabled/app.conf
我添加了:
ssl_certificate /etc/ssl/test-app-fullchain.pem;
ssl_certificate_key /etc/ssl/test-app-privkey.pem;
检查配置并重新启动 nginx。繁荣!工作起来很有魅力。 :)
我正在为 rails 应用程序使用 docker-compose 来拥有应用程序和数据库容器。为了测试某些应用程序功能,我需要 SSL...所以我将使用 LetsEncrypt 与自签名。
应用使用nginx,服务器ubuntu 14.04 lts,以phusion passenger docker镜像为基础镜像(轻量级debian)
通常使用 LetsEncrypt,我 运行 通常 ./certbot-auto certonly --webroot -w /path/to/app/public -d www.example.com
我的服务器 运行s nginx(将应用程序传递给容器的代理),所以我跳进容器到 运行 certbot 命令没有问题。
但是,当我尝试转到 https://test-app.example.com 时,它不起作用。我不知道为什么。
现场错误(Chrome):
This site can’t be reached
The connection was reset.
Curl 给出了更好的错误:
curl: (35) Unknown SSL protocol error in connection to test-app.example.com
服务器 nginx app.conf
upstream test_app { server localhost:4200; }
server {
listen 80;
listen 443 default ssl;
server_name test-app.example.com;
# for SSL
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_dhparam /etc/ssl/dhparam.pem;
ssl_prefer_server_ciphers on;
ssl_ciphers 'ECDHE-RSA-blahblahblah-SHA';
location / {
proxy_set_header Host $http_host;
proxy_pass http://test_app;
}
}
容器的nginx app.conf
server {
server_name _;
root /home/app/test/public;
ssl_certificate /etc/letsencrypt/live/test-app.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/test-app.example.com/privkey.pem;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_dhparam /etc/ssl/dhparam.pem;
ssl_prefer_server_ciphers on;
ssl_ciphers 'ECDHE-RSA-blahblah-SHA';
passenger_enabled on;
passenger_user app;
passenger_ruby /usr/bin/ruby2.3;
passenger_app_env staging;
location /app_test/assets/ {
passenger_enabled off;
alias /home/app/test/public/assets/;
gzip_static on;
expires +7d;
add_header Cache-Control public;
break;
}
}
在我的 Dockerfile 中,我有:
# expose port
EXPOSE 80
EXPOSE 443
在我的 docker-compose.yml 文件中我有:
test_app_app:
build: "."
env_file: config/test_app-application.env
links:
- test_app_db:postgres
environment:
app_url: https://test-app.example.com
ports:
- 4200:80
docker ps
显示为:
Up About an hour 443/tcp, 0.0.0.0:4200->80/tcp
我现在怀疑是因为服务器的 nginx - "front-facing" 服务器 - 没有证书,但我不能 运行 没有应用程序位置的 LetsEncrypt 命令。
我尝试了 运行在服务器上使用手动 LetsEncrypt 命令,但因为我可能暴露了端口 80,所以我得到了这个:socket.error: [Errno 98] Address already in use
我错过了什么吗?
我该怎么办?
有趣的一个。
我倾向于同意这可能是因为没有获得证书。
首先阅读我最后的免责声明。我会尝试使用 DNS authentication.,恕我直言,对于 Docker 之类的东西,这是一个更好的方法。我想到了一些想法。最简单的回答你的问题的方法是 docker 入口点脚本,它首先获取证书然后启动 nginx:
#!/bin/bash
set -ea
#get cert
./certbot-auto certonly --webroot -w /path/to/app/public -d www.example.com
#start nginx
nginx
恕我直言,这是“不错”的解决方案,但并不是真正的“自动化”(这是让加密目标的一部分)。它并没有真正解决以后更新证书的问题。如果这不是您关心的问题,那么您就可以了。
您可以真正参与并创建一个入口点脚本来检测证书何时过期,然后重新运行命令以更新它,然后重新加载 nginx。
一个更复杂(但也更具可扩展性的解决方案)是创建一个 docker 生活中唯一目的是处理 lets_encrypt 证书和续订的图像,然后提供一种分发方式这些证书到其他容器,例如:nfs(或共享 docker 卷,如果你 真的 小心)。
对于将来阅读本文的任何人:这是在 compose hooks 成为一项可用功能之前编写的,这将是迄今为止处理此类问题的最佳方式。
请阅读此免责声明:
Docker 并不是最好的解决方案,恕我直言。 Docker 图片应该是静态数据。因为 lets encrypt 证书在 3 个月后过期,这意味着您的容器的保质期应为三个月或更短(或者,如我上面所说,用于更新)。 “没关系!”我听到你说。但这也意味着您每次启动容器时都会不断获得颁发的新证书(使用入口点方法)。至少,这意味着以前的证书每次都会被吊销。我不知道使用 Lets Encrypt 执行此操作会产生什么后果。他们可能只会在他们认为有可疑的事情发生之前给你这么多撤销。
我最常做的实际上是使用配置管理并使用 nginx 作为主机系统的“前端”。或者依赖一些其他机制来处理 SSL 终止。但这并没有回答您关于如何让 Lets Encrypt 与 docker 一起工作的问题。 :-)
希望对您有所帮助或为您指明更好的方向。 :-)
我知道我错过了一件小事。如问题中所述,由于服务器上的 nginx 是 'front-facing' nginx,容器的 nginx 专门用于应用程序,因此服务器的 nginx 需要了解 SSL。
答案非常简单。将证书复制过来! (感谢我客户的运营主管)
我在 docker 容器中 cat
fullchain.pem
和 privkey.pem
并在服务器上的 /etc/ssl
中创建了相关文件。
在服务器的 /etc/nginx/sites-enabled/app.conf
我添加了:
ssl_certificate /etc/ssl/test-app-fullchain.pem;
ssl_certificate_key /etc/ssl/test-app-privkey.pem;
检查配置并重新启动 nginx。繁荣!工作起来很有魅力。 :)