如何使用 Nginx、Let's Encrypt 和 Docker Compose 保护容器化 Node.js 应用程序的安全

介绍

有多种方法可以提高您的 Node.js应用程序的灵活性和安全性。使用 https://andsky.com/tech/tutorials/digitalocean-community-glossary#reverse-proxyNginx 可以为您提供加载平衡请求、缓存静态内容和实施 Transport Layer Security (TLS) 的能力。在您的服务器上启用加密 HTTPS 可确保您的应用程序的通信保持安全。

例如,如果您正在从 Let's Encrypt获取在服务器上运行的应用程序的证书,则将所需的软件直接安装在您的主机上。 容器允许您采取不同的方法。 使用 Docker Compose,您可以为您的应用程序,您的 Web 服务器和 Certbot 客户端创建容器,这将使您能够获取您的证书。

在本教程中,您将使用 Nginx 反向代理程序部署 Node.js 应用程序,使用 Docker Compose. 您将获得与您的应用程序相关的域的 TLS/SSL 证书,并确保它从 SSL Labs获得高安全级别。

前提条件

要遵循本教程,您将需要:

请阅读此 初始服务器设置指南

一旦你已经设置了一切,你已经准备好开始第一步。

步骤 1 – 克隆和测试节点应用程序

作为第一步,您将用 Node 应用程序代码克隆存储库,其中包括 Dockerfile 以使用 Compose 构建您的应用程序图像,然后您将通过使用 docker run 命令构建和运行该应用程序来测试该应用程序,而无需反向代理或 SSL。

在您的非root用户的主目录中,从 DigitalOcean Community GitHub 帐户克隆 nodejs-image-demo 存储库

将存储库克隆成一个目录 此示例使用node_project作为目录名称. 请随心所欲命名此目录:

1git clone https://github.com/do-community/nodejs-image-demo.git node_project

转到node_project目录:

1cd node_project

在此目录中,有一个 Dockerfile,其中包含使用 Docker node:10 图像和当前项目目录的内容构建 Node 应用程序的说明。

1cat Dockerfile
 1[secondary_label Output]
 2FROM node:10-alpine
 3
 4RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app
 5
 6WORKDIR /home/node/app
 7
 8COPY package*.json ./
 9
10USER node
11
12RUN npm install
13
14COPY --chown=node:node . .
15
16EXPOSE 8080
17
18CMD [ "node", "app.js" ]

这些指令通过将项目代码从当前目录复制到容器,并在npm install中安装依赖性来构建一个节点图像。它们还利用Docker(https://andsky.com/tech/tutorials/building-optimized-containers-for-kubernetes#managing-container-layers)的[缓存和图像叠加]功能,将包含项目列出的依赖性的package.jsonpackage-lock.json的副本从应用程序代码的其余副本中分离开来。

有关此 Dockerfile 和 Node 图像最佳实践的更多信息,请参阅 如何使用 Docker 构建 Node.js 应用程序中的完整讨论。

要测试应用程序而无需 SSL,您可以使用 docker build-t 旗帜来构建和标记图像。

1docker build -t node-demo .

一旦构建过程完成,您可以将您的图像列为 docker images:

1docker images

下面的输出确认了应用程序图像构建:

1[secondary_label Output]
2REPOSITORY TAG IMAGE ID CREATED SIZE
3node-demo latest 23961524051d 7 seconds ago 73MB
4node 10-alpine 8a752d5af4ce 3 weeks ago 70.7MB

接下来,创建用docker run的容器. 此命令包含三个旗帜:

  • -p:此文将该端口发布到容器上,并将其映射到主机上的端口中。您将在本示例中使用主机上的端口 `80,但如果您在该端口上运行另一个流程,则可以随时修改该端口。

运行以下命令来构建容器:

1docker run --name node-demo -p 80:8080 -d node-demo

检查您的运行容器用 docker ps :

1docker ps

下面的输出确认您的应用程序容器正在运行:

1[secondary_label Output]
2CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
34133b72391da 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。 您的应用程序将显示以下定位页面:

Application Landing Page

现在你已经测试了应用程序,你可以停止容器并删除图像. 使用docker ps获取你的CONTAINER ID:

1docker ps
1[secondary_label Output]
2CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
34133b72391da node-demo           "node app.js"       17 seconds ago Up 16 seconds 0.0.0.0:80->8080/tcp node-demo

请确保将这里列出的CONTAINER ID替换为自己的应用程序CONTAINER ID:

1docker stop 4133b72391da

您现在可以删除已停止的容器和所有图像,包括未使用的图像和悬浮图像,使用 docker system prune-a 旗帜:

1docker system prune -a

在输出中提示时按y,以确认您希望删除停止的容器和图像。

测试应用程序图像后,您可以继续使用 Docker Compose 构建其余的设置。

步骤 2 – 定义 Web 服务器配置

有了我们的应用程序Dockerfile,您将创建一个配置文件来运行您的Nginx容器. 您可以从一个最小的配置开始,该配置将包括您的域名, 文档根,代理信息,以及一个位置块,以将Certbot的请求导向已知目录,在那里它将放置一个临时文件来验证您的域名的DNS解决到您的服务器。

首先,在当前项目目录中创建一个目录,即node_project,用于配置文件:

1mkdir nginx-conf

创建并使用nano或您最喜欢的编辑器打开文件:

1nano nginx-conf/nginx.conf

将以下服务器块添加到您的 Node 应用程序容器中的代理用户请求中,并将 Certbot 的请求导向到 .well-known 目录中。

 1[label ~/node_project/nginx-conf/nginx.conf]
 2server {
 3        listen 80;
 4        listen [::]:80;
 5
 6        root /var/www/html;
 7        index index.html index.htm index.nginx-debian.html;
 8
 9        server_name your_domain www.your_domain;
10
11        location / {
12                proxy_pass http://nodejs:8080;
13        }
14
15        location ~ /.well-known/acme-challenge {
16                allow all;
17                root /var/www/html;
18        }
19}

此服务器块将允许您启动 Nginx 容器作为反向代理,它将向您的 Node 应用容器传输请求。它还允许您使用 Certbot 的 webroot 插件来获取您的域的证书。这个插件取决于 HTTP-01 验证方法,它使用 HTTP 请求来证明 Certbot 可以从响应给定域名服务器访问资源。

完成编辑后,保存并关闭文件. 如果您使用了nano,您可以通过按CTRL + X,然后按YENTER来做到这一点。 有关 Nginx 服务器和位置封锁算法的更多信息,请参阅本文《理解 Nginx 服务器和位置封锁选择算法》(https://andsky.com/tech/tutorials/understanding-nginx-server-and-location-block-selection-algorithms)。

有了Web服务器配置详细信息,您可以继续创建您的docker-compose.yml文件,这将允许您创建您的应用服务和您将使用的Certbot容器来获得您的证书。

步骤 3 – 创建 Docker 组件文件

docker-compose.yml 文件将定义您的服务,包括 Node 应用程序和 Web 服务器. 它将指定详细信息,如命名卷,这将对在容器之间共享 SSL 凭证以及网络和端口信息至关重要。

创建并在当前目录中打开文件:

1nano docker-compose.yml

首先,定义应用服务:

 1[label ~/node_project/docker-compose.yml]
 2version: '3'
 3
 4services:
 5  nodejs:
 6    build:
 7      context: .
 8      dockerfile: Dockerfile
 9    image: nodejs
10    container_name: nodejs
11    restart: unless-stopped

nodejs服务的定义包括以下内容:

  • build:这定义了配置选项,包括 contextdockerfile,这些选项将在 Compose 构建应用程序图像时应用。 如果您想从像 Docker Hub这样的注册表中使用现有图像,则可以使用 image 指令相反,包含有关您的用户名、存储库和图像标签的信息
  • context:这定义了应用程序图像构建的构建文档。

请注意,您在本服务中不包括绑定安装,因为您的设置是专注于部署而不是开发。

要允许应用程序和 Web 服务器容器之间的通信,在重新启动定义后添加一个名为app-network的桥梁网络:

1[label ~/node_project/docker-compose.yml]
2services:
3  nodejs:
4...
5    networks:
6      - app-network

像这样的用户定义的桥梁网络允许在同一 Docker daemon 主机上的容器之间进行通信. 这简化了应用程序内部的流量和通信,因为它打开了同一桥梁网络上的容器之间的所有端口,同时不会向外部世界暴露任何端口。

接下来,定义Web服务器服务:

 1[label ~/node_project/docker-compose.yml]
 2...
 3 webserver:
 4    image: nginx:mainline-alpine
 5    container_name: webserver
 6    restart: unless-stopped
 7    ports:
 8      - "80:80"
 9    volumes:
10      - web-root:/var/www/html
11      - ./nginx-conf:/etc/nginx/conf.d
12      - certbot-etc:/etc/letsencrypt
13      - certbot-var:/var/lib/letsencrypt
14    depends_on:
15      - nodejs
16    networks:
17      - app-network

对于nodejs服务,这里定义的某些设置仍然相同,但已进行以下一些更改:

下列命名的卷和束缚装配也被指定:

  • web-root:/var/www/html:这将添加您的网站的静态资产,复制到称为 web-root的卷,到容器上的 /var/www/html 目录
  • ./nginx-conf:/etc/nginx/letcrypt:这将连接到主机上的 Nginx 配置目录到容器上的相应目录,确保您对主机上的文件的任何更改都会反映在容器中。

接下来,添加certbot容器的配置选项. 请确保用自己的域名和联系电子邮件更换域名和电子邮件信息:

 1[label ~/node_project/docker-compose.yml]
 2...
 3  certbot:
 4    image: certbot/certbot
 5    container_name: certbot
 6    volumes:
 7      - certbot-etc:/etc/letsencrypt
 8      - certbot-var:/var/lib/letsencrypt
 9      - web-root:/var/www/html
10    depends_on:
11      - webserver
12    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 中的域证书和密钥,在 certbot-var 中的 Let's Encrypt 工作目录,以及在 `web-root' 中的应用程序代码。

再次,您使用了depends_on来指定certbot容器应该在webserver服务运行后启动。

命令选项指定在启动容器时要运行的命令. 它包括certonly子命令,具有以下选项:

  • " 网根 " : 这告诉 Certbot 使用 Webroot 插件将文件放入webroot 文件夹进行认证. (_ ( )* 网根路-路径': 在此指定 Webroot 目录的路径 。 (_) ( )* 电子邮件 ' :您喜欢的用于登记和恢复的电子邮件。 (_) ( )* `同意 ' : 此处指定您同意 [ACME的订户协议] (https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf).
  • -不-不-eff-email': 这告诉 Certbot, 您不想与 [电子边境基金会] (https://www.eff.org/ (EFF) 共享您的电子邮件 。 您可以随意省略这个。 (_ ( )* -- stage': 这告诉Certbot,你想要使用Let's Enterpressing的环境来获得测试证书. 使用此选项可以测试您的配置选项并避免可能的域请求限制. 关于这些限制的更多信息,请读作让我们加密速率限制文档
  • -d': 这使得您可以指定您想要应用到您的请求中的域名 。 在这种情况下,你包括你的域'和`www.your_domain'。 请确定用您自己的域替换这些域 。 (_) (英语)

作为最后一步,添加音量和网络定义. 请确保将用户名替换为您自己的非root用户:

 1[label ~/node_project/docker-compose.yml]
 2...
 3volumes:
 4  certbot-etc:
 5  certbot-var:
 6  web-root:
 7    driver: local
 8    driver_opts:
 9      type: none
10      device: /home/sammy/node_project/views/
11      o: bind
12
13networks:
14  app-network:
15    driver: bridge

您的命名卷包括您的 Certbot 证书和工作目录卷,以及您网站的静态资产web-root的卷。在大多数情况下,Docker 卷的默认驱动程序是本地驱动程序,在Linux上它接受类似于mount命令(http://man7.org/linux/man-pages/man8/mount.8.html)的选项。由于此,您可以用driver_opts指定一个列表的驱动程序选项,这些选项将主机上的Views目录,其中包含您的应用程序的静态资产,安装在运行时的卷上。 然后,目录内容可以在容器之间共享。 有关Views目录的内容的更多信息,请阅读How To Build a Node.js Application with Docker(https://andsky.com/tech/tutorials/how-to-build-a-node-js-application-with-docker#step-2-creating-the-application-files)。

以下是完整的 docker-compose.yml 文件:

 1[label ~/node_project/docker-compose.yml]
 2version: '3'
 3
 4services:
 5  nodejs:
 6    build:
 7      context: .
 8      dockerfile: Dockerfile
 9    image: nodejs
10    container_name: nodejs
11    restart: unless-stopped
12    networks:
13      - app-network
14
15  webserver:
16    image: nginx:mainline-alpine
17    container_name: webserver
18    restart: unless-stopped
19    ports:
20      - "80:80"
21    volumes:
22      - web-root:/var/www/html
23      - ./nginx-conf:/etc/nginx/conf.d
24      - certbot-etc:/etc/letsencrypt
25      - certbot-var:/var/lib/letsencrypt
26    depends_on:
27      - nodejs
28    networks:
29      - app-network
30
31  certbot:
32    image: certbot/certbot
33    container_name: certbot
34    volumes:
35      - certbot-etc:/etc/letsencrypt
36      - certbot-var:/var/lib/letsencrypt
37      - web-root:/var/www/html
38    depends_on:
39      - webserver
40    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 
41
42volumes:
43  certbot-etc:
44  certbot-var:
45  web-root:
46    driver: local
47    driver_opts:
48      type: none
49      device: /home/sammy/node_project/views/
50      o: bind
51
52networks:
53  app-network:
54    driver: bridge

有了服务定义,您已经准备好启动容器并测试您的证书请求。

步骤 4 – 获取SSL证书和凭证

您可以使用 docker-compose up开始集装箱。这将创建和运行您的集装箱和服务,以您指定的顺序。一旦您的域请求成功,您的证书将被安装在webserver集装箱上的/etc/letsencrypt/live文件夹中。

创建docker-compose up的服务,使用-d旗帜,在背景中运行nodejswebserver容器:

1docker-compose up -d

您的输出将确认您的服务已经创建:

1[secondary_label Output]
2Creating nodejs ... done
3Creating webserver ... done
4Creating certbot   ... done

使用 docker-compose ps来检查您的服务的状态:

1docker-compose ps

如果一切顺利,你的nodejswebserver服务将是Up,而certbot容器将以0状态消息离开:

1[secondary_label Output]
2  Name Command State Ports
3------------------------------------------------------------------------
4certbot certbot certonly --webroot ... Exit 0
5nodejs node app.js Up 8080/tcp
6webserver nginx -g daemon off;             Up 0.0.0.0:80->80/tcp

如果您在NodejsWebserver服务的状态列中看到Up以外的任何东西,或者在certbot容器中看到0以外的输出状态,请确保使用docker-compose logs(https://docs.docker.com/compose/reference/logs/)命令检查服务日志。

1docker-compose logs certbot

现在您可以检查您的身份证是否已安装在webserver容器上,使用 docker-compose exec:

1docker-compose exec webserver ls -la /etc/letsencrypt/live

一旦您的请求成功,您的输出将显示如下:

1[secondary_label Output]
2total 16
3drwx------ 3 root root 4096 Dec 23 16:48 .
4drwxr-xr-x 9 root root 4096 Dec 23 16:48 ..
5-rw-r--r-- 1 root root 740 Dec 23 16:48 README
6drwxr-xr-x 2 root root 4096 Dec 23 16:48 your_domain

现在您知道您的请求将成功,您可以编辑certbot服务定义,以删除--staging旗帜。

打开docker-compose.yml文件:

1nano docker-compose.yml

查找包含certbot服务定义的文件部分,然后在命令选项中代替--staging旗帜以--force-renewal旗帜。

 1[label ~/node_project/docker-compose.yml]
 2...
 3  certbot:
 4    image: certbot/certbot
 5    container_name: certbot
 6    volumes:
 7      - certbot-etc:/etc/letsencrypt
 8      - certbot-var:/var/lib/letsencrypt
 9      - web-root:/var/www/html
10    depends_on:
11      - webserver
12    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
13...

完成编辑后,保存并退出文件. 你现在可以运行docker-compose up来重建certbot容器及其相关卷. 通过包括--no-deps选项,你告诉Compose它可以跳过启动webserver服务,因为它已经在运行:

1docker-compose up --force-recreate --no-deps certbot

以下输出表示您的证书请求成功:

 1[secondary_label Output]
 2Recreating certbot ... done
 3Attaching to certbot
 4certbot      | Account registered.
 5certbot      | Renewing an existing certificate for your_domain and www.your_domain
 6certbot      |
 7certbot      | Successfully received certificate.
 8certbot      | Certificate is saved at: /etc/letsencrypt/live/your_domain/fullchain.pem
 9certbot      | Key is saved at:         /etc/letsencrypt/live/your_domain phd.com/privkey.pem
10certbot      | This certificate expires on 2022-11-03.
11certbot      | These files will be updated when the certificate renews.
12certbot      | NEXT STEPS:
13certbot      | - 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.
14certbot      | Saving debug log to /var/log/letsencrypt/letsencrypt.log
15certbot      |
16certbot      | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -                                - - - - - - -
17certbot      | If you like Certbot, please consider supporting our work by:
18certbot      |  * Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/do nate
19certbot      |  * Donating to EFF:                    https://eff.org/donate-le
20certbot      | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -                                - - - - - - -
21certbot exited with code 0

有了您的证书,您可以继续修改您的 Nginx 配置以包括 SSL。

步骤 5 — 更改 Web 服务器配置和服务定义

在您的 Nginx 配置中启用 SSL 将包括将 HTTP 重定向添加到 HTTPS 并指定您的 SSL 证书和关键位置。

由于您将重新创建Web服务器服务以包括这些添加,您现在可以停止它:

1docker-compose stop webserver

接下来,在当前项目目录中为 Diffie-Hellman 密钥创建一个目录:

1mkdir dhparam

用你的密钥创建 openssl 命令:

1sudo openssl dhparam -out /home/sammy/node_project/dhparam/dhparam-2048.pem 2048

需要几分钟才能生成钥匙。

若要将相关的 Diffie-Hellman 和 SSL 信息添加到您的 Nginx 配置中,请先删除您之前创建的 Nginx 配置文件:

1rm nginx-conf/nginx.conf

打开文件的另一个版本:

1nano nginx-conf/nginx.conf

将下列代码添加到文件中,以将 HTTP 重定向到 HTTPS,并添加 SSL 凭证、协议和安全标题。

 1[label ~/node_project/nginx-conf/nginx.conf]
 2
 3server {
 4        listen 80;
 5        listen [::]:80;
 6        server_name your_domain www.your_domain;
 7
 8        location ~ /.well-known/acme-challenge {
 9          allow all;
10          root /var/www/html;
11        }
12
13        location / {
14                rewrite ^ https://$host$request_uri? permanent;
15        }
16}
17
18server {
19        listen 443 ssl http2;
20        listen [::]:443 ssl http2;
21        server_name your_domain www.your_domain;
22
23        server_tokens off;
24
25        ssl_certificate /etc/letsencrypt/live/your_domain/fullchain.pem;
26        ssl_certificate_key /etc/letsencrypt/live/your_domain/privkey.pem;
27
28        ssl_buffer_size 8k;
29
30        ssl_dhparam /etc/ssl/certs/dhparam-2048.pem;
31
32        ssl_protocols TLSv1.2;
33        ssl_prefer_server_ciphers on;
34
35        ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;
36
37        ssl_ecdh_curve secp384r1;
38        ssl_session_tickets off;
39
40        ssl_stapling on;
41        ssl_stapling_verify on;
42        resolver 8.8.8.8;
43
44        location / {
45                try_files $uri @nodejs;
46        }
47
48        location @nodejs {
49                proxy_pass http://nodejs:8080;
50                add_header X-Frame-Options "SAMEORIGIN" always;
51                add_header X-XSS-Protection "1; mode=block" always;
52                add_header X-Content-Type-Options "nosniff" always;
53                add_header Referrer-Policy "no-referrer-when-downgrade" always;
54                add_header Content-Security-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always;
55                #add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
56                # enable strict transport security only if you understand the implications
57        }
58
59        root /var/www/html;
60        index index.html index.htm index.nginx-debian.html;
61}

HTTP 服务器块将 Certbot 更新请求的 webroot 指定到 .well-known/acme-challenge 目录,还包括一个 重写指令,该目录将 HTTP 请求转移到 root 目录到 HTTPS。

HTTPS 服务器块允许sslhttp2。 有关 HTTP/2 如何重复 HTTP 协议以及它对网站性能的益处的更多信息,请参阅 How To Set Up Nginx with HTTP/2 Support on Ubuntu 18.04的介绍)。 该块还包括一系列选项,以确保您使用最新的 SSL 协议和加密器,并启用 OSCP 堆积。

该块还指定您的 SSL 和 Diffie-Hellman 凭证和关键位置。

最后,你已经将代理传输信息移动到这个区块,包括一个位置区块与一个 try_files]指令,指向请求到你的称Node.js应用容器,以及一个位置区块,该区块包括安全标题,将允许你得到 A的评级,如 SSL LabsSecurity Headers服务器测试站点。这些标题包括 X-Frame-Options, X-Content-Type-Options, Referrer Policy, [Content-Security-Policy(LINK6]),和 [`X-X-SS-Pro

完成编辑后,保存并关闭文件。

在重建网页服务器服务之前,您需要在您的docker-compose.yml文件中添加一些服务定义,包括有关 HTTPS 端口信息和 Diffie-Hellman 卷定义。

打开文件:

1nano docker-compose.yml

webserver服务定义中,添加以下端口绘制和命名为dhparam的卷:

 1[label ~/node_project/docker-compose.yml]
 2...
 3 webserver:
 4    image: nginx:latest
 5    container_name: webserver
 6    restart: unless-stopped
 7    ports:
 8      - "80:80"
 9      - "443:443"
10    volumes:
11      - web-root:/var/www/html
12      - ./nginx-conf:/etc/nginx/conf.d
13      - certbot-etc:/etc/letsencrypt
14      - certbot-var:/var/lib/letsencrypt
15      - dhparam:/etc/ssl/certs
16    depends_on:
17      - nodejs
18    networks:
19      - app-network

接下来,将dhparam卷添加到您的volumes定义中,请记住将sammynode_project目录替换为匹配您的目录:

 1[label ~/node_project/docker-compose.yml]
 2...
 3volumes:
 4  ...
 5  webroot:
 6  ...
 7  dhparam:
 8    driver: local
 9    driver_opts:
10      type: none
11      device: /home/sammy/node_project/dhparam/
12      o: bind

类似于web-root卷,dhparam卷将存储在主机上的Diffie-Hellman密钥插入到webserver容器。

保存并关闭文件,当你完成编辑。

重建Web服务器服务:

1docker-compose up -d --force-recreate --no-deps webserver

点击查看docker-compose ps的服务:

1docker-compose ps

以下输出表示您的nodejswebserver服务正在运行:

1[secondary_label Output]
2  Name Command State Ports
3----------------------------------------------------------------------------------------------
4certbot certbot certonly --webroot ... Exit 0
5nodejs node app.js Up 8080/tcp
6webserver nginx -g daemon off;             Up 0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp

最后,您可以访问您的域,以确保一切按预期运行。 导航您的浏览器到 https://your_domain,确保您用自己的域名替换 your_domain:

Application Landing Page

如果您想要,您可以导航到 SSL Labs Server Test landing pageSecurity Headers server test landing page. 包含的配置选项应该使您的网站在 SSL Labs Server Test 中获得 A评级。 为了在 Security Headers 服务器测试中获得 A评级,您需要在您的 nginx-conf/nginx.conf 文件中删除 Strict Transport Security (HSTS) 标题:

 1[label ~/node_project/nginx-conf/nginx.conf]
 2
 3location @nodejs {
 4                proxy_pass http://nodejs:8080;
 5                add_header X-Frame-Options "SAMEORIGIN" always;
 6                add_header X-XSS-Protection "1; mode=block" always;
 7                add_header X-Content-Type-Options "nosniff" always;
 8                add_header Referrer-Policy "no-referrer-when-downgrade" always;
 9                add_header Content-Security-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always;
10                add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
11                # enable strict transport security only if you understand the implications
12        }
13

再次,仅在您理解后果并评估其 重新加载功能时才启用此选项。

第6步:更新证书

Let's Encrypt 证书有效期为 90 天. 您可以设置一个自动更新过程,以确保它们不会过期。 这样做的一种方法是使用cron 编程工具创建工作。 您可以使用将您的证书更新并重新加载您的 Nginx 配置的脚本来安排一个cron 工作。

在您的项目目录中打开名为 ssl_renew.sh 的脚本:

1nano ssl_renew.sh

将以下代码添加到脚本中,以更新证书并重新加载 Web 服务器配置:

1[label ~/node_project/ssl_renew.sh]
2#!/bin/bash
3
4COMPOSE="/usr/local/bin/docker-compose --ansi never"
5DOCKER="/usr/bin/docker"
6
7cd /home/sammy/node_project/
8$COMPOSE run certbot renew --dry-run && $COMPOSE kill -s SIGHUP webserver
9$DOCKER system prune -af

此脚本首先将docker-compose二进制分配给一个名为COMPOSE的变量,并指定了--no-ansi选项,该选项将运行docker-compose命令而无 ANSI 控制字符

  • docker-compose run:这将启动一个 certbot 容器,并超出在 certbot 服务定义中提供的 命令。 使用 certonly子命令而不是使用renew子命令,这将更新即将到期的证书。 还包含了--dry-run` 选项来测试脚本
  • docker-compose kill:这将向 webserver 容器发送一个 SIGHUP 信号来重新加载 Nginx 配置

然后运行 docker system prune来删除所有未使用的容器和图像。

完成编辑后关闭文件,然后使其可执行:

1chmod +x ssl_renew.sh

接下来,打开您的 root crontab 文件以在指定间隔运行更新脚本:

1sudo crontab -e

如果这是你第一次编辑这个文件,你将被要求选择一个编辑器:

1[label crontab]
2no crontab for root - using an empty one
3Select an editor. To change later, run 'select-editor'.
4  1. /bin/ed
5  2. /bin/nano        <---- easiest
6  3. /usr/bin/vim.basic
7  4. /usr/bin/vim.tiny
8Choose 1-4 [2]: 
9...

在文件的末尾,添加以下行:

1[label crontab]
2...
3*/5 * * * * /home/sammy/node_project/ssl_renew.sh >> /var/log/cron.log 2>&1

这会将工作间隔设置为每五分钟,以便您可以测试您的更新请求是否按预期工作,您还创建了一个日志文件,‘cron.log’,以记录工作中的相关输出。

五分钟后,检查cron.log,确认更新请求是否成功:

1tail -f /var/log/cron.log

几秒钟后,以下输出表示成功更新:

 1[secondary_label Output]
 2- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 3** DRY RUN: simulating 'certbot renew' close to cert expiry
 4**          (The test certificates below have not been saved.)
 5
 6Congratulations, all renewals succeeded. The following certs have been renewed:
 7  /etc/letsencrypt/live/your_domain/fullchain.pem (success)
 8** DRY RUN: simulating 'certbot renew' close to cert expiry
 9**          (The test certificates above have not been saved.)
10- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
11Killing webserver ... done
 1[secondary_label Output]
 2
 3Congratulations, all simulated renewals succeeded: 
 4  /etc/letsencrypt/live/your_domain/fullchain.pem (success)
 5- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 6Saving debug log to /var/log/letsencrypt/letsencrypt.log
 7Killing webserver ... 
 8Killing webserver ... done
 9Deleted Containers:
1000cad94050985261e5b377de43e314b30ad0a6a724189753a9a23ec76488fd78
11
12Total reclaimed space: 824.5kB

在您的终端中输入CTRL + C

例如,要在中午每天运行脚本,你可以修改文件的最后一行,如下:

1[label crontab]
2...
30 12 * * * /home/sammy/node_project/ssl_renew.sh >> /var/log/cron.log 2>&1

您也可以从您的ssl_renew.sh脚本中删除--dry-run选项:

1[label ~/node_project/ssl_renew.sh]
2#!/bin/bash
3
4COMPOSE="/usr/local/bin/docker-compose --no-ansi"
5DOCKER="/usr/bin/docker"
6
7cd /home/sammy/node_project/
8$COMPOSE run certbot renew && $COMPOSE kill -s SIGHUP webserver
9$DOCKER system prune -af

你的cron工作将确保你的 Let's Encrypt 证书不会过期,当它们符合条件时,你也可以 设置 Logrotate 实用程序的日志旋转来旋转和压缩你的日志文件。

结论

您已使用集装箱来设置和运行一个 Node 应用程序,使用 Nginx 反向代理,您还为您的应用程序域设置了 SSL 证书,并在需要时设置了cron工作来更新这些证书。

如果您有兴趣了解更多关于 Let’s Encrypt 插件的信息,请查看我们关于使用 Nginx 插件独立插件的文章。

您还可以通过以下资源了解更多关于 Docker Compose 的信息:

The Compose documentation也是学习更多关于多容器应用的绝佳资源。

Published At
Categories with 技术
comments powered by Disqus