Как использовать Let Encrypt с контейнером Docker на основе изображения Node.js

Я запускаю веб-сайт Express в контейнере Docker на основе Node.js image. Как использовать Let encrypt с контейнером на основе этого изображения?

Ответ 1

Первое, что я сделал, это создать простое изображение докеры на основе экспресс-поддержки.

Я использую следующий app.js, взятый из выражения привет мирского примера в своих документах:

var express = require('express');
var app = express();

app.get('/', function (req, res) {
  res.send('Hello World!');
});

app.listen(3000, function () {
  console.log('Example app listening on port 3000!');
});

У меня также появился следующий packages.json файл после запуска их npm init в том же документе:

{
  "name": "exampleexpress",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.14.0"
  }
}

Я создал следующий файл Docker:

FROM node:onbuild
EXPOSE 3000
CMD node app.js

Здесь вывод, когда я делаю мой шаг docker build. Я удалил большую часть вывода npm install для краткости:

$ docker build -t exampleexpress .
Sending build context to Docker daemon 1.262 MB
Step 1 : FROM node:onbuild
# Executing 3 build triggers...
Step 1 : COPY package.json /usr/src/app/
Step 1 : RUN npm install
 ---> Running in 981ca7cb7256
npm info it worked if it ends with ok
<snip>
npm info ok
Step 1 : COPY . /usr/src/app
 ---> cf82ea76e369
Removing intermediate container ccd3f79f8de3
Removing intermediate container 391d27f33348
Removing intermediate container 1c4feaccd08e
Step 2 : EXPOSE 3000
 ---> Running in 408ac1c8bbd8
 ---> c65c7e1bdb94
Removing intermediate container 408ac1c8bbd8
Step 3 : CMD node app.js
 ---> Running in f882a3a126b0
 ---> 5f0f03885df0
Removing intermediate container f882a3a126b0
Successfully built 5f0f03885df0

Запуск этого изображения работает следующим образом:

$ docker run -d --name helloworld -p 3000:3000 exampleexpress
$ curl 127.0.0.1:3000
Hello World!

Мы можем очистить это, выполнив: docker rm -f helloworld


Теперь у меня есть мой самый простой экспресс-сайт, работающий в контейнере Docker, но у него пока нет настройки TLS. Еще раз взглянув на документы expressjs, наилучшая практика безопасности при использовании TLS - это использовать nginx.

Поскольку я хочу ввести новый компонент (nginx), я сделаю это со вторым контейнером.

Так как nginx потребуется несколько сертификатов для работы, отпустите и создайте те, у которых есть клиент letencrypt. Документы letencrypt о том, как использовать letencrypt в Docker, можно найти здесь: http://letsencrypt.readthedocs.io/en/latest/using.html#running-with-docker

Выполните следующие команды для генерации исходных сертификатов. Вам нужно будет запустить это в системе, которая подключена к общедоступному Интернету, и имеет порт 80/443, доступный с серверов letencrypt. Вам также нужно будет настроить DNS-имя и указать на поле, в котором вы его запускаете:

export LETSENCRYPT_EMAIL=<youremailaddress>
export DNSNAME=www.example.com

docker run --rm \
    -p 443:443 -p 80:80 --name letsencrypt \
    -v "/etc/letsencrypt:/etc/letsencrypt" \
    -v "/var/lib/letsencrypt:/var/lib/letsencrypt" \
    quay.io/letsencrypt/letsencrypt:latest \
    certonly -n -m $LETSENCRYPT_EMAIL -d $DNSNAME --standalone --agree-tos

Обязательно замените значения для LETSENCRYPT_EMAIL и DNSNAME. Адрес электронной почты используется для уведомлений об истечении срока действия.


Теперь настройте сервер nginx, который будет использовать этот вновь созданный сертификат. Во-первых, нам понадобится файл конфигурации nginx, который настроен для TLS:

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /dev/stdout  main;
    sendfile        on;
    keepalive_timeout  65;

    server {
        listen       80;
        server_name  _;
        return 301 https://$host$request_uri;
    }

    server {
        listen              443 ssl;
        #add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
        server_name         www.example.com;
        ssl_certificate     /etc/letsencrypt/live/www.example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/www.example.com/privkey.pem;
        ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers         HIGH:!aNULL:!MD5;

        location ^~ /.well-known/ {
            root   /usr/share/nginx/html;
            allow all;
        }

        location / {
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_pass http://expresshelloworld:3000;
        }
    }
}

Мы можем поместить этот файл конфигурации в наше собственное пользовательское изображение nginx со следующим файлом Docker:

FROM nginx:alpine
COPY nginx.conf /etc/nginx/nginx.conf

Это можно построить с помощью следующей команды: docker build -t expressnginx .

Затем мы создадим настраиваемую сеть, чтобы воспользоваться функцией обнаружения сервисов Docker:

docker network create -d bridge expressnet

Теперь мы можем запустить контейнеры helloworld и nginx:

docker run -d \
    --name expresshelloworld --net expressnet exampleexpress
docker run -d -p 80:80 -p 443:443 \
    --name expressnginx --net expressnet \
    -v /etc/letsencrypt:/etc/letsencrypt \
    -v /usr/share/nginx/html:/usr/share/nginx/html \
    expressnginx

Двойная проверка, что nginx подошел правильно, взглянув на вывод docker logs expressnginx.

Файл конфигурации nginx должен перенаправить любые запросы на порт 80 на порт 443. Мы можем проверить это, выполнив следующее:

curl -v http://www.example.com/

Мы также должны в этот момент сделать успешное соединение TLS и увидеть наш ответ Hello World! назад:

curl -v https://www.example.com/

Теперь, чтобы настроить процесс обновления. В приведенном выше nginx.conf содержатся положения, позволяющие пропустить известный путь для метода проверки webroot. Если вы выполните следующую команду, она будет обрабатывать обновление. Обычно вы запускаете эту команду на каком-то cron, чтобы ваши сертификаты были продлены до истечения срока действия:

export [email protected]
export DNSNAME=www.example.com

docker run --rm --name letsencrypt \
    -v "/etc/letsencrypt:/etc/letsencrypt" \
    -v "/var/lib/letsencrypt:/var/lib/letsencrypt" \
    -v "/usr/share/nginx/html:/usr/share/nginx/html" \
    quay.io/letsencrypt/letsencrypt:latest \
    certonly -n --webroot -w /usr/share/nginx/html -d $DNSNAME --agree-tos

Ответ 2

Есть много способов добиться этого в зависимости от вашей настройки. Один из популярных способов - установить nginx перед контейнером Docker и обрабатывать сертификаты полностью в вашей конфигурации nginx.

Конфигурация nginx может содержать список "usptreams" (ваши контейнеры Docker) и "серверы", которые по существу сопоставляют запросы с конкретными восходящими потоками. В рамках этого сопоставления вы также можете обрабатывать SSL.

Вы можете использовать certbot, чтобы помочь вам установить это.

Ответ 3

Вы можете посмотреть здесь: https://certbot.eff.org/docs/using.html?highlight=docker#running-with-docker

Тогда то, что я лично делаю, это:

  • Создайте том Docker для хранения сертификатов и создания сертификатов с изображением выше.
  • Создайте пользовательскую сеть Docker (https://docs.docker.com/engine/userguide/networking/#/user-defined-networks)
  • Создайте образ на основе nginx с вашей конфигурацией (возможно, этот будет полезен)
  • Создайте контейнер Nginx на основе вашего изображения, смонтируйте его в нем и подключите к сети (также отправьте порт 80 и 443 на все, что вы хотите)
  • Я бы создал контейнер для вашего приложения node.js и подключил его к той же сети.

Теперь, если вы правильно настроили nginx (укажите правильный путь для сертификатов TLS и прокси на правый URL, например http://my-app:3210) вы должны иметь доступ к вашему приложению в https.

Ответ 4

Недавно я реализовал https с возможностью шифрования с помощью nginx. Я перечисляю проблемы, с которыми столкнулся, и способ, который я внедрил здесь шаг за шагом.

Вызов

  • Докерная файловая система является эфемерной. Это означает, что каждый раз, когда вы делаете сборку, сертификаты, которые хранятся или генерируются внутри контейнера, исчезают. Поэтому очень сложно создавать сертификаты внутри контейнера.

Шаги по его устранению:

Ниже руководство не зависит от вашего приложения, поскольку оно включает только nginx и docker.

  • Сначала установите nginx на свой сервер (не на контейнер, а прямо на сервер.) Вы можете следовать этому руководству для создания сертификата для ваш домен с помощью certbot.
  • Теперь остановите этот сервер nginx и запустите сборку своего приложения. Установите nginx на свой контейнер и откройте порт 80, 443 на контейнере докера. (при использовании aws open на экземпляре ec2 также по умолчанию aws open only port 80)

  • Далее запустите контейнер и смонтируйте тома, содержащие файл сертификата непосредственно на контейнере. Я ответил на вопрос здесь о том, как сделать то же самое.

  • Это позволит включить https в вашем приложении. Если вы не можете наблюдать и используете chrome try очистка кеша dns для chrome

Процесс автоматического обновления:

  • Разрешить шифрование сертификатов действительны только в течение 3 месяцев. В приведенном выше руководстве также настраиваются шаги по настройке автоматического обновления. Но вы должны останавливать и перезапускать контейнер каждые 3 месяца, чтобы убедиться, что сертификаты, установленные на вашем контейнере докеров, обновлены. (Вам нужно будет перезапустить сервер nginx, который мы установили на первом шаге, чтобы обновление было плавным).

Ответ 5

Front end - NGINX - который прослушивает порт 443 и прокси-серверы заканчивается

Обратная сторона - контейнер для докеров