.htpasswd-Datei erstellen: Leitfaden zur HTTP-Basic-Authentifizierung
Eine .htpasswd-Datei ist der serverseitige Speicher für die Anmeldedaten der HTTP-Basic-Authentifizierung: eine reine Textdatei, in der jede Zeile ein username:hash-Paar enthält. Eine solche Datei zu erstellen heißt: diese gehashte Zeile erzeugen und an einem Ort ablegen, den Ihr Webserver lesen kann. Dafür gibt es drei Wege:
- Den Befehl
htpasswd(ausapache2-utils/httpd-tools) — das kanonische Werkzeug. openssl passwd— fast überall bereits installiert, kein zusätzliches Paket nötig.- Im Browser — verwenden Sie den htpasswd-Generator, um einen Eintrag lokal zu erzeugen, ganz ohne Installation und ohne dass etwas über das Netzwerk gesendet wird.
Dieser Leitfaden geht über den Einzeiler hinaus: wie der Basic-Auth-Handshake abläuft, wie Sie die Datei auf drei Wegen erstellen, welches der fünf Hash-Formate sich für Ihren Fall eignet, wie Sie das Ganze in Apache, nginx, Docker, Kubernetes, Caddy und Traefik einbinden und wie Sie verhindern, dass die Anmeldedatei für jeden zum Download bereitliegt.
Was ist eine .htpasswd-Datei?
Jede Zeile in einer .htpasswd-Datei enthält die Anmeldedaten eines Benutzers als durch Doppelpunkt getrenntes Paar. Den Benutzernamen speichert die Datei unverändert; das Passwort dagegen nur als Einweg-Hash, sodass der Klartext nie auf der Festplatte landet. Eine einzelne bcrypt-Zeile sieht so aus:
admin : $2y$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy
│ │
└─ username └─ hash (algorithm prefix $2y$ + cost + salt + digest)
Der Benutzername steht zuerst, dann ein einzelner :, dann der Hash. Ein Benutzername darf bis zu 255 Byte lang sein und darf niemals einen Doppelpunkt enthalten, da der Doppelpunkt das Feldtrennzeichen ist. Der Hash trägt seinen eigenen Algorithmus-Marker als Präfix ($2y$ für bcrypt, $apr1$ für Apache MD5, {SHA} für SHA-1), sodass der Server ohne zusätzliche Konfiguration weiß, wie er ihn verifizieren muss.
Für mehrere Benutzer fügen Sie pro Benutzer eine Zeile hinzu:
admin:$2y$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy
alice:$2y$10$3bQ8xY7tLp2mZ0xW5cR4fO9vK1jH6sD2nG8aQ5wE3rT7uI4oP1cm
bob:$apr1$mZ0xW5cR$4fK1jH6sD2nG8aQ5wE3rT2
Algorithmen können in derselben Datei gemischt werden. Der Server liest jede Zeile, erkennt das Format am Präfix und verifiziert gegen das jeweils verwendete Verfahren. Hier koexistieren zwei bcrypt-Benutzer und ein apr1-Benutzer problemlos.
.htpasswd vs. .htaccess
Diese beiden werden ständig verwechselt, weil sie auf Apache gemeinsam auftreten, aber sie haben unterschiedliche Aufgaben. .htaccess ist Apaches Konfigurationsdatei je Verzeichnis. Sie enthält Direktiven — darunter jene, die Basic Auth aktivieren und auf Ihren Anmeldedaten-Speicher verweisen. .htpasswd ist die Anmeldedaten-Datenbank — nur die username:hash-Zeilen, keine Konfiguration.
Kurz gesagt: .htaccess legt fest, dass ein Verzeichnis eine Anmeldung erfordert und wo die Benutzerliste zu finden ist; .htpasswd ist diese Benutzerliste. nginx verwendet .htaccess überhaupt nicht — seine Basic-Auth-Konfiguration steht im server- oder location-Block der Hauptkonfiguration, liest aber dasselbe .htpasswd-Anmeldedatenformat.
So funktioniert die HTTP-Basic-Authentifizierung
Die HTTP-Basic-Authentifizierung ist ein Challenge-Response-Handshake, der direkt in der HTTP-Spezifikation steht. Kennen Sie die drei Schritte, lässt sich später fast jeder Fehler zügig eingrenzen:
- Der Client fordert eine geschützte Ressource an — ohne Anmeldedaten.
- Der Server antwortet mit
401 Unauthorizedund fügt einen HeaderWWW-Authenticate: Basic realm="..."hinzu — das ist die Challenge. - Der Client wiederholt die Anfrage mit einem Header
Authorization: Basic <base64(user:password)>. Stimmen die Anmeldedaten mit einer Zeile in der.htpasswd-Datei überein, liefert der Server die Ressource aus.
Das ist das gesamte Protokoll. Kein Anmeldeformular, kein Sitzungs-Cookie, kein Token. Jede weitere Anfrage trägt denselben Header.
Die 401-/WWW-Authenticate-Challenge
Der WWW-Authenticate-Header erfüllt zwei Aufgaben. Sein Basic-Token sagt dem Client, welches Schema er verwenden soll; seine realm-Zeichenkette benennt den Schutzbereich. Browser zeigen den Realm-Text im Anmeldedialog an („Die Website meldet: …”) und nutzen ihn als Cache-Schlüssel. Anmeldedaten, die Sie für einen Realm eingeben, gelten dann auch für andere URLs im selben Realm — Sie müssen sie nicht auf jeder Seite neu eintippen.
Hier der rohe Austausch, mit curl -i aufgezeichnet:
$ curl -i https://example.com/admin/
HTTP/2 401
www-authenticate: Basic realm="Restricted Area"
$ curl -i -u admin:s3cret https://example.com/admin/
HTTP/2 200
Der Authorization: Basic-Header
Der Client sendet die Anmeldedaten als base64(username:password). Das ist die wichtigste Sicherheitstatsache zu Basic Auth: base64 ist Kodierung, keine Verschlüsselung. Jeder kann es vollständig umkehren, die Anmeldedaten gehen also praktisch im Klartext über die Leitung. Den Hin- und Rückweg können Sie selbst nachvollziehen:
# Encode the credential the way a browser does
printf 'admin:s3cret' | base64
# → YWRtaW46czNjcmV0
# Anyone who captures the header can decode it instantly
printf 'YWRtaW46czNjcmV0' | base64 -d
# → admin:s3cret
Diese Umkehrbarkeit ist der Grund, warum Basic Auth über HTTPS laufen muss — ohne TLS ist das Passwort für jeden im Netzwerkpfad lesbar. Wenn Sie diesen Header von Hand erstellen oder untersuchen möchten, führt der Base64-Dekodierer/-Kodierer dieselbe user:password-Transformation im Browser durch.
So erstellen Sie eine .htpasswd-Datei
Es gibt drei praktikable Wege, die Datei zu erstellen. Wählen Sie je nachdem, was installiert ist und wo das Passwort liegen soll.
Mit dem htpasswd-Befehl
Die htpasswd-Binärdatei ist Teil von Apaches Hilfspaket. Installieren Sie es zuerst:
# Debian / Ubuntu
sudo apt install apache2-utils
# RHEL / CentOS / Fedora
sudo yum install httpd-tools
Erstellen Sie die Datei und ihren ersten Benutzer. Die Option -c bedeutet create und überschreibt eine vorhandene Datei — verwenden Sie sie nur das allererste Mal:
htpasswd -c /etc/nginx/.htpasswd admin
# prompts twice for the password, then writes the file
Um weitere Benutzer hinzuzufügen, lassen Sie -c weg, sodass Sie anhängen statt zu überschreiben:
htpasswd /etc/nginx/.htpasswd alice
Um statt der Plattform-Vorgabe bcrypt zu erzwingen, ergänzen Sie -B. Um den Eintrag nach stdout auszugeben, ohne eine Datei anzufassen — praktisch zum Weiterleiten in eine Konfiguration oder ein Dockerfile —, kombinieren Sie -b (Passwort auf der Kommandozeile) und -n (keine Datei):
htpasswd -Bbn admin 's3cret'
# → admin:$2y$10$N9qo8uLOickgx2ZMRZoMye...
Die Optionen, die Sie tatsächlich verwenden werden:
| Option | Bedeutung |
|---|---|
-c | Eine neue Datei erstellen (überschreibt, falls vorhanden) — nur für den ersten Benutzer |
-B | bcrypt verwenden |
-b | Das Passwort als Kommandozeilenargument übergeben (keine Eingabeaufforderung) |
-n | Nach stdout ausgeben, statt in eine Datei zu schreiben |
-D | Den genannten Benutzer aus der Datei löschen |
Ein Vorbehalt bei -b: Das Passwort landet in Ihrem Shell-Verlauf. Für einmalige Produktiv-Anmeldedaten bevorzugen Sie die abgefragte Form oder die Browser-Option weiter unten.
Ohne apache2-utils — mit OpenSSL
Keine htpasswd-Binärdatei? OpenSSL ist auf praktisch jedem System vorhanden und kann direkt einen apr1-Hash erzeugen. Verpacken Sie es in printf, um eine vollständige Zeile zu bauen:
printf "admin:$(openssl passwd -apr1 's3cret')\n" >> /etc/nginx/.htpasswd
# admin:$apr1$k3l4Hj9.$qN8vY7tLp2mZ0xW5cR4f.
Das apr1-Format läuft sowohl auf Apache als auch auf nginx. Auf einer minimalen Maschine ist das der Weg mit den wenigsten Abhängigkeiten.
Im Browser — keine Installation, kein Leck
Wenn Sie kein Paket installieren möchten oder ein Produktiv-Passwort lieber nicht in eine Shell tippen, wo es in ~/.bash_history landet, erzeugen Sie den Eintrag clientseitig. Der htpasswd-Generator berechnet bcrypt-, apr1- und SHA-1-Hashes vollständig in Ihrem Browser, liefert Ihnen eine einfügefertige user:hash-Zeile samt passendem Server-Konfigurationsblock und überträgt niemals etwas. Erzeugen Sie dort gleich ein starkes, eindeutiges Passwort mit dem Zufallspasswort-Generator, statt eines wiederzuverwenden.
htpasswd-Passwortformate im Vergleich
Der htpasswd-Befehl kann fünf Formate ausgeben, und sie sind nicht gleichwertig. Diese Tabelle ist die Schnellreferenz für die Auswahl:
| Format | Präfix | Gesalzen | Stärke | Verwenden für |
|---|---|---|---|---|
| bcrypt | $2y$ | Ja | Am stärksten | Apache, Docker Registry, Caddy, Traefik |
| apr1 (Apache MD5) | $apr1$ | Ja | Mittel | nginx (portierbar, sichere Vorgabe) |
| SHA-1 | {SHA} | Nein | Schwach | Nur für Legacy-Kompatibilität |
| crypt (DES) | (keines) | Ja (2 Zeichen) | Sehr schwach | Nicht verwenden |
| plain | (keines) | Nein | Keine | Nur für lokale Tests |
Dazu ein paar Details, die in keine Tabellenzelle passen. bcrypt verwendet ein zufälliges 16-Byte-Salt und einen adaptiven Kostenfaktor (Vorgabe 10, moderne Empfehlung 12). Identische Passwörter erzeugen damit unterschiedliche Hashes, und der Arbeitsaufwand skaliert mit der Hardware. Eine Eigenheit hat bcrypt: Es kürzt das Passwort bei 72 Byte und ignoriert alles Längere stillschweigend. apr1 führt 1.000 Runden gesalzenes MD5 aus — deutlich schwächer als bcrypt, dafür von Apache und nginx nativ implementiert und damit die portierbare Wahl. SHA-1 ist ungesalzen; identische Passwörter ergeben identische Digests, und Rainbow Tables greifen. Behalten Sie es nur für Legacy-Systeme. crypt und plain stammen aus historischen und Test-Gründen und gehören nicht in die Produktion.
Die Präfixe $2a$ / $2b$ / $2y$
bcrypt-Hashes beginnen mal mit $2a$, mal mit $2b$, mal mit $2y$. Dahinter steckt derselbe Algorithmus, und die Hashes sind gleichwertig und austauschbar. Die Versionsbuchstaben sind Überbleibsel historischer Fehlerbehebungen — es ging darum, wie einzelne Bibliotheken mit High-Bit-Zeichen und Zeichenkettenlänge umgingen. Apaches htpasswd gibt $2y$ aus, und Caddy, Traefik und Docker Registry verifizieren es alle korrekt.
Wenn Sie den tieferen Vergleich von bcrypt mit modernen Alternativen möchten, behandelt der Leitfaden bcrypt vs. Argon2 vs. scrypt, wie sich diese Passwort-Hashing-Algorithmen in Kosten, Speicherhärte und Bedrohungsmodell unterscheiden.
Basic Auth auf Ihrem Server konfigurieren
Eine Anmeldedatei allein bewirkt nichts — Ihrem Server muss gesagt werden, dass er sie erfordern soll. Hier sind sechs Plattformen.
Apache (.htaccess)
Legen Sie dies in eine .htaccess-Datei in dem Verzeichnis ab, das Sie schützen möchten (oder in einen <Directory>-Block in Ihrem vhost):
AuthType Basic
AuthName "Restricted Area"
AuthUserFile /etc/apache2/.htpasswd
Require valid-user
AuthName ist die Realm-Zeichenkette, die der Browser anzeigt; AuthUserFile ist der absolute Pfad zu Ihrer Anmeldedatei; Require valid-user akzeptiert jeden darin aufgeführten Benutzer.
nginx (auth_basic)
nginx legt die Konfiguration in einen location- oder server-Block — es gibt kein .htaccess:
location /admin/ {
auth_basic "Restricted Area";
auth_basic_user_file /etc/nginx/.htpasswd;
}
Mit nginx -s reload neu laden. Verwenden Sie hier das apr1-Format. nginx delegiert die bcrypt-Verifizierung an das System-crypt(), was auf vielen Builds fehlschlägt (mehr dazu in der Fehlerbehebung), während apr1 auf jeder Plattform intern verifiziert wird.
Docker Registry & Kubernetes ingress-nginx
Das htpasswd-Backend einer privaten Docker Registry akzeptiert ausschließlich bcrypt. Erzeugen Sie den Eintrag, mounten Sie ihn und verweisen Sie die Registry darauf:
# Generate a bcrypt entry into a file
htpasswd -Bbn admin 's3cret' > auth/htpasswd
# Run the registry with that file
docker run -d -p 5000:5000 \
-v "$(pwd)/auth:/auth" \
-e REGISTRY_AUTH=htpasswd \
-e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
-e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
registry:2
Für Kubernetes ingress-nginx speichern Sie die Datei als Secret und referenzieren sie über Annotationen:
kubectl create secret generic basic-auth --from-file=auth=./auth/htpasswd
metadata:
annotations:
nginx.ingress.kubernetes.io/auth-type: basic
nginx.ingress.kubernetes.io/auth-secret: basic-auth
nginx.ingress.kubernetes.io/auth-realm: "Authentication Required"
Beachten Sie, dass der Secret-Schlüssel auth heißen muss — ingress-nginx sucht genau nach diesem Schlüssel.
Caddy & Traefik
Beide erwarten bcrypt-Hashes. Caddy verwendet die Direktive basic_auth (fügen Sie den bcrypt-Hash ein, nicht den Klartext):
example.com {
basic_auth /admin/* {
admin $2y$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy
}
}
Traefik verwendet eine basicauth-Middleware mit user:bcrypt-hash-Paaren (maskieren Sie jedes $ für Ihr Konfigurationsformat):
http:
middlewares:
admin-auth:
basicAuth:
users:
- "admin:$2y$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy"
Sobald ein Endpunkt geschützt ist, prüfen Sie auf der Kommandozeile, dass er funktioniert. Der cURL-Befehlsgenerator baut die -u user:pass-Anfrage für Sie zusammen, sodass Sie sowohl den 401 als auch den authentifizierten 200 bestätigen können.
Bewährte Sicherheitspraktiken
Basic Auth ist einfach, und die wenigen Wege, es falsch einzusetzen, lassen sich entsprechend gut benennen.
- Immer über HTTPS ausliefern. Die Anmeldedaten sind umkehrbares base64, sodass einfaches HTTP das Passwort auf der Leitung offenlegt. Terminieren Sie TLS vor jedem geschützten Endpunkt, ohne Ausnahme.
- Speichern Sie die Datei außerhalb des Web-Roots. Liegt
.htpasswdin einem ausgelieferten Verzeichnis, kann eine Fehlkonfiguration jemandem ermöglichen, sie herunterzuladen. Bewahren Sie sie irgendwo wie/etc/nginx/.htpasswdauf, setzen Siechmod 640und übertragen Sie das Eigentum an den Benutzer des Webservers (www-data,nginx), sodass der Server sie lesen kann und andere Konten nicht. - Verwenden Sie starke, eindeutige Passwörter. Jedes Konto sollte sein eigenes Passwort mit hoher Entropie aus dem Zufallspasswort-Generator erhalten, niemals wiederverwendet. Wenn Sie verstehen möchten, was „stark genug” in Bit bedeutet, schlüsselt der Erklärer zur Passwort-Entropie die Mathematik auf.
- Kennen Sie seine Grenzen. Basic Auth hat keinen Logout und keine Sitzung: Der Browser speichert die Anmeldedaten je Realm im Cache, bis Sie ihn schließen, und sie werden bei jeder Anfrage erneut gesendet. Eine umfassendere Checkliste zu Hashing, Headern und Validierung finden Sie in unseren bewährten Web-Sicherheitspraktiken.
Häufige Fehler beheben
nginx: crypt_r() failed (22: Invalid argument)
Das ist der mit Abstand häufigste Basic-Auth-Fehler bei nginx, und er bedeutet immer dasselbe: nginx wollte einen bcrypt-Hash ($2y$) gegen eine libc verifizieren, die das Blowfish-Schema nicht kennt — typischerweise Alpines musl oder eine ältere glibc. Erzeugen Sie den Eintrag als apr1 neu, das nginx auf jeder Plattform intern verifiziert:
printf "admin:$(openssl passwd -apr1 's3cret')\n" > /etc/nginx/.htpasswd
nginx -s reload
Auch der Wechsel zu einem Basis-Image, dessen libc bcrypt unterstützt, funktioniert, aber apr1 ist die einfachere, portierbare Lösung.
401 trotz korrektem Passwort
Wenn Sie sicher sind, dass das Passwort korrekt ist, aber dennoch einen 401 erhalten, arbeiten Sie diese Checkliste der Reihe nach ab:
- Dateipfad. Bestätigen Sie, dass
AuthUserFile/auth_basic_user_fileauf die tatsächliche Datei zeigt (absoluter Pfad, keine Tippfehler). - Berechtigungen. Der Webserver-Benutzer muss die Datei lesen können. Prüfen Sie mit
sudo -u www-data cat /etc/nginx/.htpasswd. - Zeilenenden / Kodierung. Eine unter Windows bearbeitete Datei kann
\r-Zeichen tragen, die den Hash beschädigen. Führen Siefile .htpasswdaus und wenden Sie bei Bedarfdos2unixdarauf an. - Veralteter Browser-Cache. Der Browser speichert Anmeldedaten je Realm im Cache. Testen Sie in einem privaten/Inkognito-Fenster, um ein gemerktes altes Passwort auszuschließen.
- Hash-Diskrepanz. Prüfen Sie, ob der gespeicherte Hash tatsächlich zum Passwort passt — fügen Sie beide in den Verifizierungsmodus des htpasswd-Generators ein, um es zu bestätigen, bevor Sie die Konfiguration verantwortlich machen.
Wann Sie Basic Auth NICHT verwenden sollten
Basic Auth ist das richtige Werkzeug für eine enge Reihe von Aufgaben: eine Staging-Site, einen internen Admin-Pfad, einen CI-Artefakt-Endpunkt, ein Metrik-Dashboard, eine private Registry. Es ist abhängigkeitsfrei und in zwei Minuten eingerichtet.
Es ist das falsche Werkzeug für eine Produkt-Anmeldung. Es gibt keinen Logout, kein Passwort-Zurücksetzen, kein Rate-Limiting, keine Kontosperrung und kein MFA. Anmeldedaten werden bei jeder Anfrage erneut gesendet und vom Browser bis zum Schließen im Cache gehalten. Sobald sich echte Benutzer anmelden sollen, greifen Sie zu Sitzungen, OAuth oder OIDC. Wer diese Grenze ehrlich zieht, behält Basic Auth genau dort, wo es passt.
FAQ
Was enthält eine einzelne Zeile in einer .htpasswd-Datei tatsächlich?
Ein durch Doppelpunkt getrenntes username:hash-Paar. Der Hash beginnt mit einem Algorithmus-Präfix ($2y$ für bcrypt, $apr1$ für Apache MD5, {SHA} für SHA-1), gefolgt von Salt und Digest. Das Klartext-Passwort erscheint nie in der Datei.
Was ist der Unterschied zwischen .htpasswd und .htaccess?
.htaccess ist Apaches Konfigurationsdatei je Verzeichnis — sie aktiviert Basic Auth und verweist auf den Anmeldedaten-Speicher. .htpasswd ist dieser Anmeldedaten-Speicher und enthält die username:hash-Zeilen. nginx verwendet das .htpasswd-Format, konfiguriert die Authentifizierung aber in seinen server-/location-Blöcken, nicht in .htaccess.
Wie füge ich einen Benutzer in einer .htpasswd-Datei hinzu, ändere oder entferne ihn?
Um einen Benutzer hinzuzufügen oder zu ändern, führen Sie htpasswd /path/.htpasswd username ohne -c aus — existiert der Benutzer, wird sein Hash aktualisiert. Um einen zu entfernen, führen Sie htpasswd -D /path/.htpasswd username aus. Verwenden Sie -c nur für den allerersten Benutzer, da es die gesamte Datei überschreibt.
Wie merkt sich der Browser Basic-Auth-Anmeldedaten, und wie melden sich Benutzer ab?
Der Browser speichert Anmeldedaten je Realm im Cache und sendet sie bei jeder passenden Anfrage automatisch erneut. Es gibt keinen standardisierten Logout: Die einzigen Wege, sie zu löschen, sind das Schließen des Browsers oder das Leeren seines Caches. Dieser fehlende Logout ist einer der Gründe, warum sich Basic Auth nicht für die Produkt-Authentifizierung eignet.
Kann ich dieselbe .htpasswd-Datei für Apache und nginx verwenden?
Ja, solange das Hash-Format auf beiden unterstützt wird. apr1 (Apache MD5) wird von Apache und nginx überall nativ verifiziert, daher ist es die sicherste gemeinsame Wahl. bcrypt funktioniert auf Apache, hängt auf nginx aber vom System-crypt() ab, das auf Alpine-/musl-Builds fehlschlägt.
Ist die HTTP-Basic-Authentifizierung 2026 noch relevant?
Ja. Als leichtgewichtige Schranke über HTTPS — interne Tools, Staging-Umgebungen, private Registries, Monitoring-Endpunkte — ist sie nach wie vor praktisch und abhängigkeitsfrei. Verwechseln Sie sie nur nicht mit der nutzerseitigen Produkt-Authentifizierung, die Sitzungen, Zurücksetzungen, Rate-Limiting und MFA benötigt, die Basic Auth nicht bieten kann.
Geprüft vom Go Tools-Team: Jeder Befehl, jeder Konfigurationsblock und jedes Hash-Format in dieser Anleitung wurde gegen die Referenzausgabe von Apache htpasswd (apache2-utils) und OpenSSL abgeglichen.