从一开始的 Apache/httpd 服务器部署单站点开箱即用到后来的多站点配置,再到后来多开发语言混合、项目环境隔离、负载均衡等,单独的 Apache 服务器已经无法独立满足需求了。这时候开始考虑在前面加上一个 Nginx 作流量分发等等工作。
随着运营商的越来越无节操,以及网络安全威胁日益严重,很多站点开始考虑上 HTTPS,即加上证书来保证通道的安全和可靠性。 Let’s Encrypt 提供了免费的 SSL 证书并提供了脚本化方案。无论是 Apache 还是 Nginx,网上都已经有了很多的文档,但是个人喜欢使用 Docker 来部署所有应用,那么如何在不修改原有镜像的基础上实现 SSL 证书的自动签发和续期就是一个需要解决的问题了。
同样的,本文章旨在使用 Docker 来完成上述任务,不需要安装新的软件或修改原有应用,以给一个运行在 Apache 容器中、前端用Nginx分流的站点申请和续期 SSL 证书为例,假设该站点的域名为 example.com
。
本文中的修改只涉及到 Nginx,后端的服务没有任何改动。
演示环境说明
首先介绍一下本文的环境:
- 有一个 Nginx 容器,监听 80/443 端口,作为前端的流量转发和负载均衡;
- 若干 Apache、NodeJS 等容器,分别对应不同的站点;
- 均部署在同一台服务器上;
- Nginx 的站点配置数据持久化存储在主机的
/data/nginx/conf.d/
目录,对应的容器目录为/etc/nginx/conf.d/
; - Nginx 的证书签发验证文件持久化存储在主机的
/data/nginx/webroot/
目录,对应的容器目录为/var/www/html/
; - Nginx 的站点SSL证书持久化存储在主机的
/data/ssl/
目录,对应的容器目录为/etc/letsencrypt/
;
添加 nginx 配置
修改 /data/nginx/conf.d
目录中 example.com
站点的配置文件 example.com.conf
1 | server { |
主要是添加以下几行,因为证书签发过程中会将验证文件放在网站的 /.well-known 目录下,在 Nginx 中将这个目录的流量转到 /var/www/html/example.com
目录下。
1 | location ~ /.well-known { |
除此之外,还需要在宿主机的目录 /data/nginx/webroot/
下创建 example.com
目录存放后期申请的SSL证书文件。
启动 Nginx
修改完站点配置之后,需要刷新 Nginx,这里直接采用重启的方式进行配置文件的刷新工作。
假定 Nginx 的启动脚本如下:
1 | docker service create \ |
签发 certbot(初次申请)
将宿主机的 /data/nginx/webroot/example.com/
目录映射到 certbot 容器的 /var/www/html/
目录
使用以下命令来申请 SSL 证书。
1 | docker run -it --rm --name certbot \ |
用你自己的信息替换其中的值。
如果一切正常的话,可以看到类似下图的输出,表明 SSL 证书已经完成签发并下载到了主机的 /data/ssl
目录。
修改 Nginx 配置
在初次完成 SSL 证书签发任务后,我们以后就可以使用 https 访问了,修改之前的 nginx 配置文件 example-com.conf
,将 http 流量重定向到 https 协议并配置 ssl 证书。
1 | server { |
根据具体的信息修改以上配置,修改完成后重启 nginx 容器,再次访问 http://example.com
,可以发现自动跳转到了 https://example.com
并且可以看到站点被加上了小绿锁^_^。
自动续期
至此,SSL 证书的签发和证书部署就完成了,因为 Let’s Encrypt 的证书有效期是 3 个月,到期之前需要续期,下面我们用定时任务来实现这个。
续期证书可以使用上述用来签发证书的命令且不需要修改,只需在执行之后重启 Nginx 容器即可。
创建文件 /crontab/renew_cert.sh
,文件内容如下:
1 | # Renew Certificate |
添加可执行权限
1 | chmod +x renew_cert.sh |
以上命令在续期的基础上添加了重启 Nginx 容器的功能,这样只需定期执行这个脚本就可以完成续期的目的。
再进一步,让系统自动定期执行这条命令,这样部署好之后,我们就无需关心证书有效期的问题了。
这里利用系统自带的 crontab
功能来定期执行续期脚本。
1 | crontab -e |
添加以下行
1 | 0 0 1 * * /crontab/renew_cert.sh |
保存退出,crontab 就会自动更新生效。以上命令的含义是每个月1号零点自动执行 /crontab/renew_cert.sh
这个脚本。
续期脚本的执行结果如下图所示
至此,部署完成!
其他说明
- Nginx 刷新配置文件的命令是
nginx reload
,但是由于 Docker 的特性,这一命令会造成容器的退出,所以我们直接重启容器也可以。 - 为了保持篇幅简短,文中所用的命令,尤其时 Nginx 的站点配置都十分精简,仅供参考,不适合直接用于正式环境。
- 本文中使用 Docker Swarm 部署 Nginx 和 Apache,采用其他方式部署的需要适当修改命令。