htpasswd Generator
Build Apache basic-auth lines with bcrypt, $apr1$, {SHA} or plain text, verify an existing hash, and collect several users into one file.
Nothing here leaves the browser
Cost 10 runs 2^10 key-setup rounds — the usual default. Raise it until a login takes about 250 ms on the hardware that will serve it.
Verify an existing line
Settings
Deliberately slow and salted, with a cost you raise as hardware gets faster. The only option here that is meant for a password.
How htpasswd Generator works
An .htpasswd file is about as simple as an authentication store gets: one line per user, a name, a colon, and a hash of that user’s password. Apache reads it top to bottom and stops at the first line whose name matches, which means a duplicated user is not an error — the second entry is simply unreachable. Nginx reads the same format for its basic-auth module, as do Traefik, HAProxy and most ingress controllers, so the file outlives the server that invented it.
Four hash formats appear in real files and only one of them should be written today. bcrypt, marked by a $2y$ prefix, is a deliberately slow function built on the Blowfish key schedule, with a cost factor stored inside the hash itself. Each increment of that cost doubles the work, so the same file keeps working as hardware improves and the cost is raised for new entries. The $apr1$ format is salted MD5 run a thousand times; it was Apache’s default for two decades and is what most existing files contain, but a thousand MD5 rounds is a trivial amount of work for a modern GPU. {SHA} is a single unsalted SHA-1 pass, which means identical passwords produce identical hashes and one rainbow table reverses the entire file. Plain text is exactly what it sounds like.
Salting is what separates the first two from the rest. A salt is a short random value stored alongside the hash, mixed in before hashing, and its purpose is not secrecy — it is written in the file for anyone to read. Its purpose is to make every stored hash unique even when two users choose the same password, which destroys any precomputed table and forces an attacker to attack each line separately. This is also why hashing the same password twice here produces two different lines, and why both of them verify.
Cost is the parameter worth thinking about. The bcrypt work factor is an exponent: cost 10 performs 2¹⁰ key-setup rounds, cost 12 performs four times as many. The usual guidance is to raise it until a single verification takes somewhere around a quarter of a second on the hardware that will serve the requests, which balances the cost of an offline guessing attack against the cost of a legitimate login — remembering that basic auth sends credentials on every request, so the server pays that cost far more often than a session-based login would.
Reference
- Line format: username:hash — the first colon separates them
- bcrypt: $2y$<cost>$<22-char salt><31-char digest>, cost 4–15
- Apache MD5: $apr1$<salt up to 8>$<22-char digest>, 1000 rounds
- SHA-1: {SHA}<Base64 of the 20-byte digest>, unsalted
- Work at cost c is 2^c key-setup rounds; c+1 is twice c
How to use this generator
Enter the username
Anything without a colon, since the first colon on the line is what separates the two fields and Apache provides no way to escape one.
Type the password and pick a format
bcrypt is the default and the only recommendation. The others are offered for reading and reproducing files that already exist.
Set the cost, then generate
Hashing happens on a button press rather than as you type, because every salted format would otherwise reroll its salt on each keystroke.
Collect the users you need and download the file
Repeating a username replaces its line rather than appending a second one, matching the first-match-wins rule Apache applies when reading.
Worked examples
The same password, hashed twice
- Given
- hunter2 at cost 10, generated twice
- Result
- Two entirely different $2y$10$ lines
Both verify correctly. The difference is the random salt, and it is what stops one cracked hash from revealing every reuse of that password in the file.
Reading the cost out of a hash
- Given
- $2y$12$…
- Result
- Cost 12 — four times the work of cost 10
The cost travels inside the hash, so old and new entries with different costs coexist in one file and each verifies at its own.
An unsalted format
- Given
- Two users who both chose hunter2, hashed with {SHA}
- Result
- Identical hash on both lines
Visible password reuse, straight from the file, before any cracking is attempted. This is what a salt prevents.
Verifying a line you did not write
- Given
- A pasted $apr1$ line and a candidate password
- Result
- Match or no match, with the format named
The salt is read back out of the hash and reused, which is the only way an already-salted hash can be checked.
When to use it
- Putting basic auth in front of a staging environment or an internal dashboard that has no login of its own.
- Creating the secret an ingress controller expects for its basic-auth annotation.
- Confirming that a password in a password manager still matches the line in a file nobody has touched for two years.
- Rehashing an old file’s $apr1$ entries at a bcrypt cost the current hardware can afford.
- Checking which format a line is in before deciding whether the account needs rotating.
Things to watch out for
- Basic auth sends the username and password on every single request, encoded but not encrypted. Without TLS it is equivalent to sending them in the clear, and the strength of the hash on the server is irrelevant to that.
- bcrypt only considers the first 72 bytes of a password. Longer inputs are truncated, which matters if a passphrase or a pre-hashed value is being used.
- A duplicated username is unreachable rather than invalid, because the file is read top to bottom and the first match wins.
- The 13-character hashes in very old files are crypt(3), the original Unix DES scheme, which only ever considered the first eight characters of a password. Anything still using it should be rehashed rather than verified.
- Everything on this page runs locally: the password is hashed by WebAssembly in the browser, is never transmitted, and is not stored anywhere once the tab closes.
Frequently asked questions
Which htpasswd format should I use?
bcrypt, written with the $2y$ prefix. It is the only option in the format family that was designed to resist offline guessing, and it carries an adjustable cost so the same file can be strengthened over time.
What bcrypt cost should I choose?
High enough that one verification takes roughly a quarter of a second on the server that will run it — commonly 10 to 12. Basic auth verifies on every request, so an unnecessarily high cost is paid constantly rather than once per session.
Why does the same password give a different hash each time?
Because a fresh random salt is generated for every hash and stored inside the result. Verification reads that salt back out and reuses it, so all of the different-looking hashes accept the same password.
Is $apr1$ still safe to use?
Not for anything new. It is salted, which is better than nothing, but a thousand rounds of MD5 is a negligible amount of work for hardware built to guess passwords. It exists here so existing files can be read and replaced.
Can nginx use an Apache htpasswd file?
Yes — the ngx_http_auth_basic_module reads the same format, and supports bcrypt as well as the older schemes. The same file also works with Traefik, HAProxy and most Kubernetes ingress controllers.
Does basic auth need HTTPS?
Yes. The credentials are base64-encoded, not encrypted, and are attached to every request. Over plain HTTP anyone on the path can read them, and no choice of hash on the server side changes that.
Related DevOps tools
All devops tools- Cron Expression Parser Read a cron line in plain English, expand every field, and see the next ten firings in local time and UTC.
- CIDR / Subnet Calculator Turn an IPv4 or IPv6 prefix into netmask, broadcast, usable range and host count — then split it, compare it, or aggregate a range.
- chmod / Unix Permissions Calculator Bind permission checkboxes, octal and symbolic modes together — including setuid, setgid, sticky and what a umask leaves behind.
- Uptime & SLA Calculator Convert an availability target into allowed downtime per day, month and year, track the error budget, and chain several services together.
- Kubernetes Resource Converter Convert CPU and memory quantities between every suffix Kubernetes accepts, and catch the ones that mean a billion times what you meant.
- YAML ↔ JSON Converter Convert either way with key order and comments-free fidelity, then see every scalar whose written form and parsed value disagree.