簡體   English   中英

如何使用基於Node.js圖像的Docker容器的Let's Encrypt

[英]How to use Let's Encrypt with Docker container based on the Node.js image

我正在基於Node.js映像的Docker容器中運行基於Express的網站。 如何使用基於該圖像的容器的Let's Encrypt

我做的第一件事就是創建一個簡單的基於表達式的docker鏡像。

我正在使用以下app.js ,取自他們的docs中的express的hello world示例

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!');
});

在同一個doc中運行npm init后,我也得到了以下的packages.json文件:

{
  "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"
  }
}

我創建了以下Dockerfile:

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需要一些證書才能使用,讓我們繼續使用letsencrypt客戶端生成那些證書。 關於如何在Docker中使用letsencrypt的letsencrypt文檔可以在這里找到: http ://letsencrypt.readthedocs.io/en/latest/using.html#running-with-docker

運行以下命令以生成初始證書。 您需要在連接到公共Internet的系統上運行此程序,並且可以從letsencrypt服務器訪問端口80/443。 您還需要設置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_EMAILDNSNAME的值。 電子郵件地址用於到期通知。


現在,讓我們設置一個將使用這個新生成的證書的nginx服務器。 首先,我們需要一個為TLS配置的nginx配置文件:

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;
        }
    }
}

我們可以使用以下Dockerfile將此配置文件放入我們自己的自定義nginx映像中:

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

這可以使用以下命令docker build -t expressnginx .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

通過查看docker logs expressnginx輸出,仔細檢查nginx是否正常。

nginx配置文件應該將端口80上的任何請求重定向到端口443.我們可以通過運行以下命令來測試它:

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

此時,我們還應該能夠成功建立TLS連接,並查看我們的Hello World! 回復:

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

現在,設置續訂過程。 上面的nginx.conf為webroot驗證方法提供了letsencrypt .well-known路徑。 如果運行以下命令,它將處理續訂。 通常,您將在某種類型的cron上運行此命令,以便在證書過期之前續訂證書:

export LETSENCRYPT_EMAIL=me@example.com
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

根據您的設置,有很多方法可以實現此目的。 一種流行的方法是在Docker容器前設置nginx ,並在nginx配置中完全處理證書。

nginx配置可以包含“usptreams”(您的Docker容器)和“服務器”列表,它們實際上將請求映射到特定上游。 作為映射的一部分,您還可以處理SSL。

您可以使用certbot來幫助您進行設置。

我最近實現了https,讓我們使用nginx進行加密。 我列出了我所面臨的挑戰,以及我在這里逐步實施的方式。

挑戰

  1. Docker文件系統是短暫的。 這意味着在每次構建之后,存儲的證書或在容器內生成的證書都將消失。 因此,在容器內生成證書非常棘手。

克服它的步驟

以下指南獨立於您擁有的應用程序類型,因為它只涉及nginx和docker。

  • 首先在您的服務器上安裝nginx(不是在容器上,而是直接在服務器上安裝。)您可以按照本指南使用certbot為您的域生成證書。
  • 現在停止這個nginx服務器並開始構建你的應用程序。 在容器上安裝nginx並在docker容器上打開端口80,443。 (如果在ec2實例上使用aws打開也默認為aws只打開端口80)

  • 接下來運行容器並將包含證書文件的卷直接掛載到容器上。 我在這里回答了一個關於如何做同樣問題的問題

  • 這將在您的應用上啟用https。 如果您無法觀察,並且正在使用chrome嘗試清除dns緩存中的chrome

自動續訂流程:

  • 我們的加密證書只有3個月有效。 在上述指南中,還設置了配置自動續訂的步驟。 但是,您必須每3個月至少停止並重新啟動容器,以確保您的docker容器上安裝的證書是最新的。 (您必須重新啟動我們在第一步中設置的nginx服務器才能使續訂順利進行)

您可以在這里查看: https//certbot.eff.org/docs/using.html?highlight = tokener#runingwithwith-bucketer

然后我個人做的是:

  1. 創建一個Docker卷來存儲證書並使用上面的圖像生成證書
  2. 創建Docker用戶定義的網絡( https://docs.docker.com/engine/userguide/networking/#/user-defined-networks
  3. 使用您的配置基於nginx創建一個圖像( 可能會很有用)
  4. 根據您的圖像創建一個Nginx容器,在其中安裝卷並將其連接到網絡(也可以將端口80和443轉發到您想要的任何位置)
  5. 我會為您的node.js應用程序創建一個容器,並將其連接到同一網絡

現在,如果您正確配置了nginx(指向正確的TLS證書路徑和代理到正確的URL,例如http:// my-app:3210 ),您應該可以通過https訪問您的應用。

前端 - NGINX - 監聽443端口,以及beck結束的代理

后端 - 您的泊塢窗容器

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM