为 docker 中的 nginx 配置 https

没有 https 加持的网站会逐渐地被浏览器标记为不安全的,所以为网站添加 https 已经变得刻不容缓。对于商业网站来说,花钱购买 SSL/TLS 证书并不是什么问题。但对于个人用户来说,如果能有免费的 SSL/TLS 证书可用将会是非常幸福的事情!Let‘s Encrypt 就是一个提供免费 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、conf.crt 和 html,创建 logs 目录及其子目录 nginx 和 letsencrypt:

$ mkdir -p nginx/{conf.d,conf.crt,html}
$ mkdir -p logs/{nginx,letsencrypt}

说明,本文演示的示例中需要我们手动创建的文件和目录结构如下:

创建 nginx/nginx.conf 文件,内容如下:

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/nginx/mime.types;
    default_type  application/octet-stream;

    sendfile        on;
    keepalive_timeout    65;
    client_max_body_size 10M;

    include /etc/nginx/conf.d/*.conf;
}

然后创建 nginx/conf.d/default.conf 文件,内容如下:

upstream web{
    server myweb:3000;
}
server {
    listen      80;
    listen      [::]:80;
    server_name filterinto.com www.filterinto.com;

    location ^~ /.well-known/acme-challenge/ {
        default_type "text/plain";
        root /usr/share/nginx/html;
    }
    location = /.well-known/acme-challenge/ {
        return 404;
    }
    location / {
        proxy_pass http://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)/nginx/nginx.conf:/etc/nginx/nginx.conf: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 证书

Let‘s Encrypt 是一个提供免费 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.com‘ ‘www.filterinto.com‘)
LED_LIST=()
WWW_ROOT=/usr/share/nginx/html
for domain in ${LIST[@]};do
    docker run         --rm         -v ${WEBDIR}/nginx/conf.crt:/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="[email protected]"         -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/nginx/conf.crt/live 目录下,以域名命名的目录下保存着该域名的证书:

然后去检查下 nginx/html 目录,发现多了一个隐藏的 .well-known 目录,这个目录就是在生成证书时创建的:

有了 SSL/TLS 证书,接下来我们就可以配置 https 站点了。

为站点配置 SSL/TLS 证书

有了 SSL/TLS 证书,接下来更新 nginx 的配置文件就可以了,更新 nginx/conf.d/default.conf 的内容如下:

upstream web{
    server myweb:3000;
}

server {
    listen      80;
    listen      [::]:80;
    server_name filterinto.com www.filterinto.com;

    location ^~ /.well-known/acme-challenge/ {
        default_type "text/plain";
        root /usr/share/nginx/html;
    }
    location = /.well-known/acme-challenge/ {
        return 404;
    }
    return 301 https://$server_name$request_uri;
}
server {
    listen      443;
    listen      [::]:443;
    server_name filterinto.com;

    # 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 !EXP !PSK !SRP !DSS !RC4";

    # config ssl certificate
    ssl_certificate           conf.crt/live/filterinto.com/fullchain.pem;
    ssl_certificate_key       conf.crt/live/filterinto.com/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 http://web;
    }
}
server {
    listen      443;
    listen      [::]:443;
    server_name www.filterinto.com;

    # 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 !EXP !PSK !SRP !DSS !RC4";

    # config ssl certificate
    ssl_certificate           conf.crt/live/www.filterinto.com/fullchain.pem;
    ssl_certificate_key       conf.crt/live/www.filterinto.com/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 http://web;
    }
}

然后删除容器 gateway 并用下面的脚本重新创建:

$ docker run -d     -p 80:80     -p 443:443     -v $(pwd)/nginx/conf.d:/etc/nginx/conf.d:ro     -v $(pwd)/nginx/conf.crt:/etc/nginx/conf.crt:ro     -v $(pwd)/nginx/nginx.conf:/etc/nginx/nginx.conf: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 带来的便利),在定时任务中添加下面两条记录就可以了:

0 0 1 * * /home/nick/certbot/renew_cert.sh /home/nick >> /home/nick/logs/cert.log 2>> /home/nick/logs/cert.error.log
0 1 1 * * docker exec gateway nginx -s reload

每月 1 号的 0 点更新证书,一个小时后 reload nginx 的配置。

总结

Let‘s Encrypt 是一个非常棒的网站,对于初学者和个人来说,能够帮助我们轻松的实现 HTTPS 站点(还是免费的)!在方便的同时,其隐患也是显而易见的:既然谁都可以无门槛的获得 SSL/TLS 证书,那么非法网站也可以通过它把自己伪装成看上去合法的站点。 所以千万不要片面的认为 HTTPS 站点就是安全的!

参考:
Setting up HTTPS on Nginx using Let’s Encrypt
在 docker nginx 下使用 docker let‘s encrypt
How to Set Up Free SSL Certificates from Let‘s Encrypt using Docker and Nginx

原文地址:https://www.cnblogs.com/sparkdev/p/9163162.html

时间: 2024-09-30 14:57:42

为 docker 中的 nginx 配置 https的相关文章

nginx 配置https并自签名证书

2016-10-28 转载请注明出处:http://daodaoliang.com/ 作者: daodaoliang 版本: V1.0.1 邮箱: [email protected] 参考链接: 这里 和 这里 和 官方文档 1. 制作服务器证书 服务器CA私钥: openssl genrsa -des3 -out ca.key 2048 制作解密后的CA私钥(一般无此必要): openssl rsa -in ca.key -out ca_decrypted.key ca.crt CA根证书(公

Nginx配置https服务器

配置HTTPS主机,必须在server配置块中打开SSL协议,还需要指定服务器端证书和密钥文件的位置: server { listen 443;  #要加密的域名 server_name www.test.com; ssl on; #证书所在位置,本例默认放在了nginx的conf目录下 ssl_certificate ssl.crt;  #密钥所在位置,本例默认放在了nginx的conf目录下 ssl_certificate_key server.key; ssl_session_timeou

nginx配置https及Android客户端访问自签名证书

前一篇随笔通过keytool生成keystore并为tomcat配置https,这篇随笔记录如何给nginx配置https.如果nginx已配置https,则tomcat就不需要再配置https了.通过以下三步生成自签名证书# 生成一个key,你的私钥,openssl会提示你输入一个密码,可以输入,也可以不输,# 输入的话,以后每次使用这个key的时候都要输入密码,安全起见,还是应该有一个密码保护> openssl genrsa -des3 -out selfsign.key 4096 # 使用

nginx配置https证书

连接错误,不安全 并不是hsts的锅 chrome://net-internals/#hsts, 大部分原因还是证书的问题 NET::ERR_CERT_COMMON_NAME_INVALID 证书域名和实际访问的域名要匹配:SAN 证书中增加SAN域名 open ssl openssl genrsa -out server.key 1024 openssl req -new -x509 -days 3650 -key server.key -out server.crt -subj "/C=CN

购买https证书以及nginx配置https

文章来源运维公会:购买https证书以及nginx配置https 1.https的作用https的全名是安全超文本传输协议,是在http的基础上增加了ssl加密协议.在信息传输的过程中,信息有可能被劫持,从而造成数据的丢失,而如果使用的是https的话,即使信息被劫持,因为在传输过程中,信息是被加密的,所以也能保证数据的安全性. 2.申请证书目前在阿里云或者腾讯云上都可以购买证书,现在以阿里云为例购买证书在阿里云的产品与服务上找到SSL证书点击购买证书,可以看到有免费型的SSL证书.如果是个人使

Docker中安装nginx

Docker中安装nginx 步骤: 1 .docker pull nginx 2.docker images 3.docker run -d -p 80:80 --name nginx nginx 4.docker ps 5.查看是否可以访问 注意:我这里是安装在云服务器的docker中. 原文地址:https://www.cnblogs.com/Edward-Wang/p/12049557.html

关于Nginx配置Https server后,乱跳的问题解决记录

大部分的服务器上,我们会在一个Nginx服务下配置多个vhost,以最大化运用服务器资源.然而,为其中一个vhost域名启用 HTTPS 之后,发现百度统计的实时访客或入口页中,存在一些来自其它域名的请求.即通过 https://some-other-domain.com/some-url 来访问对应的 https://www.domain.com/some-url 结果就是 Google 浏览器显示了一个安全警告页面,认为这是一个不安全的网页.因为我只配置了 www.domain.com 的

Window7 64位下Nginx配置https

一.安装Nginx 官方下载地址:http://nginx.org/en/download.html 直接下载1.7.1.zip的链接:http://nginx.org/download/nginx-1.7.1.zip 二.安装Openssl 官方下载的没弄明白怎么用,不过还是留下链接以备之后使用:http://www.openssl.org/source/ 感觉比较好用的:链接:http://pan.baidu.com/s/1kT9OcPT 密码:zg6p 三.生成密钥 安装完成Openssl

【转】Linux下nginx配置https协议访问的方法

一.配置nginx支持https协议访问,需要在编译安装nginx的时候添加相应的模块--with-http_ssl_module 查看nginx编译参数:/usr/local/nginx/sbin/nginx -V 如下所示: configure arguments: --prefix=/usr/local/nginx --with-google_perftools_module --without-http_memcached_module --user=www --group=www --