如何為docker中的nginx配置https

準(zhǔn)備環(huán)境

在 azure 上創(chuàng)建 ubuntu 類(lèi)型的虛機(jī)事件非常容易的事情,安裝 docker 也無(wú)須贅言。比較容易忽略的是配置合適的網(wǎng)絡(luò)安全組規(guī)則,比如打開(kāi) 80 和 443 端口:

如何為docker中的nginx配置https

還有就是配置 dns:

如何為docker中的nginx配置https

創(chuàng)建一個(gè)普通的 http 站點(diǎn)

簡(jiǎn)單起見(jiàn),直接使用一個(gè)鏡像中的 nodejs 應(yīng)用作為 web 站點(diǎn):

$?docker?pull?ljfpower/nodedemo $?docker?network?create?-d?bridge?webnet $?docker?run?-d?--restart=always?--expose=3000? ???--network=webnet?--name=myweb? ???ljfpower/nodedemo

在用戶的家目錄下創(chuàng)建 nginx 目錄及其子目錄 conf.d、conf.crt 和 html,創(chuàng)建 logs 目錄及其子目錄 nginx 和 letsencrypt:

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

說(shuō)明,本文演示的示例中需要我們手動(dòng)創(chuàng)建的文件和目錄結(jié)構(gòu)如下:

如何為docker中的nginx配置https

創(chuàng)建 nginx/nginx.conf 文件,內(nèi)容如下:

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; }

然后創(chuàng)建 nginx/conf.d/default.conf 文件,內(nèi)容如下:

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 工具在生成證書(shū)時(shí)創(chuàng)建的。接下來(lái)創(chuàng)建文件 nginx/html/index.html 文件,內(nèi)容如下:

nbsp;html&gt;   ?<meta> ?<title>let's?encrypt?first?time?cert?issue?site</title> ?<h1>hello?https!</h1> ?<p> ??just?used?for?the?very?first?time?ssl?certificates?are?issued?by?let's?encrypt's ??certbot. ?</p>  

這個(gè)頁(yè)面也是 certbot 在生成證書(shū)時(shí)需要用到的。最后讓我們啟動(dòng)容器(在用戶的家目錄下執(zhí)行下面的命令):

$?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

注意:這時(shí)沒(méi)有映射 443 端口,也沒(méi)有掛載存放證書(shū)的目錄。只能以 http 協(xié)議訪問(wèn)訪問(wèn)我們的站點(diǎn):

如何為docker中的nginx配置https

為站點(diǎn)生成 ssl/tls 證書(shū)

let’s encrypt 是一個(gè)提供免費(fèi) ssl/tls 證書(shū)的網(wǎng)站,它為用戶提供了 certbot 工具用來(lái)生成 ssl/tls 證書(shū)。方便起見(jiàn),我們把 certbot 簡(jiǎn)單的封裝到容器中。在用戶的家目錄下創(chuàng)建 certbot 目錄,進(jìn)入 certbot 目錄并把下面的內(nèi)容保存到 dockerfile 文件中:

from?alpine:3.4 run?apk?add?--update?bash?certbot volume?["/etc/letsencrypt"]

然后執(zhí)行下面的命令創(chuàng)建 certbot 鏡像:

$?docker?build?-t?certbot:1.0?.

然后在 certbot 目錄下創(chuàng)建自動(dòng)更新證書(shū)的腳本 renew_cert.sh,內(nèi)容如下:

#!/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="nick.li@grapecity.com"? ??-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<p>在用戶的家目錄中執(zhí)行 ./renew_cert.sh /home/nick 命令就可以生成新的證書(shū)(/home/nick 為當(dāng)前用戶的家目錄)。生成的證書(shū)被保存在 /home/nick/nginx/conf.crt/live 目錄下,以域名命名的目錄下保存著該域名的證書(shū):</p><p><img src="https://img.php.cn/upload/article/000/465/014/168511453073708.jpg" alt="如何為docker中的nginx配置https"></p><p>然后去檢查下 nginx/html 目錄,發(fā)現(xiàn)多了一個(gè)隱藏的 .well-known 目錄,這個(gè)目錄就是在生成證書(shū)時(shí)創(chuàng)建的:</p><p><img src="https://img.php.cn/upload/article/000/465/014/168511453084874.jpg" alt="如何為docker中的nginx配置https"></p><p>有了 ssl/tls 證書(shū),接下來(lái)我們就可以配置 https 站點(diǎn)了。</p><p><strong>為站點(diǎn)配置 ssl/tls 證書(shū)</strong></p><p>有了 ssl/tls 證書(shū),接下來(lái)更新 nginx 的配置文件就可以了,更新 nginx/conf.d/default.conf 的內(nèi)容如下:</p><pre class="brush:bash;">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 并用下面的腳本重新創(chuàng)建:

$?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

現(xiàn)在就只能通過(guò) https 來(lái)訪問(wèn)站點(diǎn)了:

如何為docker中的nginx配置https

自動(dòng)更新證書(shū)

let’s encrypt 提供的 ssl/tls 證書(shū)期限只有三個(gè)月,每過(guò)三個(gè)月要手動(dòng)更新一次證書(shū)也夠嗆的,下面我們介紹自動(dòng)更新證書(shū)的方法。

其實(shí)我們的配置已經(jīng)為自動(dòng)化更新證書(shū)提供了最大的便利(其實(shí)是使用 docker 帶來(lái)的便利),在定時(shí)任務(wù)中添加下面兩條記錄就可以了:

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

每月 1 號(hào)的 0 點(diǎn)更新證書(shū),一個(gè)小時(shí)后 reload nginx 的配置。

? 版權(quán)聲明
THE END
喜歡就支持一下吧
點(diǎn)贊5 分享
站長(zhǎng)的頭像-小浪學(xué)習(xí)網(wǎng)月度會(huì)員