htpasswd

Generate bcrypt or SHA-1 entries

Loading tool…

About htpasswd Entry Generator

htpasswd Entry Generator produces a single username and hash line for an Apache-style password file, using bcrypt at a cost factor you choose or the legacy SHA-1 format for servers that cannot do better. What it emits is a verifier, not a stored password.

HTTP Basic Authentication sends the username and password Base64-encoded on every request, and the server compares them against the hash in the password file. Base64 is an encoding, not encryption, so the credential is in the clear unless the connection is TLS. What the file protects rests on two things: HTTPS on the wire, and a hash slow enough that stealing the file does not hand over the passwords.

How to use this developer tool

  1. Enter the username. Colons and line breaks are rejected, because the colon separates the file's fields and a newline its records.
  2. Choose the algorithm: bcrypt for anything current, SHA-1 only when a server or appliance refuses bcrypt.
  3. For bcrypt, set the cost factor from 4 to 14. Each step doubles the work, and 10 to 12 is the normal range.
  4. Type the password, generate, and append the line to your password file, one entry per line.
  5. Confirm the file sits outside the document root and is readable only by the server user, then test over HTTPS.

Worked example: the same credential in both formats

One username and one password, generated twice. The two lines encode the same secret and have nothing in common, which is the entire point of salting.

Input
Username   deploy
Password   deploy-2026
Entries
bcrypt, cost 10
deploy:$2b$10$psTmXzHmSI/IhQ.trTEN0eoHZGy8M3nyJfsUcyu/Ny6pixaQ.kRdm

SHA-1
deploy:{SHA}U1MgtpXcK2GlT6IpcBGpgFSU2Ac=

Read the bcrypt field left to right: variant, cost, then 22 characters of encoded salt and 31 of hash, 60 in total. Generate again and the string differs completely because the salt is new, yet both verify. The SHA-1 line has no salt, so that password always yields that exact value.

Password file formats and their status

This tool writes the first and third rows. The others appear in files you inherit, and recognizing the prefix is the fastest way to judge what you are looking at.

FormatPrefixSaltStatus
bcrypt$2y$, $2a$ or $2b$128-bit, embeddedRecommended; tunable cost. Apache 2.4.4 and later, and nginx
Apache MD5$apr1$48-bitLegacy default. 1000 MD5 iterations, far too fast today
SHA-1{SHA}NoneSingle unsalted pass. Broken for storage; compatibility only
crypt (DES)13 characters, none12-bitObsolete. Truncates the password to 8 characters; Unix only
Plain textthe password itselfNoneSome non-Unix Apache builds only. Never acceptable

Troubleshooting

The server rejects every password even though the entry looks correct.

Why it happens The Apache build does not support bcrypt. Support arrived in 2.4.4, and some appliances and old distribution packages still ship without it, so a bcrypt line never matches.

Fix Check the version the server actually runs. If you cannot upgrade, fall back to SHA-1 and add an IP allowlist, because that format alone is not much protection.

This tool writes $2b$ but the server's own htpasswd -B writes $2y$.

Why it happens The prefix records which bcrypt variant produced the hash. The 2a, 2b, and 2y variants differ only in handling a historical 8-bit encoding bug, and Apache's crypt_blowfish verifies all three.

Fix Nothing is needed for Apache or nginx. If a stricter checker insists on $2y$, generate that entry with the server's own htpasswd -B rather than editing the prefix by hand.

The entry works in a shell but breaks inside a config file or a Compose variable.

Why it happens A bcrypt hash is full of dollar signs, which are variable references in shell, in Docker Compose interpolation, and in many templating systems, so the value silently becomes shorter.

Fix Single-quote it in shell, double each dollar sign in a Compose file, and prefer mounting the password file over passing a hash through an environment variable.

Authentication is slow, or the server stalls under load.

Why it happens bcrypt cost is exponential, so cost 14 is sixteen times the work of cost 10. Basic Authentication has no session, so the server re-verifies on every request.

Fix Keep the cost around 10 to 12 for a busy endpoint, and put a session or token layer in front if you need a higher factor.

When this tool is the right choice

  • Protecting a staging site, an internal dashboard, or a metrics endpoint with minimal configuration.
  • Producing an entry for nginx's auth_basic_user_file, which reads the same format.
  • Adding a user where you cannot run the htpasswd binary, such as a managed platform or an image build.
  • Seeing what changing the bcrypt cost does to the resulting line before committing to a value.

When to use something else

  • Real user accounts. There is no registration, reset, lockout, or way to revoke one credential without editing a file by hand. Use an identity provider.
  • Anything served over plain HTTP. The Authorization header is reversible Base64; TLS is the only thing keeping the password private in transit.
  • Generating a bcrypt hash for your application's user table. This emits an Apache-format pair — take only the hash, and confirm your framework's expected cost and variant.

Privacy and data handling

Hashing happens in this tab: bcrypt through a JavaScript implementation bundled with the page, SHA-1 through the browser's WebCrypto. Neither the username nor the password is transmitted, and the password field is marked so the browser will not offer to save it. The honest recommendation still holds for any secret typed into a web page: use a throwaway password here, and generate the production entry with the htpasswd binary on the server.

Related developer tools

Frequently asked questions

What cost factor should I choose?

The highest whose verification still takes a comfortable time on the machine that runs it, commonly 50 to 250 milliseconds, or cost 10 to 12 on typical hardware. Basic Authentication pays that cost on every request, not once per session.

Can the password be recovered from the entry?

No, bcrypt has no inverse. Someone holding the file can only guess: hash each candidate with the salt and cost recorded in the line, then compare. Cost, password length, and file permissions matter together.

Why does the bcrypt line change every time I generate it?

A fresh random salt is embedded in each hash, so the same password produces a different string every run and all of them verify. The SHA-1 format is weak precisely because it lacks this: identical passwords produce identical entries.

Is the SHA-1 format ever acceptable?

Only for interoperability with something that cannot do better, and only alongside another control such as an IP allowlist or a VPN. It is a single unsalted pass, which modern hardware brute-forces at enormous rates.

Does nginx accept this file?

Yes. auth_basic_user_file reads the same format and supports bcrypt, the SHA-1 form, Apache MD5, and crypt. What usually differs is the path and which user the workers run as, so check permissions first.

Where should the file live, and can it hold several users?

Outside the document root, owned by root, readable by the server user, mode 640 or stricter — a .htpasswd served as a static asset loses every credential at once. One file holds many users, one line each.