为docker中的nginx配置https
没有 https 加持的⽹站会逐渐地被浏览器标记为不安全的,所以为⽹站添加 https 已经变得刻不容缓。对于商业⽹站来说,花钱购买 SSL/TLS 证书并不是什么问题。但对于个⼈⽤户来说,如果能有免费的 SSL/TLS 证书可⽤将会是⾮常幸福的事情!就是⼀个提供免费 SSL/TLS 证书的⽹站,由于其证书期限只有三个⽉,所以需要我们⽤⾃动化的⽅式去更新证书。本⽂将介绍如何为通过 docker 运⾏的 nginx 中的站点添加 https ⽀持,并⾃动完成证书的更新。本⽂的演⽰环境为:运⾏在 Azure 上的 Ubuntu 16.04 主机(此图来⾃互联⽹):
准备环境
在 Azure 上创建 Ubuntu 类型的虚机事件⾮常容易的事情,安装 docker 也⽆须赘⾔。⽐较容易忽略的是配置合适的⽹络安全组规则,⽐如打开 80 和 443 端⼝:
还有就是配置 DNS:
创建⼀个普通的 http 站点
简单起见,直接使⽤⼀个镜像中的 nodejs 应⽤作为 web 站点:
$ docker pull ljfpower/nodedemo
$ docker network create -d bridge webnet
$ docker run -d --restart=always --expose=3000 \
--network=webnet --name=myweb \
ljfpower/nodedemo
在⽤户的家⽬录下创建 nginx ⽬录及其⼦⽬录 conf.d、 和 html,创建 logs ⽬录及其⼦⽬录 nginx 和 letsencrypt:
$ mkdir -p nginx/{conf.,html}
$ mkdir -p logs/{nginx,letsencrypt}
说明,本⽂演⽰的⽰例中需要我们⼿动创建的⽂件和⽬录结构如下:
创建 f ⽂件,内容如下:
user  nginx;
worker_processes  auto;
error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;
events {
worker_connections  2048;
}
http {
include      /etc/pes;
default_type  application/octet-stream;
sendfile        on;
keepalive_timeout    65;
client_max_body_size 10M;
include /etc/nginx/conf.d/*.conf;
}
然后创建 nginx/conf.f ⽂件,内容如下:
upstream web{
server myweb:3000;
}
server {
listen      80;
listen      [::]:80;
server_name filterinto www.filterinto;
location ^~ /.well-known/acme-challenge/ {
default_type "text/plain";
root /usr/share/nginx/html;
}
location = /.well-known/acme-challenge/ {
return 404;
}
location / {
proxy_pass web;
}
}
其中 /.well-known/acme-challenge/ ⽬录是 certbot ⼯具在⽣成证书时创建的。接下来创建⽂件 nginx/html/index.html ⽂件,内容如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Let's Encrypt First Time Cert Issue Site</title>
</head>
<body>
<h1>Hello HTTPS!</h1>
<p>
Just used for the very first time SSL certificates are issued by Let's Encrypt's
certbot.
</p>
</body>
</html>
这个页⾯也是 certbot 在⽣成证书时需要⽤到的。最后让我们启动容器(在⽤户的家⽬录下执⾏下⾯的命令):
$ docker run -d \
-p 80:80 \
-v $(pwd)/nginx/conf.d:/etc/nginx/conf.d:ro \
-v $(pwd)/f:/etc/f:ro \
-v $(pwd)/logs/nginx:/var/log/nginx \
-v $(pwd)/nginx/html:/usr/share/nginx/html \
--restart=always \
--name=gateway \
--network=webnet \
nginx:1.14
注意:这时没有映射 443 端⼝,也没有挂载存放证书的⽬录。只能以 http 协议访问访问我们的站点:
为站点⽣成 SSL/TLS 证书
nginx ssl证书配置是⼀个提供免费 SSL/TLS 证书的⽹站,它为⽤户提供了 certbot ⼯具⽤来⽣成 SSL/TLS 证书。⽅便起见,我们把 certbot 简单的封装到容器中。在⽤户的家⽬录下创建 certbot ⽬录,进⼊certbot ⽬录并把下⾯的内容保存到 Dockerfile ⽂件中:
FROM alpine:3.4
RUN apk add --update bash certbot
VOLUME ["/etc/letsencrypt"]
然后执⾏下⾯的命令创建 certbot 镜像:
$ docker build -t certbot:1.0 .
然后在 certbot ⽬录下创建⾃动更新证书的脚本 renew_cert.sh,内容如下:
#!/bin/bash
WEBDIR="$1"
LIST=('filterinto''www.filterinto')
LED_LIST=()
WWW_ROOT=/usr/share/nginx/html
for domain in ${LIST[@]};do
docker run \
--rm \
-v ${WEBDIR}/:/etc/letsencrypt \
-
v ${WEBDIR}/logs/letsencrypt:/var/log/letsencrypt \
-v ${WEBDIR}/nginx/html:${WWW_ROOT} \
certbot:1.0 \
certbot certonly --verbose --noninteractive --quiet --agree-tos \
--webroot -w ${WWW_ROOT} \
--email="nick.li@grapecity" \
-d "$domain"
CODE=$?
if [ $CODE -ne 0 ]; then
FAILED_LIST+=($domain)
fi
done
# output failed domains
if [ ${#FAILED_LIST[@]} -ne 0 ];then
echo'failed domain:'
for (( i=0; i<${#FAILED_LIST[@]}; i++ ));
do
echo ${FAILED_LIST[$i]}
done
fi
在⽤户的家⽬录中执⾏ ./renew_cert.sh /home/nick 命令就可以⽣成新的证书(/home/nick 为当前⽤户的家⽬录)。⽣成的证书被保存在 /home/nick//live ⽬录下,以域名命名的⽬
录下保存着该域名的证书:
然后去检查下 nginx/html ⽬录,发现多了⼀个隐藏的 .well-known ⽬录,这个⽬录就是在⽣成证书时创建的:
有了 SSL/TLS 证书,接下来我们就可以配置 https 站点了。
为站点配置 SSL/TLS 证书
有了 SSL/TLS 证书,接下来更新 nginx 的配置⽂件就可以了,更新 nginx/conf.f 的内容如下:
upstream web{
server myweb:3000;
}
server {
listen      80;
listen      [::]:80;
server_name filterinto www.filterinto;
location ^~ /.well-known/acme-challenge/ {
default_type "text/plain";
root /usr/share/nginx/html;
}
location = /.well-known/acme-challenge/ {
return 404;
}
return 301 $server_name$request_uri;
}
server {
listen      443;
listen      [::]:443;
server_name filterinto;
# enable ssl
ssl                      on;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers              "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH EDH+aRSA !aNULL !eNULL !LOW !3DES !MD5 !    # config ssl certificate
ssl_certificate          /live/filterinto/fullchain.pem;
ssl_certificate_key      /live/filterinto/privkey.pem;
location ^~ /.well-known/acme-challenge/ {
default_type "text/plain";
root /usr/share/nginx/html;
}
location = /.well-known/acme-challenge/ {
return 404;
}
location / {
proxy_pass web;
}
}
server {
listen      443;
listen      [::]:443;
server_name www.filterinto;
# enable ssl
ssl                      on;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers              "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH EDH+aRSA !aNULL !eNULL !LOW !3DES !MD5 !    # config ssl cer
tificate
ssl_certificate          /live/www.filterinto/fullchain.pem;
ssl_certificate_key      /live/www.filterinto/privkey.pem;
location ^~ /.well-known/acme-challenge/ {
default_type "text/plain";
root /usr/share/nginx/html;
}
location = /.well-known/acme-challenge/ {
return 404;
}
location / {
proxy_pass web;
}
}
然后删除容器 gateway 并⽤下⾯的脚本重新创建:
$ docker run -d \
-p 80:80 \
-p 443:443 \
-v $(pwd)/nginx/conf.d:/etc/nginx/conf.d:ro \
-v $(pwd)/:/etc/:ro \
-v $(pwd)/f:/etc/f:ro \
-v $(pwd)/logs/nginx:/var/log/nginx \
-
v $(pwd)/nginx/html:/usr/share/nginx/html \
--restart=always \
--name=gateway \
--network=webnet \
nginx:1.14
现在就只能通过 https 来访问站点了:
⾃动更新证书
Let's Encrypt 提供的 SSL/TLS 证书期限只有三个⽉,每过三个⽉要⼿动更新⼀次证书也够呛的,下⾯我们介绍⾃动更新证书的⽅法。
其实我们的配置已经为⾃动化更新证书提供了最⼤的便利(其实是使⽤ docker 带来的便利),在定时任务中添加下⾯两条记录就可以了:
001 * * /home/nick/certbot/renew_cert.sh /home/nick >> /home/nick/logs/cert.log 2>> /home/nick/logs/
011 * * docker exec gateway nginx -s reload
每⽉ 1 号的 0 点更新证书,⼀个⼩时后 reload nginx 的配置。
总结
Let's Encrypt 是⼀个⾮常棒的⽹站,对于初学者和个⼈来说,能够帮助我们轻松的实现 HTTPS 站点(还是免费的)!在⽅便的同时,其隐患也是显⽽易见的:既然谁都可以⽆门槛的获得SSL/TLS 证书,那么⾮法⽹站也可以通过它把⾃⼰伪装成看上去合法的站点。所以千万不要⽚⾯的认为 HTTPS 站点就是安全的!
参考:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。