Skip to content

nginx ohne Proxy

Wenn nginx ohne vorgeschalteten Proxy eingesetzt werden soll, benötigt man TLS Zertifikate, welche im Browser validiert werden können.

Kostenlose TLS Zertifikate können über Anbieter wie ZeroSSL oder Let's Encrypt bezogen werden. In unserem Fall beziehen wir diese von Let's Encrypt mithilfe von acme.sh.

# mit root-Rechten ausführen
apt install nginx-full

# acme.sh installieren und default ca auf Let's Encrypt setzen
curl https://get.acme.sh | sh -s email=acme@domain.de
ln -s /root/.acme.sh/acme.sh /usr/bin/acme.sh
acme.sh --install-cronjob

acme.sh --server "https://acme-v02.api.letsencrypt.org/directory" --set-default-ca

IPv6 Adresse pro Virtual-Host

Sofern geplant ist, jedem Virtual Host eine eigene IPv6 Adresse zu geben empfielt sich den nginx systemd-Service um einige Sekunden zu verzögern, sodass sichergestellt werden kann, dass das System die IPv6 Adressen der Netzwerkschnittstelle bereits hinzugefügt hat. Dieses Verfahren wurde auch hier beschrieben.

Result of systemctl status nginx

Dazu muss in der Datei /lib/systemd/system/nginx.service vor der ersten ExecStartPre Zeile folgendes hinzugefügt werden:

# make sure the additional ipv6 addresses (which have been added with post-up) 
# are already on the interface (only required for enabled nginx service on system boot)
ExecStartPre=/bin/sleep 5

Konfiguration für neue Dienste

Folgende Schritte sind notwendig, um ein neues HTTP Routing zu konfigurieren: 1. Dienst aufsetzen. 2. Port-Binding von Dienst auf IPv6 Localhost (::1) des Hosts. 3. TLS Zertifkat über acme.sh anfordern. 4. Optional: Eigene IPv6 Adresse für Virtual Host konfigurieren. 5. nginx Virtual-Host konfigurieren und aktivieren. 6. Konfiguration testen und nginx neu laden.

Dienst aufsetzen

...

Port-Binding von Dienst auf IPv6 Localhost (::1) des Hosts

Die Containerdefinition muss einen entsprechenden Eintrag erhalten, sodass der Port auf dem der Container den Dienst bereitstellt, auf dem Hostsystem lokal verfügbar ist. Dabei darf natürlich nur die linke Seite (hier 8081) verändert werden.

    ports:
      - "[::1]:8081:80"

TLS Zertifkat über acme.sh anfordern

Für acme.sh müssen die erforderlichen Umgebungsvariablen für die gewünschte ACME Challenge gesetzt sein. Für die DNS API's der Anbieter empfielt sich ein Blick in diese Tabelle.

# Beispielkonfiguration für Cloudflare DNS API
export CF_Account_ID=
export CF_Zone_ID=
export CF_Token=
acme.sh --issue --keylength ec-384 --dns dns_cf -d service.domain.de

Optional: Eigene IPv6 Adresse für Virtual Host konfigurieren

Sofern eine eigene IPv6 Adresse für diesen Dienst verwendet werden soll, wird diese der entsprechenden Netzwerkschnittstelle hinzugefügt, sodass diese in nginx verwendet werden kann.

# /etc/network/interfaces

# ...

iface eth0 inet6 static
    # ipv6 address of the host
    address 2001:db8:1234:5678::1/64
    gateway 2001:db8::1
    # service.domain.de
    post-up ip -6 a add 2001:db8:1234:5678:5eca:dc9d:fd4e:6564/64 dev eth0

Da Ubuntu netplan zum Konfigurieren der Netzwerkeschnittstellen verwendet, muss die entsprechende Konfiguration im Verzeichnis /etc/netplan angepasst werden. Die Konfigurationsdatei sollte ungefähr wie folgt aussehen:

network:
    version: 2
    renderer: networkd
    ethernets:
        enp1s0:
            addresses:
                - 10.10.10.2/24
                - 2001:db8::5/64
            dhcp4: no
            routes:
                - to: 0.0.0.0/0
                via: 10.10.10.1
                - to: ::/0
                via: 2001:db8::1
            nameservers:
                addresses: [10.10.10.1, 1.1.1.1, 2001:470:20::2]
Wenn die Konfigurationsdatei gefunden wurde, fügt man in dem addresses Abschnitt die neue IPv6 Adresse wie folgt hinzu:
addresses:
    ...
    - 2001:db8:4a:90a:d8d5:dbf4:fd80:8f80

nginx Virtual-Host konfigurieren und aktivieren

Anschließend wird die Virtual Host Konfiguration unter dem Pfad /etc/nginx/sites-available/domain angelegt. Dabei müssen hauptsächlich die mit Pfeil markierten Zeilen beachtet werden.

# https://ssl-config.mozilla.org/#server=nginx&version=1.17.7&config=modern&openssl=1.1.1d&guideline=5.6
server {
    server_name service.domain.de;               # <---
    listen 0.0.0.0:80 http2;
    listen [::]:80 http2;                        # <---

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

server {
    server_name service.domain.de;               # <---
    listen 0.0.0.0:443 ssl http2; 
    listen [::]:443 ssl http2;                   # <---

    ssl_certificate /root/.acme.sh/service.domain.de_ecc/fullchain.cer;
    ssl_certificate_key /root/.acme.sh/service.domain.de_ecc/service.domain.de.key;
    ssl_session_timeout 1d;
    ssl_session_cache shared:MozSSL:10m;  # about 40000 sessions
    ssl_session_tickets off;

    # modern configuration
    ssl_protocols TLSv1.3;
    ssl_prefer_server_ciphers off;

    # HSTS (ngx_http_headers_module is required) (63072000 seconds)
    add_header Strict-Transport-Security "max-age=63072000" always;

    # OCSP stapling
    ssl_stapling on;
    ssl_stapling_verify on;

    location / {
        proxy_pass http://[::1]:8081/;           # <---
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header X-Real-IP $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}

Konfiguration aktivieren, testen und anwenden.

Nun muss noch der Link zu /etc/nginx/sites-enabled/ angelegt werden, bevor die Konfiguration von nginx getestet werden kann und anschließend nginx neu geladen werden kann, sofern der Test keine Fehler ergeben hat:

ln -s /etc/nginx/sites-available/service.domain.de \
    /etc/nginx/sites-enabled/

nginx -t && systemctl reload nginx