Raspberry Pi als Webserver einrichten

Inhaltsverzeichnis

Projektziel

Ein Raspberry Pi soll als Webserver aus dem Internet erreichbar sein. Dabei sollen Zertifikate von https://letsencrypt.org/ für die Transportverschlüsselung (https;//) verwendet werden., die von der Software https://traefik.io/traefik bereitgestellt werden. Es soll eine kostenlose Domainbezeichnung von https://ipv64.net/ für die Erreichbarkeit des Servers sorgen – auch wenn keine feste IP-Adresse durch unseren Provider vergeben wird. Zur Bereitstellung der Software werden Docker-Container verwendet. Dies soll eine spätere Erweiterung der Dienste erleichtern.

Vorbereitende Maßnahmen

  • Bereitstellung des Raspberry Pi
    Ich habe auf einem Raspberry Pi 5 das Betriebssystem Raspian Trixie Stand Dezember 2025 mit dem Imager-Tool von der Seite https://www.raspberrypi.com/software/ aufgespielt.
  • Anmeldung bei ipv64.net
    Hierzu auf der Seite https://ipv64.net/account.php registrieren und nach erfolgreicher Registrierung im Kundencenter rechts unten im Bereich Add DynDNS address eine neue Domain eintragen. Schon nach kurzer Zeit erscheint der Eintrag in der Liste der aktivierten Domainnamen:
    Hardcopy Liste Domains
    Mit dem kostenlosen Paket sind nur .ipv64.de-Domains möglich.
  • Den Router (hier eine Fritzbox) vorbereiten
    Die beiden Ports 80 und 443 müssen für unseren Raspi freigegeben werden.
    Die Menüfolge Internet -> Freigaben bringt uns zum Register Porfreigaben. Dort auf den Button „Gerät für Freigebe hinzufügen“ drücken und unseren Raspi auswählen und danach die 2 Ports freigeben:




    Das gleicher für den Port 443 HTTPS-Server wiederholen.

Installation von Software auf dem Rasperry Pi

Für den Betrieb der Container benötigen wir die Software docker. Weiterhin habe ich den Editor Geany und das Tool tree zur übersichtlichen Darstellung der Verzeichnisstruktur installiert

# Raspi Update
sudo apt update
sudo apt upgrade

# Editor Geany
sudo apt install geany geany-common libcanberra-gtk3-0 libcanberra-gtk3-module 

# Tools
sudo apt install tree

# Docker
#Docker Repository verwenden
# Add Docker's official GPG key:
sudo apt update
sudo apt install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# Add the repository to Apt sources:
sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/debian
Suites: $(. /etc/os-release && echo "$VERSION_CODENAME")
Components: stable
Signed-By: /etc/apt/keyrings/docker.asc
EOF

sudo apt update

#aktuelle Version installieren
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

#Prüfung ob Docker vorhanden ist
docker --version
docker compose version

# Den aktuellen Benutzer der Gruppe docker hinzufügen
sudo usermod -aG docker $USER

# Firewall installieren
sudo apt install ufw

#Default alle Eingänge blockieren
sudo ufw default deny incoming
sudo ufw default allow outgoing

#Wichtig: ssh erlauben
sudo ufw allow ssh

#Port 80 und 443 freigeben
sudo ufw allow 80,443/tcp

#Starten und Status prüfen
sudo ufw enable
sudo ufw status verbose

Raspian Trixie protokolliert die ssh-Anmeldungen nicht mehr in einer Log-Datei sondern mittels journalctl. Damit Traefik die ssh-Anmeldungen überwachen kann, installierenwir rsyslog. Dadurch wird die Logdatei /var/log/auth.log wieder befüllt.

sudo apt update && sudo apt install rsyslog
sudo systemctl enable --now rsyslog

Traefik als Container bereitstellen

Traefik ist ein Loadbalancer, kann durch Anwendung des ACME-Protokolls Zertifikate von Lets-Encrypt bereitstellen und verwendet crowdsec um bekannte IP-Adressen mit bösen Absichten zu sperren.

Auf der Homepage von https://goneuland.de/ existiert eine ausführliche Anleitung, um Traefik als Container bereitzustellen:
https://goneuland.de/traefik-ab-v3-6-mit-crowdsec-installieren-und-konfigurieren/

Die Anleitung verweist auf das dazugehörende Github-Projekt :
https://github.com/Psycho0verload/traefik-crowdsec-stack

Darin befindet sich eine README-Datei mit den ausführlichen Schriftt-für-Schritt-Anweisungen.
Abeichend davon habe ich mir das Verzeichnis /srv/containers als Zielordner ausgewählt.

Nach Ausführung der Einzelschritte habe ich eine Verzeichnisstruktur erhalten, die ich in dieser ZIP-Datei zur Verfügung stelle:

# ZIP-Datei herunterladen
https://lang-dieter.de/wp/uploads/2026/04/traefik_container.zip

# und entpacken
unzip traefik_container.zip 

# den Inhalt des srv-Verzeichnisses nach /srv kopieren
sudo mv traefik_container/srv /

# das tempräre Verzeichnis löschen
rm traefik-container -rf

# Zugriff auf das Verzeichnis /srv für den aktuellen Benutzer erlauben
sudo chown $USER:root /srv -R

Als Ergebnis liegt folgende Verzeichnisstruktur vor:

tree /srv

srv
└── containers
    └── traefik
        ├── boncer-key-firewall.txt
        ├── compose
        │   ├── crowdsec.yml
        │   ├── networks.yml
        │   ├── socket-proxy.yml
        │   ├── traefik-crowdsec-bouncer.yml
        │   └── traefik.yml
        ├── data
        │   ├── crowdsec
        │   │   ├── config
        │   │   │   ├── acquis.d
        │   │   │   ├── acquis.yaml
        │   │   │   ├── collections
        │   │   │   ├── config.yaml
        │   │   │   ├── console.yaml
        │   │   │   ├── contexts
        │   │   │   ├── dev.yaml
        │   │   │   ├── hub
        │   │   │   │   ├── collections
        │   │   │   │   │   └── crowdsecurity
        │   │   │   │   │       ├── base-http-scenarios.yaml
        │   │   │   │   │       ├── http-cve.yaml
        │   │   │   │   │       ├── linux.yaml
        │   │   │   │   │       ├── sshd.yaml
        │   │   │   │   │       ├── traefik.yaml
        │   │   │   │   │       └── whitelist-good-actors.yaml
        │   │   │   │   ├── contexts
        │   │   │   │   │   └── crowdsecurity
        │   │   │   │   │       ├── bf_base.yaml
        │   │   │   │   │       └── http_base.yaml
        │   │   │   │   ├── parsers
        │   │   │   │   │   ├── s00-raw
        │   │   │   │   │   │   └── crowdsecurity
        │   │   │   │   │   │       ├── cri-logs.yaml
        │   │   │   │   │   │       ├── docker-logs.yaml
        │   │   │   │   │   │       └── syslog-logs.yaml
        │   │   │   │   │   ├── s01-parse
        │   │   │   │   │   │   └── crowdsecurity
        │   │   │   │   │   │       ├── sshd-logs.yaml
        │   │   │   │   │   │       ├── sshd-success-logs.yaml
        │   │   │   │   │   │       └── traefik-logs.yaml
        │   │   │   │   │   └── s02-enrich
        │   │   │   │   │       └── crowdsecurity
        │   │   │   │   │           ├── dateparse-enrich.yaml
        │   │   │   │   │           ├── geoip-enrich.yaml
        │   │   │   │   │           ├── http-logs.yaml
        │   │   │   │   │           ├── public-dns-allowlist.yaml
        │   │   │   │   │           └── whitelists.yaml
        │   │   │   │   ├── postoverflows
        │   │   │   │   │   ├── s00-enrich
        │   │   │   │   │   │   └── crowdsecurity
        │   │   │   │   │   │       └── rdns.yaml
        │   │   │   │   │   └── s01-whitelist
        │   │   │   │   │       └── crowdsecurity
        │   │   │   │   │           ├── cdn-whitelist.yaml
        │   │   │   │   │           └── seo-bots-whitelist.yaml
        │   │   │   │   └── scenarios
        │   │   │   │       ├── crowdsecurity
        │   │   │   │       │   ├── apache_log4j2_cve-2021-44228.yaml
        │   │   │   │       │   ├── CVE-2017-9841.yaml
        │   │   │   │       │   ├── CVE-2019-18935.yaml
        │   │   │   │       │   ├── CVE-2022-26134.yaml
        │   │   │   │       │   ├── CVE-2022-35914.yaml
        │   │   │   │       │   ├── CVE-2022-37042.yaml
        │   │   │   │       │   ├── CVE-2022-40684.yaml
        │   │   │   │       │   ├── CVE-2022-41082.yaml
        │   │   │   │       │   ├── CVE-2022-41697.yaml
        │   │   │   │       │   ├── CVE-2022-42889.yaml
        │   │   │   │       │   ├── CVE-2022-44877.yaml
        │   │   │   │       │   ├── CVE-2022-46169.yaml
        │   │   │   │       │   ├── CVE-2023-22515.yaml
        │   │   │   │       │   ├── CVE-2023-22518.yaml
        │   │   │   │       │   ├── CVE-2023-49103.yaml
        │   │   │   │       │   ├── CVE-2024-0012.yaml
        │   │   │   │       │   ├── CVE-2024-38475.yaml
        │   │   │   │       │   ├── CVE-2024-9474.yaml
        │   │   │   │       │   ├── f5-big-ip-cve-2020-5902.yaml
        │   │   │   │       │   ├── fortinet-cve-2018-13379.yaml
        │   │   │   │       │   ├── grafana-cve-2021-43798.yaml
        │   │   │   │       │   ├── http-admin-interface-probing.yaml
        │   │   │   │       │   ├── http-backdoors-attempts.yaml
        │   │   │   │       │   ├── http-bad-user-agent.yaml
        │   │   │   │       │   ├── http-crawl-non_statics.yaml
        │   │   │   │       │   ├── http-cve-2021-41773.yaml
        │   │   │   │       │   ├── http-cve-2021-42013.yaml
        │   │   │   │       │   ├── http-cve-probing.yaml
        │   │   │   │       │   ├── http-generic-bf.yaml
        │   │   │   │       │   ├── http-generic-test.yaml
        │   │   │   │       │   ├── http-open-proxy.yaml
        │   │   │   │       │   ├── http-path-traversal-probing.yaml
        │   │   │   │       │   ├── http-probing.yaml
        │   │   │   │       │   ├── http-sap-interface-probing.yaml
        │   │   │   │       │   ├── http-sensitive-files.yaml
        │   │   │   │       │   ├── http-sqli-probing.yaml
        │   │   │   │       │   ├── http-wordpress-scan.yaml
        │   │   │   │       │   ├── http-xss-probing.yaml
        │   │   │   │       │   ├── jira_cve-2021-26086.yaml
        │   │   │   │       │   ├── netgear_rce.yaml
        │   │   │   │       │   ├── pulse-secure-sslvpn-cve-2019-11510.yaml
        │   │   │   │       │   ├── spring4shell_cve-2022-22965.yaml
        │   │   │   │       │   ├── ssh-bf.yaml
        │   │   │   │       │   ├── ssh-cve-2024-6387.yaml
        │   │   │   │       │   ├── ssh-generic-test.yaml
        │   │   │   │       │   ├── ssh-refused-conn.yaml
        │   │   │   │       │   ├── ssh-slow-bf.yaml
        │   │   │   │       │   ├── ssh-time-based-bf.yaml
        │   │   │   │       │   ├── thinkphp-cve-2018-20062.yaml
        │   │   │   │       │   ├── vmware-cve-2022-22954.yaml
        │   │   │   │       │   └── vmware-vcenter-vmsa-2021-0027.yaml
        │   │   │   │       └── ltsich
        │   │   │   │           └── http-w00tw00t.yaml
        │   │   │   ├── local_api_credentials.yaml
        │   │   │   ├── notifications
        │   │   │   │   ├── email.yaml
        │   │   │   │   ├── file.yaml
        │   │   │   │   ├── http.yaml
        │   │   │   │   ├── sentinel.yaml
        │   │   │   │   ├── slack.yaml
        │   │   │   │   └── splunk.yaml
        │   │   │   ├── online_api_credentials.yaml
        │   │   │   ├── parsers
        │   │   │   │   ├── s00-raw
        │   │   │   │   ├── s01-parse
        │   │   │   │   └── s02-enrich
        │   │   │   ├── patterns
        │   │   │   │   ├── aws
        │   │   │   │   ├── bacula
        │   │   │   │   ├── bro
        │   │   │   │   ├── cowrie_honeypot
        │   │   │   │   ├── exim
        │   │   │   │   ├── firewalls
        │   │   │   │   ├── haproxy
        │   │   │   │   ├── java
        │   │   │   │   ├── junos
        │   │   │   │   ├── linux-syslog
        │   │   │   │   ├── mcollective
        │   │   │   │   ├── modsecurity
        │   │   │   │   ├── mongodb
        │   │   │   │   ├── mysql
        │   │   │   │   ├── nagios
        │   │   │   │   ├── nginx
        │   │   │   │   ├── paths
        │   │   │   │   ├── postgresql
        │   │   │   │   ├── rails
        │   │   │   │   ├── redis
        │   │   │   │   ├── ruby
        │   │   │   │   ├── smb
        │   │   │   │   ├── ssh
        │   │   │   │   └── tcpdump
        │   │   │   ├── postoverflows
        │   │   │   │   ├── s00-enrich
        │   │   │   │   └── s01-whitelist
        │   │   │   ├── profiles.yaml
        │   │   │   ├── scenarios
        │   │   │   ├── simulation.yaml
        │   │   │   └── user.yaml
        │   │   └── data
        │   │       ├── admin_interfaces.txt
        │   │       ├── backdoors.txt
        │   │       ├── bad_user_agents.regex.txt
        │   │       ├── crowdsec.db
        │   │       ├── http_path_traversal.txt
        │   │       ├── jira_cve_2021-26086.txt
        │   │       ├── log4j2_cve_2021_44228.txt
        │   │       ├── sensitive_data.txt
        │   │       ├── sqli_probe_patterns.txt
        │   │       ├── thinkphp_cve_2018-20062.txt
        │   │       ├── trendy_cves_uris.json
        │   │       └── xss_probe_patterns.txt
        │   ├── socket-proxy
        │   ├── traefik
        │   │   ├── certs
        │   │   │   ├── acme_letsencrypt.json
        │   │   │   └── tls_letsencrypt.json
        │   │   ├── dynamic_conf
        │   │   │   ├── http.middlewares.default.org
        │   │   │   ├── http.middlewares.default-security-headers_iframe_erlaubt.yml
        │   │   │   ├── http.middlewares.default-security-headers.yml
        │   │   │   ├── http.middlewares.default-security-headers.yml.sample
        │   │   │   ├── http.middlewares.default.yml
        │   │   │   ├── http.middlewares.default.yml.sample
        │   │   │   ├── http.middlewares.gzip.yml
        │   │   │   ├── http.middlewares.gzip.yml.sample
        │   │   │   ├── http.middlewares.traefik-bouncer.yml
        │   │   │   ├── http.middlewares.traefik-bouncer.yml.sample
        │   │   │   ├── http.middlewares.traefik-dashboard-auth.yml
        │   │   │   ├── http.middlewares.traefik-dashboard-auth.yml.sample
        │   │   │   ├── tls.yml
        │   │   │   └── tls.yml.sample
        │   │   ├── dynamic_off
        │   │   │   └── forward-raspi5.yml
        │   │   ├── traefik.yml
        │   │   └── traefik.yml.sample
        │   └── traefik-crowdsec-bouncer
        ├── docker-compose.yml
        ├── first_install.sh
        └── README.md

47 directories, 153 files

Anpassung an die gewünschte Domain:

Beginnen wir mit der Definiton der Angaben zur Subdomain, unter der wir die Verwaltungsoberfläche von Traefik erreichen mchten.. Hierzu müssen wir die Datei /srv/containers/traefik/.env bearbeiten:

# Schreib- und Leserecht setzen
sudo chmod 755 /srv/containers/traefik/.env

# Datei im gewünschten Editor öffen - hier der nano-Editor
nano /srv/containers/traefik/.env

Der im Bild markierte Text [domainname.de] muss mit dem gewünschten Domainnamen ohne www. am Anfang befüllt werden. Anstatt www. steht ja schon die Angabe wir traefik. in der Datei.

Hardcop .env-Datei

Als nächstes müssen wir noch die für LetsEncrypt benötigten Angaben einpflegen. Hierzu müssen wir die Datei /srv/containers/traefik/data/traefik/traefik.yml bearbeiten und an zwei Stellen eine gültige E-Mail-Adresse eintragen. Diese dient der Errichbarkeit für Letsencrypt falls die Notwendigkeit zu einer Kontaktaufnahme besteht. Ersetzen Sie die Angabe <IHRE EMAIL_ADRESSE> durch die gewünschte E-Mail-Adresse:
Hardcopy LetsEncrypt

Nun können wir schon mal testen, ob der Container funktioniert. Da in der docker-compose-Datei der aktuelle Pfad ermittelt und als Pfadangabe in diversen Unterbereichen verwendet wird, müssen wir uns erst in das Traefik-Verzeichnis begeben. Dann können wir mit dem Parameter config die Datei prüfen. Wenn dabei kein Fehler angezeigt wird, wir der Container manuell gestartet..

# in das Traefik-Verzeichnis wechseln
cd /srv/containers/traefik/

# Docker-Datei testen
docker compose config

# wenn die Datei ohne Fehlermeldung durchläuft und angezeigt wird
docker compose up

Beim ersten Aufruf dauert es etwas länger, dai die Container-Images erst heruntergeladen werden. Diesen Vorgang nennt man pulling.
Hardcopy pulling

Jetzt können Sie live am Bildschirm den Aufbau der Container verfolgen und dabei auch schon sehen, daß traefik und crowdsec miteinander kommunizieren.

Woher kommen die Zertifikate ?

LetsEncrypt verwendet das ACME-Protokoll zur Bereitstellung der Zertifikate. Unser Traefik meldet sich bei LetsEncrypt und teilt mit, für welche Domain ein Zertifikat erwünscht wird. Darauf hin prüft LetsEncrypt, ob es unter http://www.<beantragte Domain>.de eien bestimmte Antwort zurückkommt. Wenn dies mit Erfolg beschieden ist, wird ein Zertifkat erstellt und an uns übermittelt. Diesen Vorgang erledigt Traefik für uns ganz automatisch im Hintergrund. Bei Ablauf der Gültigkeitsdauer des ausgestellten Zertifikates, wird von Traefik automatisch auf die gleiche Art und Weise ein neues Zertifkat beantragt.

Prüfung der Zertifikatsbeantragung

Hierzu müssen wir einen Blick auf die Logdatei von Traefik werfen. Der Container ist so eingestellt, dass dies auf dem Host-Rechner als /var/log/traefik/traefik.log gespeichert wird. Hier sehen wir, dass der Vorgang fehlgeschlagen ist. Der Grund liegt darin, das wir noch keine Porfreigabe im Internet-Router eingetragen haben und somit die Rückfrage von LetsEncrypt misslingt.

cat /var/log/traefik/traefik.log | grep error

{"level":"error","error":"error while adding rule HostSNI(`traefik.[lang-dieter.de]`): invalid value for HostSNI matcher, \"traefik.[lang-dieter.de]\" is not a valid hostname","time":"2026-04-20T12:33:18+02:00","message":"Error while adding route for host"}
{"level":"error","providerName":"tls_resolver.acme","acmeCA":"https://acme-v02.api.letsencrypt.org/directory","providerName":"tls_resolver.acme","ACME CA":"https://acme-v02.api.letsencrypt.org/directory","routerName":"traefik-dashboard@docker","rule":"HOST(`traefik.[lang-dieter.de]`)","error":"unable to generate a certificate for the domains [traefik.[lang-dieter.de]]: acme: error: 400 :: POST :: https://acme-v02.api.letsencrypt.org/acme/new-order :: urn:ietf:params:acme:error:rejectedIdentifier :: Invalid identifiers requested :: Cannot issue for \"traefik.[lang-dieter.de]\": Domain name contains an invalid character","domains":["traefik.[lang-dieter.de]"],"time":"2026-04-20T12:33:19+02:00","message":"Unable to obtain ACME certificate for domains"}

Regel für Weiterleitung im Internet-Router eintragen

Damit der Raspi Pakete aus dem Internet erreichen können, müssen wir in unserem Router die Ports 80 und 443 an unseren Raspi weiterleiten. In meiner Fritzbox musste ich hierzu die Menüfolge:
Internet -> Freigaben aufrufen und dann „Gerät für Freigabe hinzufügen.“ Hier das Ergebnis:

Nach einem Neustart des Containers sollten in der Datei /var/log/traefik/traefik.log keine Fehlermeldungen mehr auftauchen und die Bestätigung des Zertifikates als erfolgreich zu sehen sein:

cat /var/log/traefik/traefik.log | grep acme

{"level":"info","time":"2026-04-21T09:36:13+02:00","message":"Starting provider *acme.ChallengeTLSALPN"}
{"level":"info","time":"2026-04-21T09:36:13+02:00","message":"Starting provider *acme.Provider"}
{"level":"info","providerName":"tls_resolver.acme","acmeCA":"https://acme-v02.api.letsencrypt.org/directory","time":"2026-04-21T09:36:13+02:00","message":"Testing certificate renew..."}
{"level":"info","time":"2026-04-21T09:36:13+02:00","message":"Starting provider *acme.Provider"}
{"level":"info","providerName":"http_resolver.acme","acmeCA":"https://acme-v02.api.letsencrypt.org/directory","time":"2026-04-21T09:36:13+02:00","message":"Testing certificate renew..."}

Erster Onlinezugriff auf unser eigenes Traefik-Portal

Nun können wir im Browser unter der Adresse https://traefik.unsere-domain.de das eigene Traefik-Portal aufrufen. Das Kennwort dazu wurde im Kapitel Traefik konfigurieren gesetzt.

Jetzt müssen wir nur noch einen Container als Webserver hinzufügen.

Anbindung des Servers mittel IP V6 – ohne eigene Domain

Leider musste ich feststellen, daß ich von meinem Provider https://www.wemaconnect.de/ keine echten öffentlichen IPV6-Adressen erhalte. Auf der Seite mit den Service-Hinweisen wird sogar die komplette Abschaltung der IP-V6-Unterstützung im Router gefordert. Willkommen im Jahre 2026 !

Ich bekommen nur IP-V6-Adressen, die mit 2002:: beginnen. (6to4-Tunnelprotokoll). Diese werden von LetsEncrypt nicht unterstützt, weil sie als nicht vertraueswürdig gelten. Siehe hierzu diesen Forumseintrag aus dem Jahre 2016 !
https://community.letsencrypt.org/t/problems-validating-ipv6-against-host-running-6to4/18312/10
Forum LetsEncrypt

Deshalb funktoniert bei mir im Moment die untenstehende Anleitung noch nicht. Wenn Sie auch keine öffentlichen IP-V6 erhalten, bleibt nur die Anbindung mittels IP-V4. Bei mehr verwende ich hierzu eine fixe IP4-Adresse, die mir mein Provider bei jedem Verbindungsaufbau mit gleichen Inhalt zuteilt.

Meine Domain ist schon mittel IP-V4 an einem anderen Container in Betrieb, um meine Website auszuliefern.
Deshalb zeige ich hier, wie man einen Raspi ohne feste IP-Adresse ohne kostenpfichtige Domain im Internet veröffentlicht.

Zu Beginn des Beitrages haben wir uns ja sćhon bei IPv64.net angemeldet. Melden wir uns also auf der Webseite https://ipv64.net/account an und gehen auf den Button „Domains-DynDNS“ um uns die Liste unsere vorhandenen Domains anzuzeigen. Ich verwende hier im weitern Verlauf die Domain:
demoweb.ipv64.de:
DomaiinÜbersicht
Drücken Sie nun de Button „Edit Domain“ um auf die Seite mit den Einstellungen zu Ihrer Domain zu gelangen. Dort scrollen Sie etwas nach unten, bis zur Auswahl der Update-URLs kommen.
Mit der Auswahl „Domain Update-URL“ können wir für jede Domain einen eigenen Schlüssel festlegen.
Klicken Sie in dieser Zeile auf das Symbole für Kopie in Zwischenablage und Sie erhalten die aktuelle Update-URL die z. B. so aussieht:
https://ipv64.net/nic/update?key=JDyosWG9mMv2rL648T05QnNIqR3UcwzC

Den könner wir hier manuell aktualisieren.
Updat URL

Danach lassen wir uns durch Klick auf die Menüflge DynDNS -> Anleitungen nach Auswhahl unser Domain und des Zielgerätes Raspberry Pi die Befehlszeile für crontab anzeigen.
Wir rufen den Editor für crontab auf:

crontab -e

und tragen die Zeile mit dem aktuellen Schlüssel ein:

0 */2 * * * curl -sSL "https://ipv64.net/nic/update?key=JDyosWG9mMv2rL648T05QnNIqR3UcwzC&domain=demoweb.ipv64.de"

Es muss alles in einer Zeile eingetragen werden. Nach dem ? ist kein Zeilenwechsel vorhanden.

Nun meldet sich der Raspi alle 2 Stunden und somit ist IPv64.net bekannt, unter welcher IP-Adresse unser Computer zu erreichen ist. Wir können den Befehl auch manuell ausführen:

curl -sSL "https://ipv64.net/nic/update?key=JDyosWG9mMv2rL648T05QnNIqR3UcwzC&domain=demoweb.ipv64.de"

# und seen in der Antwort die erfolgreiche Verbindung
{"info":"","status":"success","ip":{"ipv4":"ignore"}

Webserver hinzufügen

Wenn keine Fehler im Log sichtbar sind, ist unser Raspi aus dem Internet erreichbar und wir können testweise einen Webserver in unserer Konfiguration hinzufügen. Ich verwende hier den Caddy und gehe wie folgt vor:
Eine neue Ordnerstruktur für den Container anlegen:

mkdir -p /srv/container/caddy_web/html

Die Datei srv/containers/caddy_web/docker-compose.yaml neu anlegen:

nano /srv/containers/caddy_web/docker-compose.yaml 
services:
  caddy-webserver:
    image: caddy:alpine
    container_name: caddy_backend
    restart: unless-stopped
    volumes:
      - ./html:/usr/share/caddy:ro        # die HTML-Dateien
      - ./Caddyfile:/etc/caddy/Caddyfile  # die Konfiguration
    networks:
      - proxy # Das Netzwerk, in dem dein Traefik läuft
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.mywebserver.rule=Host(`www.lang-dieter.de`)" # Deine Domain
      - "traefik.http.routers.mywebserver.entrypoints=websecure" # Schaltet um auf https
      - "traefik.http.routers.mywebserver.tls.certresolver=tls_resolver" # Dein Resolver-Name
      - "traefik.http.services.mywebserver.loadbalancer.server.port=80" # Port, unter dem der Webserver von Außen erreichbar ist

networks:
  proxy:
    external: true

Die Datei mit den Caddy-Einstellungen anlegen:
nano /srv/containers/caddy_web/docker-compose.yaml

:80 {
    root * /usr/share/caddy

	# Dies aktiviert das Logging in die Standardausgabe (Docker Logs)
    log {
        format console
    }



    route {
        # 1. Statische Dateien (werden sofort beendet, kein Redirect nach /wp)
        handle /robots.txt {
            file_server
        }

        handle /index.html {
            file_server
        }
        handle /410.html {
            file_server
        }

        file_server
    }

}

Und in das Verzeichnis html noch eine Testdatei namens
/srv/containers/caddy_web/html/index.html
anlegen:

<!DOCTYPE html>
<html lang="de">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Caddy Testseite</title>
    <style>
        body { font-family: sans-serif; display: flex; justify-content: center; align-items: center; height: 100vh; background-color: #f4f4f9; margin: 0; }
        .card { background: white; padding: 2rem; border-radius: 10px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); text-align: center; }
        h1 { color: #007bff; }
        .status { color: green; font-weight: bold; }
    </style>
</head>
<body>
    <div class="card">
        <h1>Caddy @ Raspi Neu</h1>
        <p>Der Webserver läuft erfolgreich hinter <strong>Traefik</strong>.</p>
        <p class="status">✓ SSL/TLS Verbindung ist aktiv</p>
    </div>
</body>
</html>

Nun sollte der Aufruf von https:/www.demoweb.ipv64.de funktionieren:


html-Verzeichnis mit Inhalt füllen

Wie sie WordPress als offline-CMS einrichten um damit den Inhalt Ihrer Webseite zu erstellen, habe ich im Beitrag https://www.lang-dieter.de/wp/posts/wordpress-offline-cms-static-html/ beschrieben.