it-swarm.com.de

So verwenden Sie Let's Encrypt mit Docker-Container basierend auf dem Node.js-Image

Ich führe eine Express -basierte Website in einem Docker-Container basierend auf dem Node.js-Abbild aus. Wie verwende ich Let's Encrypt mit einem Container, der auf diesem Image basiert?

19
jsejcksn

Als Erstes habe ich ein einfaches Express-basiertes Docker-Image erstellt.

Ich verwende den folgenden app.js aus dem hello world-Beispiel von express in ihren Dokumenten:

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

Ich habe auch die folgende packages.json-Datei erhalten, nachdem ich npm init im selben Dokument ausgeführt hatte:

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

Ich habe die folgende Docker-Datei erstellt:

FROM node:onbuild
EXPOSE 3000
CMD node app.js

Hier ist die Ausgabe, wenn ich meinen Schritt docker build mache. Ich habe die meisten npm install-Ausgaben aus Gründen der Kürze entfernt:

$ 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

Das Ausführen dieses Bildes funktioniert folgendermaßen:

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

Wir können dies bereinigen, indem wir Folgendes tun: docker rm -f helloworld


Nun, ich habe meine sehr grundlegende, Express-basierte Website in einem Docker-Container ausgeführt, aber es ist noch kein TLS eingerichtet. Wenn Sie noch einmal die expressjs-Dokumente betrachten, ist die bewährte security-Methode bei Verwendung von TLS die Verwendung von nginx.

Da ich eine neue Komponente (nginx) einführen möchte, mache ich das mit einem zweiten Container.

Da nginx einige Zertifikate für die Arbeit benötigt, lassen Sie uns diese mit dem letsencrypt-Client generieren. Die letsencrypt-Dokumente zur Verwendung von letsencrypt in Docker finden Sie hier: http://letsencrypt.readthedocs.io/de/latest/using.html#running-with-docker

Führen Sie die folgenden Befehle aus, um die ursprünglichen Zertifikate zu generieren. Sie müssen dies auf einem System ausführen, das mit dem öffentlichen Internet verbunden ist und über den Port 80/443 verfügt, der von den letsencrypt-Servern erreichbar ist. Sie müssen außerdem Ihren DNS-Namen einrichten und auf die Box verweisen, in der Sie Folgendes ausführen:

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

Stellen Sie sicher, dass Sie die Werte für LETSENCRYPT_EMAIL und DNSNAME ersetzen. Die E-Mail-Adresse wird für Ablaufbenachrichtigungen verwendet.


Lassen Sie uns nun einen Nginx-Server einrichten, der dieses neu generierte Zertifikat verwenden wird. Zuerst benötigen wir eine Nginx-Konfigurationsdatei, die für TLS konfiguriert ist:

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

Wir können diese Konfigurationsdatei mit der folgenden Docker-Datei in unser eigenes benutzerdefiniertes Nginx-Image einfügen:

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

Dies kann mit dem folgenden Befehl erstellt werden: docker build -t expressnginx .

Als Nächstes erstellen wir ein benutzerdefiniertes Netzwerk, damit wir die Service Discovery-Funktion von Docker nutzen können:

docker network create -d bridge expressnet

Jetzt können wir die helloworld- und nginx-Container hochfahren:

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

Vergewissern Sie sich noch einmal, dass nginx korrekt ausgeführt wurde, indem Sie die Ausgabe von docker logs expressnginx betrachten.

Die Nginx-Konfigurationsdatei sollte alle Anforderungen an Port 80 an Port 443 umleiten. Wir können dies testen, indem Sie Folgendes ausführen:

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

An diesem Punkt sollten wir auch in der Lage sein, eine erfolgreiche TLS-Verbindung herzustellen und unsere Hello World!-Antwort wieder zu sehen:

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

Nun, um den Erneuerungsprozess einzurichten. Die obige nginx.conf enthält Bestimmungen für den bekannten Pfad letsecrypt für die Webroot-Überprüfungsmethode. Wenn Sie den folgenden Befehl ausführen, wird die Erneuerung behandelt. Normalerweise führen Sie diesen Befehl auf einer Art cron aus, damit Ihre Zertifikate vor ihrem Ablauf erneuert werden:

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
27
programmerq

Es gibt viele Möglichkeiten, dies abhängig von Ihrem Setup zu erreichen. Ein beliebter Weg ist, nginx vor Ihrem Docker-Container einzurichten und die Zertifikate vollständig in Ihrer nginx-Konfiguration zu verarbeiten.

Die nginx config kann eine Liste von 'usptreams' (Ihre Docker-Container) und 'Server' enthalten, die im Wesentlichen Anforderungen bestimmten Upstreams zuordnen. Als Teil dieser Zuordnung können Sie auch mit SSL umgehen.

Sie können certbot verwenden, um das Einrichten zu erleichtern.

5
duncanhall

Ich habe vor kurzem https implementiert, mit nginx verschlüsseln. Ich liste die Herausforderungen auf, denen ich begegnet bin, und die Art und Weise, wie ich hier Schritt für Schritt umgesetzt habe.

Herausforderung:

  1. Das Docker-Dateisystem ist vergänglich. Das bedeutet, dass nach jedem Erstellen eines Builds die Zertifikate, die gespeichert werden oder wenn sie im Container generiert werden, verschwinden. Daher ist es sehr schwierig, Zertifikate im Container zu generieren. 

Schritte zur Überwindung:

Der folgende Leitfaden ist unabhängig von der Art der App, da nur Nginx und Docker verwendet werden.

  • Installieren Sie zunächst nginx auf Ihrem Server (nicht auf dem Container, sondern direkt auf dem Server). Sie können folgen Sie dieser Anleitung , um ein Zertifikat für Ihre Domäne mithilfe von certbot zu generieren.
  • Stoppen Sie jetzt diesen Nginx-Server und starten Sie den Build Ihrer App. Installieren Sie nginx in Ihrem Container und öffnen Sie die Ports 80, 443 in Ihrem Docker-Container. (wenn aws open auf ec2-Instanz verwendet wird, standardmäßig auch aws open nur Port 80)

  • Führen Sie als Nächstes Ihren Container aus und hängen Sie die Volumes, die die Zertifikatsdatei enthalten, direkt in den Container ein. Ich habe eine Frage hier beantwortet, wie das Gleiche zu tun ist. 

  • Dadurch wird https in Ihrer App aktiviert. Wenn Sie nicht in der Lage sind zu beobachten, und verwenden Sie Chrome versuchen Löschen von DNS-Cache für Chrome

Automatischer Erneuerungsprozess:

  • Lassen Sie uns Zertifikate verschlüsseln, sind nur 3 Monate gültig. In der obigen Anleitung wird auch das Konfigurieren der automatischen Erneuerung festgelegt. Sie müssen Ihren Container jedoch mindestens alle 3 Monate anhalten und erneut starten, um sicherzustellen, dass die in Ihrem Docker-Container installierten Zertifikate auf dem neuesten Stand sind. (Sie müssen den Nginx-Server, den wir im ersten Schritt eingerichtet haben, neu starten, damit die Erneuerung reibungslos verläuft.)
3
Penkey Suresh

Hier können Sie nachschauen: https://certbot.eff.org/docs/using.html?highlight=docker#running-with-docker

Was ich dann persönlich mache:

  1. Erstellen Sie ein Docker-Volume, um die Zertifikate zu speichern, und erstellen Sie die Zertifikate mit dem obigen Bild
  2. Erstellen Sie ein benutzerdefiniertes Docker-Netzwerk ( https://docs.docker.com/engine/userguide/networking/#/user-defined-networks ).
  3. Erstellen Sie ein auf nginx basierendes Image mit Ihrer Konfiguration (vielleicht das wird nützlich sein)
  4. Erstellen Sie einen Nginx-Container, der auf Ihrem Image basiert, mounten Sie das Volume darin und verbinden Sie es mit dem Netzwerk (leiten Sie die Port 80 und 443 auch an, was Sie möchten).
  5. Ich würde einen Container für Ihre node.js-App erstellen und ihn mit demselben Netzwerk verbinden

Wenn Sie nun nginx richtig konfiguriert haben (zeigen Sie auf den richtigen Pfad für die TLS-Zertifikate und den Proxy auf die richtige URL, z. B. http: // my-app: 3210 ), sollten Sie Zugriff auf Ihre App in https haben.

2
Paul Trehiou

Frontend - NGINX - der Port, der auf den Port 443 wartet, und die zu beckenden Proxies

Backend - Sie Docker-Container

1
Denis Lisitskiy