如何在运行 NGINX Docker 容器的 AWS EC2 上启用 HTTPS? [英] How to enable HTTPS on AWS EC2 running an NGINX Docker container?

查看:35
本文介绍了如何在运行 NGINX Docker 容器的 AWS EC2 上启用 HTTPS?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 AWS 上有一个运行 Amazon Linux 2 的 EC2 实例.

I have an EC2 instance on AWS that runs Amazon Linux 2.

在上面,我安装了 Git、docker 和 docker-compose.完成后,我克隆了我的存储库并运行 docker-compose up 来启动我的生产环境.我转到公共 DNS,它可以工作.

On it, I installed Git, docker, and docker-compose. Once done, I cloned my repository and ran docker-compose up to get my production environment up. I go to the public DNS, and it works.

我现在想在网站上启用 HTTPS.

I now want to enable HTTPS onto the site.

我的项目有一个前端,使用 React 在 Nginx-alpine 服务器上运行.后端是一个 NodeJS 服务器.

My project has a frontend using React to run on an Nginx-alpine server. The backend is a NodeJS server.

这是我的 nginx.conf 文件:

This is my nginx.conf file:

server {
    listen       80;
    server_name  localhost;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
        try_files $uri /index.html;
    }

    location /api/ {
        proxy_pass http://${PROJECT_NAME}_backend:${NODE_PORT}/;
    }    

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

这是我的 docker-compose.yml 文件:

Here's my docker-compose.yml file:

version: "3.7"
services:
##############################
# Back-End Container
##############################
  backend: # Node-Express backend that acts as an API.
    container_name: ${PROJECT_NAME}_backend
    init: true
    build:
      context: ./backend/
      target: production
    restart: always
    environment:
      - NODE_PATH=${EXPRESS_NODE_PATH}
      - AWS_REGION=${AWS_REGION}
      - NODE_ENV=production
      - DOCKER_BUILDKIT=1
      - PORT=${NODE_PORT}
    networks:
      - client
##############################
# Front-End Container
##############################
  nginx:
    container_name: ${PROJECT_NAME}_frontend
    build:
      context: ./frontend/
      target: production
      args:
        - NODE_PATH=${REACT_NODE_PATH}
        - SASS_PATH=${SASS_PATH}
    restart: always
    environment:
      - PROJECT_NAME=${PROJECT_NAME}
      - NODE_PORT=${NODE_PORT}
      - DOCKER_BUILDKIT=1
    command: /bin/ash -c "envsubst '$$PROJECT_NAME $$NODE_PORT' < /etc/nginx/conf.d/nginx.template > /etc/nginx/conf.d/default.conf && exec nginx -g 'daemon off;'"
    expose:
      - "80"
    ports:
      - "80:80"
    depends_on:
      - backend
    networks:
      - client
##############################
# General Config
##############################
networks:
  client:

我知道 certbot 有一个 Docker 映像,但我不确定如何使用它.我还担心我通过 http 将对 /api/ 的请求代理到服务器的方式.这也会给我带来任何问题吗?

I know there's a Docker image for certbot, but I'm not sure how to use it. I'm also worried about the way I'm proxying requests to /api/ to the server over http. Will that also give me any problems?

尝试 #1:Traefik

Attempt #1: Traefik

我创建了一个 Traefik 容器来通过 HTTPS 路由所有流量.

I created a Traefik container to route all traffic through HTTPS.

version: '2'

services:
  traefik:
    image: traefik
    restart: always
    ports:
      - 80:80
      - 443:443
    networks:
      - web
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /opt/traefik/traefik.toml:/traefik.toml
      - /opt/traefik/acme.json:/acme.json
    container_name: traefik

networks:
  web:
    external: true

对于 toml 文件,我添加了以下内容:

For the toml file, I added the following:

debug = false

logLevel = "ERROR"
defaultEntryPoints = ["https","http"]

[entryPoints]
  [entryPoints.http]
  address = ":80"
    [entryPoints.http.redirect]
    entryPoint = "https"
  [entryPoints.https]
  address = ":443"
  [entryPoints.https.tls]

[retry]

[docker]
endpoint = "unix:///var/run/docker.sock"
domain = "ec2-00-000-000-00.eu-west-1.compute.amazonaws.com"
watch = true
exposedByDefault = false

[acme]
storage = "acme.json"
entryPoint = "https"
onHostRule = true
[acme.httpChallenge]
entryPoint = "http"

我将此添加到我的 docker-compose 生产文件中:

I added this to my docker-compose production file:

labels:
  - "traefik.docker.network=web"
  - "traefik.enable=true"
  - "traefik.basic.frontend.rule=Host:ec2-00-000-000-00.eu-west-1.compute.amazonaws.com"
  - "traefik.basic.port=80"
  - "traefik.basic.protocol=https"

我为 Traefik 容器运行了 docker-compose up,然后在我的生产映像上运行了 docker-compose up.我收到以下错误:

I ran docker-compose up for the Traefik container, and then ran docker-compose up on my production image. I got the following error:

无法获得 acme 证书

unable to obtain acme certificate

我正在阅读 Traefik 文档,显然有一种方法可以专门为 Amazon ECS 配置 toml 文件:https://docs.traefik.io/configuration/backends/ecs/

I'm reading the Traefik docs and apparently there's a way to configure the toml file specifically for Amazon ECS: https://docs.traefik.io/configuration/backends/ecs/

我在正确的轨道上吗?

推荐答案

启用 SSL 是通过遵循 上的教程完成的Nginx 和让我们在不到 5 分钟的时间内使用 Docker 加密.我在关注它的过程中遇到了一些问题,所以我会在这里尝试澄清一些事情.

Enabling SSL is done through following the tutorial on Nginx and Let's Encrypt with Docker in Less Than 5 Minutes. I ran into some issues while following it, so I will try to clarify some things here.

步骤包括将以下内容添加到docker-compose.yml:

The steps include adding the following to the docker-compose.yml:

##############################
# Certbot Container
##############################
  certbot:
    image: certbot/certbot:latest
    volumes:
      - ./frontend/data/certbot/conf:/etc/letsencrypt
      - ./frontend/data/certbot/www:/var/www/certbot

至于 docker-compose.ymlNginx Container 部分,应该修改它以包括添加到 Certbot Container,以及添加端口和公开配置:

As for the Nginx Container section of the docker-compose.yml, it should be amended to include the same volumes added to the Certbot Container, as well as add the ports and expose configurations:

  service_name:
    container_name: container_name
    image: nginx:alpine
    command: /bin/ash -c "exec nginx -g 'daemon off;'"
    volumes:
      - ./data/certbot/conf:/etc/letsencrypt
      - ./data/certbot/www:/var/www/certbot
    expose:
      - "80"
      - "443"
    ports:
      - "80:80"
      - "443:443"
    networks:
      - default

data 文件夹可以保存在其他任何地方,但请确保知道它在哪里,并确保在以后重用时正确引用它.在这个例子中,我只是将它保存在与 docker-compose.yml 文件相同的目录中.

The data folder may be saved anywhere else, but make sure to know where it is and make sure to reference it properly when reused later. In this example, I am simply saving it in the same directory as the docker-compose.yml file.

上述配置到位后,需要执行几个步骤来初始化证书的颁发.

Once the above configurations are put into place, a couple of steps are to be taken in order to initialize the issuance of the certificates.

首先,您的 Nginx 配置 (default.conf) 将被更改以适应域验证请求:

Firstly, your Nginx configuration (default.conf) is to be changed to accommodate the domain verification request:

server {
    listen       80;
    server_name example.com www.example.com;
    server_tokens off;

    location / {
        return 301 https://$server_name$request_uri;
    }

    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }
}

server {
     listen 443 ssl;
     server_name example.com www.example.com;
     server_tokens off;

     ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
     ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
     include /etc/letsencrypt/options-ssl-nginx.conf;
     ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

     location / {
         root   /usr/share/nginx/html;
         index  index.html index.htm;
         try_files $uri /index.html;
         proxy_set_header    Host                $http_host;
         proxy_set_header    X-Real-IP           $remote_addr;
         proxy_set_header    X-Forwarded-For     $proxy_add_x_forwarded_for;
     }
}

修改 Nginx 配置文件后,将创建一个虚拟证书,以允许进行 Let's Encrypt 验证.有一个脚本可以自动执行所有这些操作,在修改以适应环境之前,可以使用 CURL 将其下载到项目的根目录中.还需要使用 chmod 命令使脚本可执行:

Once the Nginx configuration file is amended, a dummy certificate is created to allow for Let's Encrypt validation to take place. There is a script that does all of this automatically, which can be downloaded, into the root of the project, using CURL, before being amended to suit the environment. The script would also need to be made executable using the chmod command:

curl -L https://raw.githubusercontent.com/wmnnd/nginx-certbot/master/init-letsencrypt.sh > init-letsencrypt.sh && chmod +x init-letsencrypt.sh

脚本下载后,修改如下:

Once the script is downloaded, it is to be amended as follows:

#!/bin/bash

if ! [ -x "$(command -v docker-compose)" ]; then
  echo 'Error: docker-compose is not installed.' >&2
  exit 1
fi

-domains=(example.org www.example.org)
+domains=(example.com www.example.com)
rsa_key_size=4096
-data_path="./data/certbot"
+data_path="./data/certbot"
-email="" # Adding a valid address is strongly recommended
+email="admin@example.com" # Adding a valid address is strongly recommended
staging=0 # Set to 1 when testing setup to avoid hitting request limits

if [ -d "$data_path" ]; then
  read -p "Existing data found for $domains. Continue and replace existing certificate? (y/N) " decision
  if [ "$decision" != "Y" ] && [ "$decision" != "y" ]; then
    exit
  fi
fi

if [ ! -e "$data_path/conf/options-ssl-nginx.conf" ] || [ ! -e "$data_path/conf/ssl-dhparams.pem" ]; then
  echo "### Downloading recommended TLS parameters ..."
  mkdir -p "$data_path/conf"
  curl -s https://raw.githubusercontent.com/certbot/certbot/master/certbot-nginx/certbot_nginx/tls_configs/options-ssl-nginx.conf > "$data_path/conf/options-ssl-nginx.conf"
  curl -s https://raw.githubusercontent.com/certbot/certbot/master/certbot/ssl-dhparams.pem > "$data_path/conf/ssl-dhparams.pem"
  echo
fi

echo "### Creating dummy certificate for $domains ..."
path="/etc/letsencrypt/live/$domains"
mkdir -p "$data_path/conf/live/$domains"
-docker-compose run --rm --entrypoint "\
+docker-compose -f docker-compose.yml run --rm --entrypoint "\
  openssl req -x509 -nodes -newkey rsa:1024 -days 1\
    -keyout '$path/privkey.pem' \
    -out '$path/fullchain.pem' \
    -subj '/CN=localhost'" certbot
echo

echo "### Starting nginx ..."
-docker-compose up --force-recreate -d nginx
+docker-compose -f docker-compose.yml up --force-recreate -d service_name
echo

echo "### Deleting dummy certificate for $domains ..."
-docker-compose run --rm --entrypoint "\
+docker-compose -f docker-compose.yml run --rm --entrypoint "\
  rm -Rf /etc/letsencrypt/live/$domains && \
  rm -Rf /etc/letsencrypt/archive/$domains && \
  rm -Rf /etc/letsencrypt/renewal/$domains.conf" certbot
echo

echo "### Requesting Let's Encrypt certificate for $domains ..."
#Join $domains to -d args
domain_args=""
for domain in "${domains[@]}"; do
  domain_args="$domain_args -d $domain"
done

# Select appropriate email arg
case "$email" in
  "") email_arg="--register-unsafely-without-email" ;;
  *) email_arg="--email $email" ;;
esac

# Enable staging mode if needed
if [ $staging != "0" ]; then staging_arg="--staging"; fi

-docker-compose run --rm --entrypoint "\
+docker-compose -f docker-compose.yml run --rm --entrypoint "\
  certbot certonly --webroot -w /var/www/certbot \
    $staging_arg \
    $email_arg \
    $domain_args \
    --rsa-key-size $rsa_key_size \
    --agree-tos \
    --force-renewal" certbot
echo

echo "### Reloading nginx ..."
-docker-compose exec nginx nginx -s reload
+docker-compose exec service_name nginx -s reload

我确保始终在 docker-compose 命令中包含 -f 标志,以防有人不知道如果他们有自定义名为 docker-compose.yml 文件.与教程不同,我还确保将服务名称设置为 service_name 以确保区分服务名称和 Nginx 命令.

I have made sure to always include the -f flag with the docker-compose command just in case someone doesn't know what to change if they had a custom named docker-compose.yml file. I have also made sure to set the service name as service_name to make sure to differentiate between the service name and the Nginx command, unlike the tutorial.

注意:如果不确定设置是否有效,请确保将暂存设置为 1 以避免达到请求限制.重要的是要记住在测试完成后将其设置回 0 并重做修改 init-letsencrypt.sh 文件的所有步骤.测试完成并将暂存设置为 0 后,重要的是停止之前运行的容器并删除数据文件夹,以便进行适当的初始认证:

Note: If unsure about the fact that the setup is working, make sure to set staging as 1 to avoid hitting request limits. It is important to remember to set it back to 0 once testing is done and redo all steps from amending the init-letsencrypt.sh file. Once testing is done and the staging is set to 0, it is important to stop previous running containers and delete the data folder for the proper initial certification to ensue:

$ docker-compose -f docker-compose.yml down && yes | docker system prune -a --volumes && sudo rm -rf ./data

一旦证书准备好初始化,脚本将使用sudo运行;使用 sudo 非常重要,因为如果没有它运行,容器内的权限会出现问题.

Once the certificates are ready to be initialized, the script is to be run using sudo; it is very important to use sudo, as issues will occur with the permissions inside the containers if run without it.

$ sudo ./init-letsencrypt.sh

证书颁发后,有自动更新证书的问题;需要做两件事:

After the certificate is issued, there is the matter of automatically renewing the certificate; two things need to be done:

  • Nginx Container中,Nginx 将通过以下修改重新加载新获得的证书:
  • In the Nginx Container, Nginx would reload the newly obtained certificates through the following ammendment:
service_name:
...
- command: /bin/ash -c "exec nginx -g 'daemon off;'"
+ command: /bin/ash -c "while :; do sleep 6h & wait $${!}; nginx -s reload; done & exec nginx -g 'daemon off;'"
...

  • Certbot Container 部分,添加以下内容以检查证书是否按照 Let's Encrypt 的建议每十二小时更新一次:

    • In the Certbot Container section, the following is to be add to check if the certificate is up for renewal every twelve hours, as recommended by Let's Encrypt:
    • certbot:
      ...
      + entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew --webroot -w /var/www/certbot; sleep 12h & wait $${!}; done;'"
      

      在运行 docker-compose -f docker-compose.yml up 之前,data 的所有权应该更改为 ec2-user代码>;这是为了避免在运行 docker-compose -f docker-compose.yml up 或以 sudo 模式运行时遇到权限错误:

      Before running docker-compose -f docker-compose.yml up, the ownership of the data should be changed folder to the ec2-user; this is to avoid running into permission errors when running docker-compose -f docker-compose.yml up, or running it in sudo mode:

      sudo chown ec2-user:ec2-user -R /path/to/data/
      

      不要忘记在您的 DNS 提供商中为 Let's Encrypt 添加 CAA 记录.您可以在此处阅读有关如何操作的更多信息.

      Don't forget to add a CAA record in your DNS provider for Let's Encrypt. You may read here for more information on how to do so.

      如果你在 Nginx 容器中遇到任何问题,因为你正在替换变量并且 $server_name$request_uri 没有正确显示,你可以参考 这个问题.

      If you run into any issues with the Nginx container because you are substituting variables and $server_name and $request_uri are not appearing properly, you may refer to this issue.

      这篇关于如何在运行 NGINX Docker 容器的 AWS EC2 上启用 HTTPS?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆