Kleine Letsencrypt + nginx Anleitung
Mal eine Kurzfassung zum meinem gestrigen Vortag zu letsenrypt auf dem Leipziger FHEM-Stammtisch
Es wurde behandelt: letsencrypt (certpot) über einen laufenden nginx-Server (http Authentifizierung)
Voraussetzungen: nginx, letsenrypt und Maschine ist extern über Port 80 erreichbar
Voraussetzungen: Automatisierung: da ein Zertifikat nur 3 Monate Haltbarkeit hat, sollte (und muß) man den Erhalt automatisieren, also Port 80 NICHT dicht machen!
Voraussetzungen: Domainname muß auf IP zeigen (hier www.test.de, bitte anpassen!)
Vorbereiten nginx:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name default_server;
root /usr/share/nginx/html;
index index.html index.htm;
access_log /var/log/nginx/default.access.log;
error_log /var/log/nginx/default.error.log;
# Sicherheit
server_tokens off;
add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains' always;
# Für LetsEncrypt
location ~ /\.well-known {
root /usr/share/nginx/html;
}
# Alles andere auf https://
location / {
try_files $uri $uri/ =404;
return 301 https://$host$request_uri;
}
Damit leitet nginx die Authentifizierung letsencrypt auf /usr/share/nginx/html, alles andere per redirect auf https (Auch wenn es noch nicht funktioniert). Nach einem reboot kann (und sollte) man testen, ein externer Aufruf auf port 80 muß zu einer Umleitung auf https und damit ein "nicht erreichbar" führen
Aufruf letsencrypt (als root):
letsencrypt certonly --webroot -w /usr/share/nginx/html -d www.test.de
Hinweis: Man kann auch mehrere "-d Domainname" angeben. Das Zertifikat erhält den ersten Domainnamen, aber alle sind im zetifikat enthalten
Jetzt sollte man ein ".. Gratulation .." bekommen, sonst Fehlermeldung lesen!
Das Zertifikat liegt unter /etc/letsencrypt/live/www.test.de
nginx einrichten:
server {
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
server_name default_server;
ssl_certificate_key /etc/letsencrypt/live/www.test.de/privkey.pem;
ssl_certificate /etc/letsencrypt/live/www.test.de/fullchain.pem;
root /usr/share/nginx/html;
index index.html index.htm;
access_log /var/log/nginx/default.access.log;
error_log /var/log/nginx/default.error.log;
# Hier Security-Regel einfügen
#include /etc/nginx/template/security;
# Normalerweise alles nur nach Login
location / {
auth_basic "Restricted Content";
auth_basic_user_file /etc/nginx/.htpasswd;
}
}
So ... nun haben wir ein Zertifikat, einen laufenden nginx und können uns freuen .. bis in 3 Monaten ... es fehlt also die Automatisierung.
letsencrypt renew
Dieses guckt, ob ein Zertifikat y30 Tage gültig und erneuert es ggf., sofern obiger Webserver noch läuft. leider ... müsste nach einem Zertifikatserneuerung der nginx neu gestartet werden, sonst kriegt er davon nichts mit. Besser ... es gleich als cron-atumatisieren:
in /etc/cron.weekly/letsencrypt (ausführbar!)
#!/bin/sh
DIR="/etc/letsencrypt/live"
LOG="/var/log/letsencrypt/weekly.letsencrypt.log"
/usr/bin/letsencrypt renew >${LOG}.tmp 2>&1
result=$(find ${DIR}/ -type l -mtime -1 )
if [ -n "$result" ]; then
echo "$(date "+%Y-%m-%d/%H:%M:%S") Neues Zertifikat" >>$LOG
# Hier kann man mit dem zertifikat noch andere Dinge erledigen, z.B. es auf andere Geräte verteilen
echo "$(date "+%Y-%m-%d/%H:%M:%S") Notwendige Dienste rebooten" >>$LOG
/usr/sbin/service nginx restart
else
echo "$(date "+%Y-%m-%d/%H:%M:%S") Keine neuen Dateien" >>${LOG}.no
fi
So ... dad war es nun, noch Fragen?
-----
Ausblick:
beim Treffn habe ich über Authentifizierung über http gesprochen. Mittlerweile gibt es auch eine über DNS. Dort braucht man aber eine API-fähigen DNS-Provider ....
Hallo Wernieman,
Vielen Dank für den Vortrag und die Anleitung. Da kommt gleich die erste Noob Frage: ich habe eine feste ip auf meinem VDSL, kein dynDNS. Die mag Let's Encrypt nicht:"The Let's Encrypt certificate authority will not issue certificates for a bare IP address."
Was mache ich da?
Du brauchst eine Domain, keine IP.
Ei n Zertifikat wird z.B. für www.test.de oder auch broetchen.metwurst.de ausgestellt, aber NICHT für eine IP.
Hi Wernieman,
danke für deine Infos !
Grüße
Heiko
Edit:
Hatte oben ausversehen die Zeile "include ...." vergessen auszukommentieren. Was ih damit erreichen will, kommt später (nächste Woche?)
Hallo Wernieman,
Ich wäre übrigens sehr daran interessiert dies über Docker abzubilden.
Also im Optimalfall Reverse Proxy, Letsencrypt und fail2ban als Docker Container mit einem Configfile zur Steuerung der Ports welche an welchem Container ankommen sollen.
Idee ist den internen Zugriff auf fhem und nodered über freigegebene Ports im Docker auf den Standardports zuzulassen.
Für den externen Zugriff dann per Dyndns (example.duckdns.org), Fritzbox Weiterleitung an 443 über den Reverse Proxy und der verteilt an fhem bzw. nodered mit fhem.example.duckdns.org oder nodered.example.duckdns.org.
Ich habe versucht mein Fhem im Dockercontainer über solch eine Konstellation per https erreichbar zu machen. Bin aber kläglich gescheitert, da ich mich im Proxyumfeld nicht auskenne.
fail2ban mußt DU auf dem Hostsystem laufen lassen, da die Berechtigung für Netzwerkzugriffe über Docker .... nicht nett sind.
Auch würde ich Dir (persönlich) empfehlen, den Proxy auf dem Host. Wenn Du mehrere Netwerke im Docker definiert (ideal), hat nur der Host auf alle Zugriff. Es gibt docker-Container mit Proxylösungen (z.B. j.wilder), aber dann müssen alle Contaiiner in einem Netz sein.
Ich habe mich entschlossen, hier keinen Vortrag über Proxy zu halten. Der Sicherheitsaspekt ist doch sehr hoch. Wer nicht weiß, was er tut (gilt bei VPN genau so), sollte lieber "die Finger von lassen". Zu schnell holt man sich "den Fein" ins Haus!
Hallo Wernieman,
ich versuche gerade deine Anleitung zu folgen komme da aber nicht weiter.
Deine Voraussetzungen erfülle ich:
Zitat von: Wernieman am 25 Januar 2019, 12:06:33
Voraussetzungen: nginx, letsenrypt und Maschine ist extern über Port 80 erreichbar
Voraussetzungen: Automatisierung: da ein Zertifikat nur 3 Monate Haltbarkeit hat, sollte (und muß) man den Erhalt automatisieren, also Port 80 NICHT dicht machen!
Voraussetzungen: Domainname muß auf IP zeigen (hier www.test.de, bitte anpassen!)
1. Ja ist es
2. Ja bleibt es
3. Domainname habe ich und lautet etwa so ,,ort.nachname.net"
Die FritzBox aktualisiert auch immer und alle anderen Server sind auch zu erreichen (andrer Port)
Dann habe ich die Datei ,,/etc/nginx/sites-available/reverse-proxy" angepasst mit deinem Code.
Reboot wurde ausgeführt.
Das Ergebnis von:
letsencrypt certonly --webroot -w /usr/share/nginx/html -d ort.nachname.net
lautet dann:
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator webroot, Installer None
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for ort.nachname.net
Using the webroot path /usr/share/nginx/html for all unmatched domains.
Waiting for verification...
Cleaning up challenges
Failed authorization procedure. ort.nachname.net (http-01): urn:ietf:params:acme:error:connection :: The server could not connect to the client to verify the domain :: Fetching http://ort.nachname.net/.well-known/acme-challenge/xxxxx: Connection refused
IMPORTANT NOTES:
- The following errors were reported by the server:
Domain: ort.nachname.net
Type: connection
Detail: Fetching
http://ort.nachname.net/.well-known/acme-challenge/xxxxx:
Connection refused
To fix these errors, please make sure that your domain name was
entered correctly and the DNS A/AAAA record(s) for that domain
contain(s) the right IP address. Additionally, please check that
your computer has a publicly routable IP address and that no
firewalls are preventing the server from communicating with the
client. If you're using the webroot plugin, you should also verify
that you are serving files from the webroot path you provided.
Was mache ich da jetzt falsch?
Fetching http://ort.nachname.net/.well-known/acme-challenge/xxxxx: Connection refused
Zum Testen
Lege mal einen Ordner an:
mkdir /usr/share/nginx/html/.well-known
Und jetzt
date >/usr/share/nginx/html/.well-known/test.txt
Beides sollte für jeden Lesbar sein. Und jetzt im Browser (von Extern!):
Zitathttp:/www.test.de/.well-known/test.txt
Natürlich, wie immer, www.test.de anpassen.
Es sollte im Browser das Datum / die Uhrzeit des date Aufrufs erscheinen. Wenn ja .. haben wir ein problem. Wenn Nein (bei Dir am wahrscheinlichsten), solltest Du im nfginx / beim router gucken, warum NICHT
Natürlich nein!
Router ist der Port offen! Definitiv. Dann weiß ich aber schon nimmer weiter.
Ich habe mich beim einrichten an diese Anleitung gehalten:
https://wiki.fhem.de/wiki/HTTPS-Absicherung_%26_Authentifizierung_via_nginx_Webserver (https://wiki.fhem.de/wiki/HTTPS-Absicherung_%26_Authentifizierung_via_nginx_Webserver)
Wird da etwas gemacht was hier nicht passt?
Vergiss erst mal FHEM und nimm erstmal einfach "nur" meinen zitierten Code in nginx (Mach von Deiner Config eine Sicherung!)
Bist Du Dir Sicher, das die Portweiterleitung auf den richtigen Rechner zeigt?
das Praktische an Proxmox ist man baut sich schnell eine neue VM.
also wieder alles installiert und frei gegeben:
*bevor die Frage kommt: Ja die Datei mit dem Datum ist da!*
jetzt hat sich die Fehlermeldung verändert:
Failed authorization procedure. xxx.xxxx.net (http-01): urn:ietf:params:acme:error:unauthorized :: The client lacks sufficient authorization :: Invalid response from http://xxx.xxx.net/.well-known/acme-challenge/xxxxx: "<html>\r\n<head><title>404 Not Found</title></head>\r\n<body bgcolor=\"white\">\r\n<center><h1>404 Not Found</h1></center>\r\n<hr><center>"
IMPORTANT NOTES:
- The following errors were reported by the server:
Domain: xxx.xxx.net
Type: unauthorized
Detail: Invalid response from
Wie rufst Du letsencrypt auf?
Was er eindeutig sagt:
Zitathttp://xxx.xxx.net/.well-known/acme-challenge/xxxxx: ".... 404 Not Found
Er findet das "Geheimnis" nicht. Du bist Dir sicher, das der oben genannte Zugriff von außen (Wichtig: außen!) auch wirklich funktioniert?
p.s.:
Wie häufig ändert sich Deine IP-Adresse? Wie aktuell ist dann Dein DNS-Record?
Letsencrypt fragt mit mehreren Rechnern ab und da die in der Welt verteilt sind, kann es bei zu schnellen Änderungen dazu führen, das es eben nicht aktuell ist.
Jeden Tag wird getrennt. Das kann ich aber ändern, ich meine das das die Telekom nicht mehr verlangt.
ich bin bei der Arbeit somit das das hier von außen! und gestern Abend habe ich es mit dem Handy getestet (wlan off)
ich habe Zugriff von Außen. Es ist ja auch eine 404 Seite von nginx "404 Not Found nginx/1.10.3"
Ich habe es noch nicht ganz verstanden. Das Verzeichnis /acme-challenge/ existiert nicht. Wie und wann wird das angelegt?
1. Wo siehst Du in Deiner Antwort das: "nginx/1.10.3"??
2. Das acme-challenge wird von letsencrypt angelegt und anschließend auch wieder aufgeräumt.
3. Geb uns bi8tt mal Deinen "letsencrypt-Aufruf" ...
Und .. auf welchem Betriebsystem mit welcher letsencrypt-Version?
Zitat von: Wernieman am 13 Februar 2019, 09:17:04
1. Wo siehst Du in Deiner Antwort das: "nginx/1.10.3"??
2. Das acme-challenge wird von letsencrypt angelegt und anschließend auch wieder aufgeräumt.
3. Geb uns bi8tt mal Deinen "letsencrypt-Aufruf" ...
Und .. auf welchem Betriebsystem mit welcher letsencrypt-Version?
1. Wenn ich versuche die Testdatei auf zu rufen. Wie du sie gepostet hast.
2. ok das erklärt warum ich das nicht sehe
3.
letsencrypt certonly --webroot -w /usr/share/nginx/html -d ort.nachname.net
Analog deinem ersten Post!
Sorry wegen 1. aber ...
siehst Du jetzt die Datei, oder bekommst Du (von außen) ein 404?
Wenn ich von außen auf http://ort.nachname.net/.well-known/test.txt zugreife kommt:
Zitat
404 Not Found
nginx/1.10.3
Oh,
so ein blöder Fehler!! jetzt geht es auch, das fehlte mir beim neu aufgesetzten:
$ sudo unlink /etc/nginx/sites-enabled/default
$ sudo ln -s /etc/nginx/sites-available/reverse-proxy /etc/nginx/sites-enabled/reverse-proxy
Danke dir, jetzt mache ich mal mit deiner Anleitung weiter!
Dann kannst DU jetzt mit letsencrypt testen ;o)
Der macht schließlich nichts anderes, als mein "Test". Du kannst übrigens die Test-Datei wieder löschen ...
Ich finde das Thema hier aktuell sehr spannend, denn ich überlege, wie ich meinen Nginx-Proxy besser absichern kann.
Bei mir läuft alles in einer Docker-Umgebung (nginx-proxy von jwilder (https://github.com/jwilder/nginx-proxy/) und docker-letsencrypt-nginx-proxy-companion (https://github.com/JrCs/docker-letsencrypt-nginx-proxy-companion/)). Ich nutze die Variante mit den getrennten Containern: https://github.com/jwilder/nginx-proxy/#separate-containers . So habe ich keine kritischen Container, die auf den Docker-Stack Zugriff haben.
Die Ports 80/443 sind von außen erreichbar. Nicht nur für LetEncrypt-ACME, sondern auch natürlich für den FHEM-Zugriff.
Das Ganze ist mit einer simplen htpasswd (apache2-utils) geschützt.
Die Reverse Proxy-Lösung ist unter Docker mit nur wenigen Zeilen und ohne großen Aufwand umsetzbar.
Aber ich würde gerne das System vor Brute Force-Angriffen schützen.
@Wernieman: Ist fail2ban unter Docker wirklich so kompliziert? Hast du Tipps oder ein Best Practice zu diesem Thema?
Oder gibt es vielleicht viel bessere Ideen?
Ich sehe persöhnlich (und so habe ich es auch auf der Arbeit umgesetzt) als "Dienstleistung des Docker-Server.
Also nginx (als Proxy), ssh, fail2ban und docker auf einem Server. Der "Rest" im Container.
Der nginx-proxy von jwilder hat den Nachteil, das der Container in allen Docker Netzen sein muß. Habe mir deshalb in eigenes Script geschrieben, was den nginx automatisch Konfiguriert und eben von host-Seite kommt.
Bezüglich Sicherheit:
Es ist relativ einfach (nicht nur mit dem aktuellen Problem) aus einem Docker-Container auszubrechen. Ich sehe also docker erstmal NICHT als Sicherheitsgewinn. Der Vorteil ist, das in einem Container nur das "installiert" sein muß, was man braucht. Ein Anfreifer also in seinen Möglichkeiten beschränkt wird.
Nur mals als Beispiel Wordpress. Die meisten Probleme liegen in Zusatzmodulen. Wenn eine Instanz aber ein Modul X nicht braucht und deshalb nicht installiert hat, kann es nicht angegriffen werden ....
Deshalb bin ich auch gegen "fette" Container, wie z.B. der in einem anderen Thread eingearbeitete FHEM-Container. Container müssen "schlank" sein ...
Hallo Wernieman,
leider komme ich nicht klar :-( Ich habe es einfach nicht verstanden.
Ich versuche deine Anleitung mit der zu verbinden https://wiki.fhem.de/wiki/HTTPS-Absicherung_%26_Authentifizierung_via_nginx_Webserver (https://wiki.fhem.de/wiki/HTTPS-Absicherung_%26_Authentifizierung_via_nginx_Webserver) und zu verstehen was ich da mache.
Leider bekomme ich es nicht hin FHEM mit deinem Zertifikatsweg von aussen erreichbar zu machen :-(
Könntest du mir nochmal auf die Sprünge helfen?
Vg
Tim
Hast Du jetzt das Problem, nginx sicher zu machen oder ein Zertifikat zu kriegen?
Nginx und fhem zusammen laufen zu lassen. Ich muss ja die nginx config anpassen damit auch fhem erreichbar ist. Da fehlt mir das wissen wie das geht. Ein Zertifikat habe ich erstellen können, aber wie gehts nun weiter?
.. Sorry aber dieser Thread bezieht sich auf letsencrypt und nginx.
Nicht auf nginx als Proxy für fhem, dafür bitte neuen Thread ....
Dir ist klar, das Dein Konstrukt im Netz hängt, also abgesichert sein muß? Jeder Mensch mit Internetanschluß kann ansonsten auf Dein System zugreifen. Ich bin mir nicht so sicher, ob Du das Wissen hast, dieses Umzusetzen. Deshalb hatte ich auch keine Anleitung dafür gepostet.
Ist jetzt nicht persönlich gemeint, habe aber beruflich genug damit zu tun, Angriff von solchen Gekaperten Systemen abzuwehren ....
Hallo,
wie ich jetzt festgestellt habe werden auf meiner Synology die Zertifikate nicht verlängert. Das betrifft aber nur die , die eine eigene Konfiguration besitzen. Ein "renew" wird für alle nicht auf der Synology gehosteten Dienste mit einer Fehlermeldung quittiert. Was auch etwas seltsam ist, dass die Konfiguration bislang funktioniert hat und die Zertifikate einwandfrei erneuert wurden
/usr/syno/sbin/syno-letsencrypt renew-all -v
DEBUG: start to renew [/usr/syno/etc/certificate/_archive/NtTBO7].
DEBUG: setup acme url https://acme-v01.api.letsencrypt.org/directory
DEBUG: GET Request: https://acme-v01.api.letsencrypt.org/directory
DEBUG: strat to do new-authz for dm500.frank.dyn-vpn.de
DEBUG: ==> start new authz.
DEBUG: new authz: do new-authz.
DEBUG: Post JWS Request: https://acme-v01.api.letsencrypt.org/acme/new-authz
DEBUG: Post Request: https://acme-v01.api.letsencrypt.org/acme/new-authz
DEBUG: new authz: setup challenge env.
DEBUG: new authz: http-01 challenge.
DEBUG: Post JWS Request: https://acme-v01.api.letsencrypt.org/acme/chall-v3/59297993/dKQBqQ
DEBUG: Post Request: https://acme-v01.api.letsencrypt.org/acme/chall-v3/59297993/dKQBqQ
DEBUG: new authz: http-01 check result.
DEBUG: GET Request: https://acme-v01.api.letsencrypt.org/acme/authz-v3/59297993
DEBUG: GET Request: https://acme-v01.api.letsencrypt.org/acme/authz-v3/59297993
DEBUG: Not synology DDNS.
DEBUG: DNS challenge failed, reason: {"error":108,"file":"challenge.cpp","msg":"Not synology DDNS."}
DEBUG: Normal challenge failed, reason: {"error":102,"file":"client.cpp","msg":"Invalid response from https://dm500.frank.dyn-vpn.de/.well-known/acme-challenge/F9Gh_4R-Dbn60TdQqlbRTMSfJfPsiRGEmzl9FtPWbQM [92.117.43.29]: \"<html>\\r\\n<head><title>401 Authorization Required</title></head>\\r\\n<body>\\r\\n<center><h1>401 Authorization Required</h1></center>\\r\\n<h\""}
Wenn ich die Fehlermeldung richtig interpretiere findet der Let's Encrypt die Domain mit der Zufällig erstellten Datei nicht mehr. Deswegen habe ich meine Fehlersuche auf die "location ^~ /.well-known/acme-challenge ...." Konfiguration konzentriert. Ist es aber scheinbar nicht.
Für den Moment komme ich hier nicht weiter. Wer hat noch eine Idee zu diesem Fehler.
Edit:
Ich hatte gerade noch eine Idee und den Fehler gefunden. In der zusätzlichen Konfiguration ist die Umleitung zu https Schuld an dem Fehler.
return 301 https://dm500.frank.dyn-vpn.de$request_uri;
Die Frage ist jetzt nur wie die Config in diesem Punkt aussehem muss?
Moin,
könnte es sein, dass das Problem durch das neueste DSM Update gelöst wird ... oder aber dadurch verursacht wurde ? :)
Version: 6.2.2-24922-3
(2019-08-21)
Important Note
The update is expected to be available for all regions within the next few days, although the time of release in each region may vary slightly.
This update will restart your Synology NAS.
What's New
Updated the protocol of Let's Encrypt to ACME V2 to enhance the stability of the registration process.
....
Grüße,
Heiko
Moin Heiko,
das habe ich auch schon gelesen. Daran liegt es, wie ich jetzt weiß, nicht.
Ich hatte den Beitrag oben gerade editiert.
Zitat
Ich hatte gerade noch eine Idee und den Fehler gefunden. In der zusätzlichen Konfiguration ist die Umleitung zu https Schuld an dem Fehler.
return 301 https://dm500.frank.dyn-vpn.de$request_uri;
Die Frage ist jetzt nur wie die Konfig in diesem Punkt aussehen muss?
Änder die Umleitung doch einfach, das letsencrypt NICHT auf https umgebogen wird ...
Ich habe jetzt die Konfiguration so geändert:
server {
listen 80;
server_name dm500.frank.dyn-vpn.de;
location / {
return 301 https://dm500.frank.dyn-vpn.de$request_uri;
}
#Let's Encrypt
location ^~ /.well-known/acme-challenge {
root /var/lib/letsencrypt;
default_type text/plain;
}
}
Damit funktioniert es. Ist es das was Du meinst?
Jep .. würde es nur umdrehen. Die allgemeine location nach Unten .. ist aber eher Optisch als Funktionell interessant.