如何使用Nginx、Let’s Encrypt和Docker Compose来保护容器化的Node.js应用程序
简介
有多种方法可以增强您的Node.js应用程序的灵活性和安全性。使用像Nginx这样的反向代理服务器可以实现请求负载均衡、缓存静态内容和实现传输层安全(TLS)。在服务器上启用加密的HTTPS确保与应用程序之间的通信始终保持安全。
在容器中使用TLS/SSL实现反向代理与直接在主机操作系统上工作需要一套不同的步骤。举个例子,如果你要为在服务器上运行的应用程序获取Let’s Encrypt的证书,你需要直接在主机上安装所需的软件。而容器让你可以采取一种不同的方法。使用Docker Compose,你可以为你的应用程序、Web服务器和Certbot客户端创建容器,从而使你能够获取证书。通过按照这些步骤进行操作,你可以充分利用容器化工作流程的模块化和可移植性。
在本教程中,您将使用Docker Compose部署一个具有Nginx反向代理的Node.js应用程序。您将获取与您的应用程序关联的域名的TLS/SSL证书,并确保它在SSL Labs中获得高安全评级。最后,您将设置一个定时任务来更新您的证书,以保持您的域名的安全性。
先决条件
要按照这个教程的步骤进行,你需要以下物品:
- An Ubuntu 18.04 server, a non-root user with sudo privileges, and an active firewall. For guidance on how to set these up, please read this Initial Server Setup guide.
- Docker and Docker Compose installed on your server. For guidance on installing Docker, follow Steps 1 and 2 of How To Install and Use Docker on Ubuntu 18.04. For guidance on installing Compose, follow Step 1 of How To Install Docker Compose on Ubuntu 18.04.
- A registered domain name. This tutorial will use your_domain throughout. You can get one for free at Freenom, or use the domain registrar of your choice.
- Both of the following DNS records set up for your server. You can follow this introduction to Silicon Cloud DNS for details on how to add them to a Silicon Cloud account, if that’s what you’re using:An A record with your_domain pointing to your server’s public IP address.
An A record with www.your_domain pointing to your server’s public IP address.
一旦你把一切准备就绪,你就可以开始第一步了。
第一步 – 克隆和测试节点应用程序
作为第一步,您将使用包含Dockerfile的Node应用程序代码克隆存储库,通过Compose使用它来构建应用程序映像。然后,您将使用docker run命令构建和运行应用程序,而无需使用反向代理或SSL进行测试。
在非root用户的主目录下,从Silicon Cloud Community 的GitHub账户克隆nodejs-image-demo存储库。这个存储库包含了在《如何使用Docker构建Node.js应用》中描述的设置代码。
将存储库克隆到一个目录中。本示例将使用node_project作为目录名称。请随意根据您的喜好来命名此目录。
- git clone https://github.com/do-community/nodejs-image-demo.git node_project
切换至node_project目录。
- cd node_project
在这个目录中,有一个Dockerfile,包含了使用Docker node:10镜像和当前项目目录的内容来构建一个Node应用程序的指令。您可以使用以下命令预览Dockerfile的内容。
- cat Dockerfile
FROM node:10-alpine RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app WORKDIR /home/node/app COPY package*.json ./ USER node RUN npm install COPY –chown=node:node . . EXPOSE 8080 CMD [ “node”, “app.js” ]
这些指令通过将项目代码从当前目录复制到容器中,并使用npm install安装依赖项,构建了一个Node镜像。它们还利用了Docker的缓存和镜像分层功能,通过将package.json和package-lock.json(包含项目列出的依赖项)的复制与应用程序代码的其余部分的复制分开。最后,这些指令指定容器将作为非root节点用户运行,在应用程序代码和node_modules目录上设置适当的权限。
有关此 Dockerfile 和 Node 镜像的最佳实践的更多信息,请在“如何使用 Docker 构建 Node.js 应用程序”的第3步中查看完整讨论。
要在没有 SSL 的情况下测试应用程序,您可以使用 docker build 和 -t 标志来构建和标记镜像。此示例将图像命名为 node-demo,但您可以自由地为其命名为其他名称。
- docker build -t node-demo .
当构建过程完成后,您可以使用”docker images”命令列出您的镜像。
- docker images
以下输出确认了应用程序的镜像构建。
REPOSITORY TAG IMAGE ID CREATED SIZE node-demo latest 23961524051d 7 seconds ago 73MB node 10-alpine 8a752d5af4ce 3 weeks ago 70.7MB
接下来,使用docker run命令创建容器。此命令包含了三个标志。
- -p: This publishes the port on the container and maps it to a port on your host. You will use port 80 on the host in this example, but feel free to modify this as necessary if you have another process running on that port. For more information about how this works, review this discussion in the Docker documentation on port binding.
- -d: This runs the container in the background.
- –name: This allows you to give the container a memorable name.
运行以下命令来构建容器:
- docker run –name node-demo -p 80:8080 -d node-demo
使用docker ps命令检查运行中的容器。
- docker ps
以下输出确认了您的应用程序容器正在运行:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 4133b72391da node-demo “node app.js” 17 seconds ago Up 16 seconds 0.0.0.0:80->8080/tcp node-demo
您现在可以访问您的域名来测试您的设置:http://your_domain。记得将your_domain替换为您自己的域名。您的应用程序将显示以下引导页面:

现在您已经测试了该应用程序,您可以停止容器并删除镜像。使用docker ps获取您的容器ID。
- docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 4133b72391da node-demo “node app.js” 17 seconds ago Up 16 seconds 0.0.0.0:80->8080/tcp node-demo
使用docker stop停止容器。请确保将此处列出的CONTAINER ID替换为您自己应用程序的CONTAINER ID。
- docker stop 4133b72391da
现在,您可以使用docker system prune和-a标志一次性删除已停止的容器以及所有图像,包括未使用和悬空的图像。
- docker system prune -a
在输出中提示时按y键确认您要删除已停止的容器和镜像。请注意,这也会删除您的构建缓存。
一旦你的应用图像经过测试,你就可以使用Docker Compose继续构建你的其他设置。
步骤 2 — 定义网络服务器配置
有了我们的Dockerfile应用程序,您将创建一个配置文件来运行您的Nginx容器。您可以从一个最小的配置开始,其中包括您的域名,文档根目录,代理信息以及一个location block来指向.certbot目录,Certbot将在其中放置一个临时文件来验证您的域名的DNS是否解析到您的服务器。
首先,在当前项目目录node_project中创建一个目录,用于存放配置文件。
- mkdir nginx-conf
使用nano或您喜爱的编辑器创建并打开文件。
- nano nginx-conf/nginx.conf
将以下服务器块添加到代理用户请求到您的Node应用容器,并将Certbot的请求定向到.well-known目录。请务必使用您自己的域名替换your_domain。
server {
listen 80;
listen [::]:80;
root /var/www/html;
index index.html index.htm index.nginx-debian.html;
server_name your_domain www.your_domain;
location / {
proxy_pass http://nodejs:8080;
}
location ~ /.well-known/acme-challenge {
allow all;
root /var/www/html;
}
}
这个服务器块将允许您启动Nginx容器作为反向代理,将请求传递到您的Node应用容器。它还将允许您使用Certbot的webroot插件来获取您的域名的证书。该插件依赖于HTTP-01验证方法,它使用一个HTTP请求来验证Certbot能够访问响应给定域名的服务器资源。
编辑完成后,请保存并关闭文件。如果您使用的是nano编辑器,可以按下CTRL+X,然后按Y键,最后按回车键来完成操作。要了解更多关于Nginx服务器和location块选择算法的信息,请参阅这篇关于理解Nginx服务器和location块选择算法的文章。
在完成了Web服务器配置细节之后,你可以开始创建你的docker-compose.yml文件,这将允许你创建应用程序服务和使用的Certbot容器来获取证书。
第三步——创建Docker Compose文件
docker-compose.yml文件将定义您的服务,包括Node应用程序和Web服务器。它将指定详细信息,如命名卷,这对于在容器之间共享SSL凭据非常重要,以及网络和端口信息。它还允许您指定在创建容器时要运行的命令。此文件是定义您的服务如何协同工作的核心资源。
在当前目录下创建并打开文件。
- nano docker-compose.yml
首先,对应用服务进行定义。
以下是用本地语言进行的中文释义:
`~/node_project/docker-compose.yml` 为一 Docker Compose 的配置文件。
version: '3'
services:
nodejs:
build:
context: .
dockerfile: Dockerfile
image: nodejs
container_name: nodejs
restart: unless-stopped
Node.js服务定义包括以下内容:
- build: This defines the configuration options, including the context and dockerfile, that will be applied when Compose builds the application image. If you wanted to use an existing image from a registry like Docker Hub, you could use the image instruction instead, with information about your username, repository, and image tag.
- context: This defines the build context for the application image build. In this case, it’s the current project directory which is represented with the ..
- dockerfile: This specifies the Dockerfile that Compose will use for the build — the Dockerfile reviewed at in Step 1.
- image, container_name: These apply names to the image and container.
- restart: This defines the restart policy. The default is no, but in this example, the container is set to restart unless it is stopped.
请注意,您在这项服务中不包括绑定挂载,因为您的设置侧重于部署而不是开发。如需更多信息,请阅读Docker关于绑定挂载和卷的文档。
在重新启动定义之后,添加名为app-network的桥接网络,以实现应用程序和web服务器容器之间的通信。
services:
nodejs:
...
networks:
- app-network
这样的用户自定义桥接网络可以在同一台Docker守护程序主机上的容器之间进行通信。这简化了应用程序内的流量和通信,因为它在同一个桥接网络上打开了所有容器之间的端口,并且不向外界开放任何端口。因此,您可以选择性地仅打开需要公开前端服务的端口。
接下来,定义网络服务器服务:
...
webserver:
image: nginx:mainline-alpine
container_name: webserver
restart: unless-stopped
ports:
- "80:80"
volumes:
- web-root:/var/www/html
- ./nginx-conf:/etc/nginx/conf.d
- certbot-etc:/etc/letsencrypt
- certbot-var:/var/lib/letsencrypt
depends_on:
- nodejs
networks:
- app-network
这里为nodejs服务定义的一些设置保持不变,但是进行了一些以下修改:
- image: This tells Compose to pull the latest Alpine-based Nginx image from Docker Hub. For more information about alpine images, please read Step 3 of How To Build a Node.js Application with Docker.
- ports: This exposes port 80 to enable the configuration options you’ve defined in your Nginx configuration.
下列指定了具名卷和绑定挂载的选项:
- web-root:/var/www/html: This will add your site’s static assets, copied to a volume called web-root, to the the /var/www/html directory on the container.
- ./nginx-conf:/etc/nginx/conf.d: This will bind mount the Nginx configuration directory on the host to the relevant directory on the container, ensuring that any changes you make to files on the host will be reflected in the container.
- certbot-etc:/etc/letsencrypt: This will mount the relevant Let’s Encrypt certificates and keys for your domain to the appropriate directory on the container.
- certbot-var:/var/lib/letsencrypt: This mounts Let’s Encrypt’s default working directory to the appropriate directory on the container.
接下来,为certbot容器添加配置选项。请确保用您自己的域名和联系邮箱替换域名和电子邮件信息。
~/node_project/docker-compose.yml请提供一个选项即可:
...
certbot:
image: certbot/certbot
container_name: certbot
volumes:
- certbot-etc:/etc/letsencrypt
- certbot-var:/var/lib/letsencrypt
- web-root:/var/www/html
depends_on:
- webserver
command: certonly --webroot --webroot-path=/var/www/html --email sammy@your_domain --agree-tos --no-eff-email --staging -d your_domain -d www.your_domain
这个定义告诉Compose从Docker Hub拉取certbot/certbot镜像。它还使用了命名卷来与Nginx容器共享资源,包括域名证书和密钥在certbot-etc中,Let’s Encrypt工作目录在certbot-var中,以及应用程序代码在web-root中。
再次,您已使用 depends_on 来指定只有当 webserver 服务正在运行时,certbot 容器才会启动。
当容器启动时,命令选项指定要运行的命令。它包括使用certonly子命令和以下选项。
- –webroot: This tells Certbot to use the webroot plugin to place files in the webroot folder for authentication.
- –webroot-path: This specifies the path of the webroot directory.
- –email: Your preferred email for registration and recovery.
- –agree-tos: This specifies that you agree to ACME’s Subscriber Agreement.
- –no-eff-email: This tells Certbot that you do not wish to share your email with the Electronic Frontier Foundation (EFF). Feel free to omit this if you would prefer.
- –staging: This tells Certbot that you would like to use Let’s Encrypt’s staging environment to obtain test certificates. Using this option allows you to test your configuration options and avoid possible domain request limits. For more information about these limits, please read Let’s Encrypt’s rate limits documentation.
- -d: This allows you to specify domain names you would like to apply to your request. In this case, you’ve included your_domain and www.your_domain. Be sure to replace these with your own domains.
最后一步,添加卷和网络定义。请确保将此处的用户名替换为您自己的非root用户。
...
volumes:
certbot-etc:
certbot-var:
web-root:
driver: local
driver_opts:
type: none
device: /home/sammy/node_project/views/
o: bind
networks:
app-network:
driver: bridge
您的命名卷包括Certbot证书和工作目录卷,以及站点静态资产web-root的卷。在大多数情况下,Docker卷的默认驱动程序是本地驱动程序,在Linux上接受类似于mount命令的选项。多亏了这一点,您可以使用driver_opts指定驱动程序选项列表,将主机上包含应用程序静态资产的views目录挂载到运行时的卷中。然后,目录内容可以在容器之间共享。有关views目录内容的更多信息,请阅读使用Docker构建Node.js应用程序的第2步。
以下是完整的docker-compose.yml文件:
~/node_project/docker-compose.yml 可以被改写为:
~/node_project/docker-compose.yml 文件
version: '3'
services:
nodejs:
build:
context: .
dockerfile: Dockerfile
image: nodejs
container_name: nodejs
restart: unless-stopped
networks:
- app-network
webserver:
image: nginx:mainline-alpine
container_name: webserver
restart: unless-stopped
ports:
- "80:80"
volumes:
- web-root:/var/www/html
- ./nginx-conf:/etc/nginx/conf.d
- certbot-etc:/etc/letsencrypt
- certbot-var:/var/lib/letsencrypt
depends_on:
- nodejs
networks:
- app-network
certbot:
image: certbot/certbot
container_name: certbot
volumes:
- certbot-etc:/etc/letsencrypt
- certbot-var:/var/lib/letsencrypt
- web-root:/var/www/html
depends_on:
- webserver
command: certonly --webroot --webroot-path=/var/www/html --email sammy@your_domain --agree-tos --no-eff-email --staging -d your_domain -d www.your_domain
volumes:
certbot-etc:
certbot-var:
web-root:
driver: local
driver_opts:
type: none
device: /home/sammy/node_project/views/
o: bind
networks:
app-network:
driver: bridge
有了服务定义,您可以开始启动容器并测试您的证书请求。
步骤4 – 获取SSL证书和凭证
您可以使用docker-compose up命令启动容器。这将按照您指定的顺序创建和运行容器和服务。一旦您的域名请求成功,您的证书将被挂载到Web服务器容器的/etc/letsencrypt/live文件夹中。
使用docker-compose up命令,加上-d标志,创建服务,并且在后台运行nodejs和webserver容器。
- docker-compose up -d
您的输出将确认您的服务已被创建。
Creating nodejs … done Creating webserver … done Creating certbot … done
使用docker-compose ps命令来检查您服务的状态。
- docker-compose ps
如果一切顺利的话,你的Node.js和Web服务器服务将会成功运行,并且certbot容器将会以0状态消息退出。
Name Command State Ports ———————————————————————— certbot certbot certonly –webroot … Exit 0 nodejs node app.js Up 8080/tcp webserver nginx -g daemon off; Up 0.0.0.0:80->80/tcp
如果您在nodejs和webserver服务的状态列中注意到除了Up之外的任何内容,或者certbot容器的退出状态不为0,请务必使用docker-compose logs命令检查服务日志。例如,如果您想要检查Certbot日志,可以运行以下命令:
- docker-compose logs certbot
您现在可以使用docker-compose exec命令验证您的凭据是否已挂载到Web服务器容器上。
- docker-compose exec webserver ls -la /etc/letsencrypt/live
一旦您的请求成功,您的输出将显示以下内容:
total 16 drwx—— 3 root root 4096 Dec 23 16:48 . drwxr-xr-x 9 root root 4096 Dec 23 16:48 .. -rw-r–r– 1 root root 740 Dec 23 16:48 README drwxr-xr-x 2 root root 4096 Dec 23 16:48 your_domain
既然你知道你的请求会成功,你可以编辑certbot服务的定义,删除–staging标志。
打开docker-compose.yml文件
- nano docker-compose.yml
找到包含certbot服务定义的文件部分,并将命令选项中的–staging标志替换为–force-renewal标志。这将告诉Certbot您希望使用与现有证书相同的域名请求新证书。certbot服务定义应包含以下定义。
~/node_project/docker-compose.yml“`text
以下是~/node_project/docker-compose.yml的替代描述,只需要一种选项:
“`
~/node_project/docker-compose.yml文件
...
certbot:
image: certbot/certbot
container_name: certbot
volumes:
- certbot-etc:/etc/letsencrypt
- certbot-var:/var/lib/letsencrypt
- web-root:/var/www/html
depends_on:
- webserver
command: certonly --webroot --webroot-path=/var/www/html --email sammy@your_domain --agree-tos --no-eff-email --force-renewal -d your_domain -d www.your_domain
...
当你完成编辑后,保存并退出文件。现在你可以运行docker-compose up来重新创建certbot容器及其相关的卷。通过包含–no-deps选项,你告诉Compose可以跳过启动webserver服务,因为它已经在运行。
- docker-compose up –force-recreate –no-deps certbot
下面的输出表明您的证书请求成功。
Recreating certbot … done Attaching to certbot certbot | Account registered. certbot | Renewing an existing certificate for your_domain and www.your_domain certbot | certbot | Successfully received certificate. certbot | Certificate is saved at: /etc/letsencrypt/live/your_domain/fullchain.pem certbot | Key is saved at: /etc/letsencrypt/live/your_domain phd.com/privkey.pem certbot | This certificate expires on 2022-11-03. certbot | These files will be updated when the certificate renews. certbot | NEXT STEPS: certbot | – The certificate will need to be renewed before it expires. Cert bot can automatically renew the certificate in the background, but you may need to take steps to enable that functionality. See https://certbot.org/renewal-setu p for instructions. certbot | Saving debug log to /var/log/letsencrypt/letsencrypt.log certbot | certbot | – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – certbot | If you like Certbot, please consider supporting our work by: certbot | * Donating to ISRG / Let’s Encrypt: https://letsencrypt.org/do nate certbot | * Donating to EFF: https://eff.org/donate-le certbot | – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – certbot exited with code 0
一旦您获得了证书,您可以进一步修改Nginx配置来添加SSL。
第五步 — 修改Web服务器配置和服务定义
在您的Nginx配置中启用SSL将涉及到添加HTTP重定向到HTTPS,并指定SSL证书和密钥的位置。还需要指定您将用于完美前向保密的Diffie-Hellman组。
既然你打算重新创建网页服务器服务并加入这些新增功能,那你可以现在停止它。
- docker-compose stop webserver
下一步,在您当前的项目目录中为Diffie-Hellman密钥创建一个目录。
- mkdir dhparam
使用openssl命令生成您的密钥。
- sudo openssl dhparam -out /home/sammy/node_project/dhparam/dhparam-2048.pem 2048
生成密钥需要一些时间。
为了在您的Nginx配置中添加相关的Diffie-Hellman和SSL信息,请先删除您之前创建的Nginx配置文件。
- rm nginx-conf/nginx.conf
打开文件的另一个版本。
- nano nginx-conf/nginx.conf
在文件中添加以下代码,将HTTP重定向到HTTPS,并添加SSL凭证、协议和安全头。请记得将your_domain替换为您自己的域名。
~/node_project/nginx-conf/nginx.conf我的回答:
~/node_project/nginx-conf/nginx.conf
server {
listen 80;
listen [::]:80;
server_name your_domain www.your_domain;
location ~ /.well-known/acme-challenge {
allow all;
root /var/www/html;
}
location / {
rewrite ^ https://$host$request_uri? permanent;
}
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name your_domain www.your_domain;
server_tokens off;
ssl_certificate /etc/letsencrypt/live/your_domain/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your_domain/privkey.pem;
ssl_buffer_size 8k;
ssl_dhparam /etc/ssl/certs/dhparam-2048.pem;
ssl_protocols TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;
ssl_ecdh_curve secp384r1;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8;
location / {
try_files $uri @nodejs;
}
location @nodejs {
proxy_pass http://nodejs:8080;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always;
#add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# enable strict transport security only if you understand the implications
}
root /var/www/html;
index index.html index.htm index.nginx-debian.html;
}
HTTP 服务器块指定 Certbot 续订请求的网页根目录为 .well-known/acme-challenge 目录。它还包括一个重写指令,将 HTTP 请求重定向到根目录的 HTTPS。
HTTPS服务器块启用了SSL和HTTP/2。如果想了解更多关于HTTP/2如何迭代HTTP协议以及它对网站性能的好处,请阅读《如何在Ubuntu 18.04上设置带有HTTP/2支持的Nginx》的介绍。此块还包括一系列选项,以确保您使用的是最新的SSL协议和密码以及是否开启OCSP Stapling。OCSP Stapling允许在初始TLS握手过程中提供来自证书授权机构的时间戳响应,这可以加快认证过程。
该区块还可以指定您的SSL和Diffie-Hellman凭证以及密钥文件位置。
最后,你将代理传递的信息移至此区块中,包括一个带有try_files指令的位置区块,将请求指向你的别名化Node.js应用程序容器,并包含一个针对该别名的位置区块,其中包含安全头信息,使你能够在诸如SSL Labs和Security Headers等服务器测试网站上获得“A”级评分。这些头信息包括X-Frame-Options、X-Content-Type-Options、Referrer Policy、Content-Security-Policy和X-XSS-Protection。HTTP Strict Transport Security(HSTS)头信息已被注释掉 – 仅在你理解其影响并评估过其“preload”功能后启用。
当你完成编辑后,保存并关闭文件。
在重新创建网络服务器服务之前,您需要在docker-compose.yml文件中为服务定义添加一些东西,包括HTTPS的相关端口信息和Diffie-Hellman卷定义。
打开文件:
- nano docker-compose.yml
在Web服务器服务定义中,添加以下端口映射和名为dhparam的卷:
~/node_project/docker-compose.yml
...
webserver:
image: nginx:latest
container_name: webserver
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- web-root:/var/www/html
- ./nginx-conf:/etc/nginx/conf.d
- certbot-etc:/etc/letsencrypt
- certbot-var:/var/lib/letsencrypt
- dhparam:/etc/ssl/certs
depends_on:
- nodejs
networks:
- app-network
接下来,在卷定义中添加dhparam卷。记得将sammy和node_project目录替换为与您的目录相匹配的目录。
~/node_project/docker-compose.yml文件的中文版本。
...
volumes:
...
webroot:
...
dhparam:
driver: local
driver_opts:
type: none
device: /home/sammy/node_project/dhparam/
o: bind
与Web根卷类似,dhparam卷将把存储在主机上的Diffie-Hellman密钥挂载到Web服务器容器上。
在编辑完成后保存并关闭文件。
重新创建Web服务器服务
- docker-compose up -d –force-recreate –no-deps webserver
使用docker-compose ps命令检查您的服务。
- docker-compose ps
下面的输出表明您的nodejs和Web服务器服务正在运行。
Name Command State Ports ———————————————————————————————- certbot certbot certonly –webroot … Exit 0 nodejs node app.js Up 8080/tcp webserver nginx -g daemon off; Up 0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp
最后,你可以访问你的域名,以确保一切都能正常工作。在浏览器中打开https://your_domain,并确保将your_domain替换为你自己的域名。

你的浏览器安全指示器中应该出现一个锁定图标。如果你愿意,你可以导航到SSL Labs服务器测试着陆页面或安全标头服务器测试着陆页面。所包括的配置选项应该能够使你的网站在SSL Labs服务器测试中获得A级评分。为了在安全标头服务器测试中获得A级评分,你需要在你的nginx-conf/nginx.conf文件中取消注释Strict Transport Security(HSTS)标头。
~/node_project/nginx-conf/nginx.conf
…
location @nodejs {
proxy_pass http://nodejs:8080;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# enable strict transport security only if you understand the implications
}
…
如果你理解其影响并评估过其“预加载”功能,请开启此选项。
步骤6 — 更新证书
Let’s Encrypt证书的有效期是90天。您可以设置自动更新流程,以确保证书不过期。其中一种方法是利用cron调度工具创建一个作业。您可以使用一个脚本来安排cron作业,该脚本将更新您的证书并重新加载您的Nginx配置。
在您的项目目录中打开一个名为ssl_renew.sh的脚本。
- nano ssl_renew.sh
将以下代码添加到脚本中,以更新您的证书并重新加载您的Web服务器配置。
~/node项目/ssl_renew.sh
#!/bin/bash
COMPOSE="/usr/local/bin/docker-compose --ansi never"
DOCKER="/usr/bin/docker"
cd /home/sammy/node_project/
$COMPOSE run certbot renew --dry-run && $COMPOSE kill -s SIGHUP webserver
$DOCKER system prune -af
此脚本首先将docker-compose二进制文件分配给一个名为COMPOSE的变量,并指定–no-ansi选项,这将在运行docker-compose命令时不使用ANSI控制字符。然后它对docker二进制文件执行相同的操作。最后,它切换到~/node_项目目录并运行以下docker-compose命令。
- docker-compose run: This will start a certbot container and override the command provided in the certbot service definition. Instead of using the certonly subcommand use the renew subcommand, which will renew certificates that are close to expiring. Also included is the –dry-run option to test the script.
- docker-compose kill: This will send a SIGHUP signal to the webserver container to reload the Nginx configuration.
然后运行docker system prune命令以删除所有未使用的容器和镜像。
当你完成编辑后,关闭文件,然后将其设置为可执行。
- chmod +x ssl_renew.sh
接下来,打开您的根 crontab 文件以便在指定的间隔运行续订脚本。
sudo crontab -e
如果这是你第一次编辑这个文件,你将被要求选择一个编辑器。
no crontab for root - using an empty one
Select an editor. To change later, run 'select-editor'.
1. /bin/ed
2. /bin/nano <---- easiest
3. /usr/bin/vim.basic
4. /usr/bin/vim.tiny
Choose 1-4 [2]:
...
请在文件的末尾添加以下一行内容:
...
*/5 * * * * /home/sammy/node_project/ssl_renew.sh >> /var/log/cron.log 2>&1
这将把任务间隔设置为每五分钟一次,这样您就可以测试您的续订请求是否按预期工作。您还创建了一个名为cron.log的日志文件,用于记录任务的相关输出。
5分钟后,检查cron.log以确认续订请求是否成功。
- tail -f /var/log/cron.log
过了一会儿,以下输出信号表示续订成功。
– – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – ** DRY RUN: simulating ‘certbot renew’ close to cert expiry ** (The test certificates below have not been saved.) Congratulations, all renewals succeeded. The following certs have been renewed: /etc/letsencrypt/live/your_domain/fullchain.pem (success) ** DRY RUN: simulating ‘certbot renew’ close to cert expiry ** (The test certificates above have not been saved.) – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – Killing webserver … done
… Congratulations, all simulated renewals succeeded: /etc/letsencrypt/live/your_domain/fullchain.pem (success) – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – Saving debug log to /var/log/letsencrypt/letsencrypt.log Killing webserver … Killing webserver … done Deleted Containers: 00cad94050985261e5b377de43e314b30ad0a6a724189753a9a23ec76488fd78 Total reclaimed space: 824.5kB
在终端中通过输入CTRL + C退出。
现在您可以修改crontab文件以设置每天的时间间隔。例如,要在每天中午运行脚本,您可以修改文件的最后一行如下:
...
0 12 * * * /home/sammy/node_project/ssl_renew.sh >> /var/log/cron.log 2>&1
你也可以从你的ssl_renew.sh脚本中删除–dry-run选项。
#!/bin/bash
COMPOSE="/usr/local/bin/docker-compose --no-ansi"
DOCKER="/usr/bin/docker"
cd /home/sammy/node_project/
$COMPOSE run certbot renew && $COMPOSE kill -s SIGHUP webserver
$DOCKER system prune -af
你的定时任务将确保让我们加密证书在符合条件时进行续订,以防止过期。你还可以使用Logrotate工具设置日志轮换,以轮换和压缩你的日志文件。
结论
你已经使用容器来设置和运行一个Node应用程序,并且安装了Nginx反向代理。你还为应用程序的域名设置了SSL证书,并设置了一个定时任务来在需要时更新这些证书。
如果您对学习更多关于Let’s Encrypt插件感兴趣,请查阅我们关于使用Nginx插件或独立插件的文章。
你还可以通过以下资源了解更多关于Docker Compose的内容。
- How To Install Docker Compose on Ubuntu 18.04.
- How To Configure a Continuous Integration Testing Environment with Docker and Docker Compose on Ubuntu 16.04.
- How To Set Up Laravel, Nginx, and MySQL with Docker Compose.
Compose文档也是学习更多关于多容器应用的绝佳资源。