Bei Contabo wird Webmin — sofern als Option mitgebucht — standardmäßig auf einer automatisch generierten Subdomain (vmd<id>.contaboserver.net:10000) bereitgestellt, üblicherweise mit einem selbstsignierten Zertifikat. Das ist für den produktiven Betrieb ungeeignet, da Browser warnen und Anmeldedaten auf einem nicht vertrauenswürdig signierten Kanal eingegeben werden müssten. In dieser Anleitung sicherst du Webmin mit einem kostenlosen Let's Encrypt SSL-Zertifikat ab, machst es über deine eigene Domain erreichbar und setzt Nginx als Reverse Proxy davor — der saubere Standard-Aufbau.

Vorbereitung

Diese Anleitung setzt folgenden Stand voraus:

  • VPS: Du hast Zugriff auf deinen Contabo-VPS per SSH und kannst sudo nutzen.
  • Webmin: Webmin ist installiert (entweder als Contabo-Option oder manuell aus dem offiziellen Repository) und unter https://<contabo-host>:10000 erreichbar.
  • Nginx: Nginx ist installiert und läuft (systemctl status nginx).
  • Certbot: Certbot wird im weiteren Verlauf installiert — du brauchst es noch nicht vorab.
  • Domain: Du besitzt eine Domain und hast Zugriff auf deren DNS-Verwaltung.

Betriebssystem: Beispiele basieren auf Ubuntu 22.04/24.04 bzw. Debian 12. Auf anderen Distributionen weichen Paketnamen und Pfade leicht ab.

Firewall am Anfang: Solange du Webmin noch direkt aufrufen können musst, muss Port 10000 (TCP) erreichbar sein. Sobald der Reverse Proxy fertig steht (Abschnitt 7), schließen wir Port 10000 wieder — Webmin lauscht dann nur noch auf Loopback.

DNS-Eintrag

Ziel: Webmin ist unter webmin.mydomain.com erreichbar (Domain natürlich durch deine ersetzen).

Damit das Routing funktioniert, muss ein A-Record für die Subdomain auf die öffentliche IPv4-Adresse deines VPS zeigen. Wenn dein Server eine IPv6-Adresse hat, kommt zusätzlich ein AAAA-Record dazu.

Beispiel-DNS-Konfiguration

TypNameValue/ZielTTL
Awebmin203.0.113.423600
AAAAwebmin2001:db8::423600
A@203.0.113.423600
CNAMEwwwmydomain.com.3600

Hinweis: 203.0.113.42 und 2001:db8::42 sind Dokumentations-IPs (RFC 5737 / RFC 3849). Ersetze sie durch die tatsächliche IP deines VPS — diese findest du im Contabo-Kundenportal oder per ip -4 addr show direkt auf dem Server. Für Webmin selbst ist nur der A-Record (und ggf. AAAA) für webmin zwingend; die übrigen Zeilen sind nur als Beispiel für eine vollständige Domain-Konfiguration aufgeführt.

A-Records nehmen ausschließlich IP-Adressen entgegen, niemals Domainnamen — dafür gibt es CNAME. Eine häufige Stolperfalle.

Nach dem Speichern dauert die DNS-Propagation je nach TTL und Provider zwischen Sekunden und einigen Stunden. Prüfen kannst du sie z. B. so:

Bash
dig +short webmin.mydomain.com A
# erwartet: 203.0.113.42

Hostname und /etc/hosts (optional)

Damit der Server selbst seinen eigenen FQDN korrekt auflöst — was z. B. bei Hostname-basierten Logs, Mail-Versand und einigen Webmin-Selbstchecks praktisch ist — kann ein lokaler Eintrag in /etc/hosts sinnvoll sein.

Wichtig zur Klarstellung: /etc/hosts hat keinen Einfluss darauf, ob dein Server von außen über webmin.mydomain.com erreichbar ist. Das regelt ausschließlich der DNS-Eintrag aus Abschnitt 2. Der Hosts-Eintrag ist eine reine lokale Namensauflösung auf dem Server.

Konfiguration /etc/hosts
127.0.0.1     localhost
203.0.113.42  mydomain.com webmin.mydomain.com

VPS - Hosts Eintrag - Subdomain

Certbot installieren und Zertifikat ausstellen

Wir nutzen den Webroot-Authenticator von Certbot. Vorteil gegenüber --standalone: Nginx muss für die Ausstellung und für jedes Renewal nicht gestoppt werden — Certbot legt die ACME-Challenge einfach in einem Verzeichnis ab, das der laufende Webserver ausliefert.

1 — System aktualisieren

Bash
sudo apt update && sudo apt upgrade -y

2 — Certbot installieren

Bash
sudo apt install certbot -y

Auf älteren Systemen (Ubuntu 20.04 und davor) wird die Snap-Variante von Certbot empfohlen — siehe certbot.eff.org. Die Konfiguration im Folgenden bleibt identisch.

3 — Minimal-Vhost für die ACME-Challenge anlegen

Damit der Webroot-Authenticator funktioniert, braucht es einen Server-Block, der auf Port 80 für webmin.mydomain.com antwortet und das Verzeichnis /var/www/html ausliefert. Lege dafür /etc/nginx/sites-available/webmin.mydomain.com an:

Nginx /etc/nginx/sites-available/webmin.mydomain.com
server {
    listen 80;
    listen [::]:80;
    server_name webmin.mydomain.com;
    root /var/www/html;
}

Symlink in sites-enabled setzen, Konfiguration prüfen und Nginx neu laden:

Bash
sudo ln -s /etc/nginx/sites-available/webmin.mydomain.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

4 — Zertifikat ausstellen

Bash
sudo certbot certonly --webroot -w /var/www/html -d webmin.mydomain.com

Certbot fragt nach E-Mail und AGB-Zustimmung, legt eine ACME-Challenge unter /var/www/html/.well-known/acme-challenge/ ab und stellt das Zertifikat aus. Der Vhost bleibt dabei in dem minimalen Zustand aus Schritt 3 — den finalen Reverse-Proxy-Block schreiben wir gleich selbst (Abschnitt 6). Das hält die Konfiguration deterministisch und nicht durch Certbot-Manipulation überschrieben.

Die Zertifikatsdateien liegen anschließend hier:

Pfade
/etc/letsencrypt/live/webmin.mydomain.com/fullchain.pem
/etc/letsencrypt/live/webmin.mydomain.com/privkey.pem

Renewal läuft danach automatisch via systemd-Timer (systemctl list-timers | grep certbot); ein manueller Probe-Lauf:

Bash
sudo certbot renew --dry-run

Webmin auf Loopback umstellen

Webmin bringt einen eigenen Mini-Webserver (miniserv) mit. Damit der Reverse Proxy davor sauber funktioniert, soll Webmin

  • nur noch auf 127.0.0.1 lauschen (nicht mehr öffentlich),
  • den ursprünglichen Port 10000 behalten,
  • intern kein TLS mehr machen — Nginx terminiert HTTPS außen, intern reicht Klartext über Loopback.

Öffne /etc/webmin/miniserv.conf und passe folgende Werte an (bzw. ergänze sie):

Konfiguration /etc/webmin/miniserv.conf
bind=127.0.0.1
port=10000
ssl=0
# Webmin akzeptiert sonst nur Requests, deren Host-Header zur eigenen
# Erkennung passt — die Subdomain explizit erlauben:
referers=webmin.mydomain.com
# Damit Webmin X-Forwarded-Proto/Host vom Reverse Proxy auswertet
# und Redirects korrekt mit https:// erzeugt:
trust_x_forwarded=1

Webmin neu starten:

Bash
sudo systemctl restart webmin

Warum nicht port=443? Auf Port 443 lauscht ab Abschnitt 6 Nginx. Webmin auf 443 zu legen würde nur deshalb funktionieren, weil es ausschließlich an 127.0.0.1 bindet — verwirrend, fehleranfällig und ohne Vorteil. Der Standard ist: Webmin bleibt auf 10000 (intern), der Proxy regelt 443 nach außen.

Nginx als Reverse Proxy

Jetzt erweitern wir die in Abschnitt 4 angelegte Server-Konfiguration zu einem vollwertigen Reverse Proxy. Öffne /etc/nginx/sites-available/webmin.mydomain.com erneut und ersetze den Inhalt durch:

Nginx /etc/nginx/sites-available/webmin.mydomain.com
server {
    listen 80;
    listen [::]:80;
    server_name webmin.mydomain.com;

    # ACME-Challenges für Renewal weiter erlauben, alles andere
    # auf HTTPS umleiten.
    location /.well-known/acme-challenge/ {
        root /var/www/html;
    }

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

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name webmin.mydomain.com;

    ssl_certificate     /etc/letsencrypt/live/webmin.mydomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/webmin.mydomain.com/privkey.pem;

    # Sicherheitsheader
    add_header Strict-Transport-Security "max-age=31536000" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;

    # Webmin-Uploads (Module-Installer, Backups) brauchen Spielraum.
    client_max_body_size 256M;

    location / {
        proxy_pass         http://127.0.0.1:10000;
        proxy_http_version 1.1;
        proxy_set_header   Host              $host;
        proxy_set_header   X-Real-IP         $remote_addr;
        proxy_set_header   X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;

        # Webmin-Sessions sind teils langlebig (Updates, Backups).
        proxy_read_timeout 300s;
    }
}

Konfiguration prüfen und neu laden:

Bash
sudo nginx -t
sudo systemctl reload nginx

Kein includeSubDomains und kein preload im HSTS-Header — beides verbietet sich, solange du nicht für alle Subdomains von mydomain.com HTTPS garantieren kannst. Setze diese Flags erst bewusst, wenn du das gesamte Setup verstanden hast.

Firewall schließen und Setup verifizieren

Da Webmin nun ausschließlich über den Reverse Proxy erreichbar sein soll, kann (und sollte) Port 10000 nach außen geschlossen werden:

Bash ufw
sudo ufw delete allow 10000/tcp   # falls vorher freigegeben
sudo ufw status verbose

Alternativ mit nftables oder iptables — entscheidend ist, dass 10000 von außen nicht mehr erreichbar ist. Test von einem anderen Host:

Bash
curl -v --max-time 5 https://<server-ip>:10000   # sollte Timeout werfen
curl -I https://webmin.mydomain.com              # 200 OK + gültiges Cert

Erwartetes Ergebnis

  • https://webmin.mydomain.com öffnet das Webmin-Login mit gültigem Let's-Encrypt-Zertifikat.
  • HTTP-Aufrufe (http://...) werden auf HTTPS umgeleitet.
  • Direkter Zugriff auf :10000 von außen ist blockiert.
  • Renewal läuft per systemd-Timer alle 12 h, ohne dass Nginx oder Webmin manuell gestoppt werden müssen.

Damit ist der Webmin-Admin-Zugang produktionsreif aufgesetzt: korrekt signiert, hinter einem Reverse Proxy, nicht öffentlich exponiert und mit automatischer Zertifikatserneuerung.

/ Weiter

Zurück zu Cloud & VPS-Anbieter

Zur Übersicht