如何在运行NGINX Docker容器的AWS EC2上启用HTTPS?

时间:2019-07-28 08:36:53

标签: docker nginx amazon-ec2 certbot

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

在其上,我安装了Git,docker和docker-compose。完成后,我克隆了存储库并运行docker-compose up以启动生产环境。我去了公共DNS,就可以了。

我现在要在网站上启用HTTPS。

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

这是我的nginx.conf文件:

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文件:

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/代理到服务器的方式。那还会给我带来任何问题吗?

2 个答案:

答案 0 :(得分:1)

通过遵循Nginx and Let's Encrypt with Docker in Less Than 5 Minutes上的教程来启用SSL。我在遵循它时遇到了一些问题,因此我将在这里尝试澄清一些事情。

这些步骤包括将以下内容添加到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.yml Nginx容器部分,应进行修改,以包括添加到 Certbot容器的相同卷,以及添加端口并公开配置:

  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文件所在的目录中。

完成上述配置后,将采取几个步骤来初始化证书的颁发。

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

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配置文件后,将创建一个虚拟证书以允许进行我们的加密验证。有一个脚本可以自动执行所有这些操作,可以在使用CURL进行修改以适应环境之前,将其下载到项目的根目录中。还需要使用chmod命令使脚本可执行:

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

下载脚本后,将对其进行如下修改:

#!/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

我已确保在-f命令中始终包含docker-compose标志,以防万一有人拥有名为docker-compose.yml的自定义文件不知道要更改什么。与教程不同,我还确保将服务名称设置为service_name,以确保区分服务名称和Nginx命令。

注意::如果不确定安装程序是否正常运行,请确保将登台设置为1,以避免达到请求限制。重要的是要记住,测试完成后将其设置回0并重做修改init-letsencrypt.sh文件的所有步骤。完成测试并将阶段设置为0后,停止先前运行的容器并删除数据文件夹以确保进行适当的初始认证很重要:

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

一旦准备好初始化证书,就可以使用sudo运行脚本;使用sudo非常重要,因为如果不使用sudo,容器内部的权限就会出现问题。

$ sudo ./init-letsencrypt.sh

颁发证书后,存在自动续订证书的问题;需要完成两件事:

  • Nginx容器中,Nginx将通过以下修订重新加载新获得的证书:
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容器部分中,将添加以下内容,以按照让我们加密的建议,每十二小时检查一次证书是否可以更新。 li>
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模式运行时出现权限错误:

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

不要忘记在您的DNS提供商中为让我们加密添加CAA记录。您可以阅读here,以获取更多有关这样做的信息。

如果由于替换变量而导致Nginx容器出现任何问题,并且$server_name$request_uri的显示不正确,则可以参考this issue

答案 1 :(得分:0)

最简单的方法是设置ALB并将其用于HTTPS。

  1. 创建ALB
  2. 将443侦听器添加到ALB
  3. 使用AWS Certificate Manager生成证书
  4. 将“证书”设置为负载均衡器的默认证书
  5. 创建目标组
  6. 将您的EC2实例添加到目标组
  7. 将ALB指向目标组

请求将使用带有https的ALB服务