Skip to content

htpasswd Generator — bcrypt, Apache MD5 (apr1) & Basic Auth

Generate htpasswd entries with bcrypt, Apache MD5 (apr1), SHA-1 & more. Get ready-to-paste Apache, nginx & Docker config. 100% in your browser — no upload.

No Tracking Runs in Browser Free
100% in your browser — passwords never leave your device.
Server
bcrypt cost: 12
htpasswd entry
Authorization header
 
Verify an existing hash
Reviewed for hash correctness and Basic Auth standards compliance — Go Tools Engineering Team · Jun 4, 2026

What Is an htpasswd File?

An .htpasswd file stores the credentials used by HTTP Basic Authentication. Each line is a single username:hash pair, where the hash is a one-way digest of the password — the plaintext is never stored. Web servers read this file to decide who may access a protected URL. On Apache, a .htaccess file (or a <Directory> block) references the .htpasswd file and prompts the browser for a username and password before serving the page.

The hash format depends on which algorithm produced it. Apache's htpasswd tool can emit several: bcrypt (lines starting with $2y$) is the strongest and is recommended for Apache, Docker Registry, and Caddy; apr1 (Apache MD5, starting with $apr1$) is the most portable and the safe default for nginx; SHA-1 (starting with {SHA}) is unsalted and considered insecure; crypt (traditional DES) is legacy and truncates at 8 characters; and plain stores the password in cleartext, which should never be used in production.

This generator runs entirely in your browser — no username, password, or hash is ever uploaded. If you need a strong password to go with your entry, use our Random Password Generator. To build the Authorization: Basic header by hand, the credential is just base64(user:password), which you can produce with our Base64 Encoder. And once your endpoint is protected, test it from the command line with our cURL Command Builder.

# Apache htpasswd CLI equivalents (apache2-utils / httpd-tools)

# bcrypt entry, printed to stdout (recommended; -B = bcrypt, -n = no file, -b = password on CLI)
htpasswd -Bbn admin 's3cret'
# → admin:$2y$10$N9qo8uLOickgx2ZMRZoMye...

# apr1 (Apache MD5) entry, portable for nginx — no apache2-utils needed
printf "admin:$(openssl passwd -apr1 's3cret')\n"
# → admin:$apr1$k3l4Hj9.$qN8...

# Append a user to an existing file from the shell
htpasswd -B /etc/apache2/.htpasswd alice

# Note: nginx delegates bcrypt to the system crypt(); on Alpine/musl or old
# glibc that fails — prefer apr1 for nginx to stay portable.

Key Features

Multiple Hash Algorithms

Generate bcrypt ($2y$), apr1 / Apache MD5 ($apr1$), and SHA-1 ({SHA}) entries — plus a plain (cleartext) option for testing. Each uses a fresh cryptographic salt where the format supports one.

Generate and Verify

Create new entries or verify existing ones. Paste a stored user:hash line and a candidate password to confirm instantly whether they match — useful for debugging a 401 in production.

Choose by Server

Pick Apache, nginx, Docker, or Caddy and the correct algorithm is selected automatically — bcrypt where it's supported, apr1 for nginx portability — so you avoid silent crypt() failures.

Ready-to-Paste Config Blocks

Get six copy-ready configuration snippets — Apache .htaccess, nginx auth_basic, Docker, Kubernetes ingress-nginx, Caddy, and Traefik — already wired to your generated .htpasswd entry.

100% Client-Side

All hashing happens locally in your browser via Web Crypto and a bundled bcrypt implementation. No username, password, or hash is ever sent to a server, so you can generate production credentials privately.

Examples

bcrypt entry (recommended)

admin:$2y$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy

A bcrypt entry with a $2y$ prefix and cost 10. This is the strongest, most portable format — use it for Apache, Docker Registry, Caddy, and Traefik.

apr1 entry (portable nginx)

admin:$apr1$kl3H9j2.$qN8vY7tLp2mZ0xW5cR4fK1

Apache MD5 (apr1) with an 8-character salt after the $apr1$ marker. The safe default for nginx, where bcrypt verification depends on an unreliable system crypt().

SHA-1 entry (legacy)

admin:{SHA}W6ph5Mm5Pz8GgiULbPgzG37mj9g=

A {SHA} entry is the base64 of an unsalted SHA-1 digest. Apache and nginx accept it, but it's unsalted and insecure — included only for legacy compatibility.

Authorization: Basic header

Authorization: Basic YWRtaW46czNjcmV0

The client-side credential for the same user: base64('admin:s3cret'). Send this header with curl -H or Postman to authenticate without writing a .htpasswd file.

Multi-user .htpasswd file

admin:$2y$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy
alice:$2y$10$3bQ8xY7tLp2mZ0xW5cR4fO9vK1jH6sD2nG8aQ5wE3rT7uI4oP1cm
bob:$apr1$mZ0xW5cR$4fK1jH6sD2nG8aQ5wE3rT2

One username:hash line per user. Algorithms can be mixed in the same file — here two bcrypt entries and one apr1 entry coexist for three users.

How to Use

  1. 1

    Configure Server & Algorithm

    Pick your target server (Apache, nginx, Docker, Caddy). The right algorithm is auto-selected — bcrypt for Apache/Docker/Caddy, apr1 for portable nginx — but you can override it and tune the bcrypt cost.

  2. 2

    Generate the Hash

    Enter a username and password (or click Random password), then click Generate. The hash is computed locally with a fresh random salt. Re-roll the salt anytime to mint a new entry.

  3. 3

    Copy the Entry

    Copy the user:hash line for your .htpasswd file, copy the echo >> append command for the shell, or copy the Authorization: Basic header for curl and Postman.

  4. 4

    Deploy the Config

    Paste the generated config block into your Apache .htaccess, nginx server block, Docker, Kubernetes ingress, Caddy, or Traefik configuration, point it at your .htpasswd file, and reload the server.

Common Use Cases

Apache Directory Protection
Lock down a folder with HTTP Basic Auth using a .htaccess file and an AuthUserFile directive. Drop in the bcrypt entry and the generated Apache config block to require a login on any path.
nginx auth_basic
Protect a location or server block with auth_basic and auth_basic_user_file. Use the apr1 format so verification works reliably across Alpine, Debian, and other base images.
Docker Registry
A private Docker Registry only accepts bcrypt htpasswd entries. Generate a $2y$ line with htpasswd -Bbn, mount it into the registry container, and authenticate your docker login.
Kubernetes ingress-nginx
Create a basic-auth Secret from your .htpasswd file and reference it with the nginx.ingress.kubernetes.io/auth-type and auth-secret annotations to gate an ingress route.
Caddy & Traefik
Caddy's basic_auth directive and Traefik's basicauth middleware both expect bcrypt hashes. Paste the generated entry directly into your Caddyfile or Traefik labels/dynamic config.
curl & Postman Authorization Header
Skip the file entirely for quick tests: copy the Authorization: Basic header to send credentials directly. Drop it into a curl -H flag or a Postman request to hit a protected endpoint.

Technical Details

bcrypt ($2y$)
An adaptive, salted hash based on the Blowfish cipher with a tunable cost factor. Each entry embeds a random 16-byte salt and the cost, so identical passwords produce different hashes. Note: bcrypt truncates the password at 72 bytes — characters beyond that are ignored.
apr1 (Apache MD5)
Apache's iterated, salted MD5 variant ($apr1$ + 8-char salt). It runs 1,000 MD5 rounds, which is far weaker than bcrypt's adaptive cost, but it is implemented natively by Apache and nginx, making it the most portable format across platforms and base images.
SHA-1 and crypt
SHA-1 entries ({SHA} + base64 digest) are unsalted, so identical passwords yield identical hashes and are vulnerable to rainbow tables — included only for legacy compatibility. Traditional crypt (DES) is even weaker and silently truncates passwords at 8 characters.
Salt & Iterations
Salting prevents precomputed (rainbow-table) attacks by making every hash unique. bcrypt uses a 128-bit random salt with a configurable cost; apr1 uses an 8-character salt with 1,000 fixed iterations. Use Re-roll salt to regenerate a different valid hash for the same password.
Base64 & UTF-8 Handling
Passwords are encoded as UTF-8 bytes before hashing, so non-ASCII characters are handled consistently. The Authorization: Basic header is the base64 of the raw UTF-8 username:password bytes, matching what servers decode on the receiving end.
Honesty Notes & Caveats
Generated hashes are computed locally and never verified against a live server. Copied entries and downloaded .htpasswd files land on your clipboard and disk in plaintext-hash form — handle them like secrets, restrict file permissions, and clear your clipboard after pasting into production config.

Best Practices

Prefer bcrypt Wherever Supported
Use bcrypt ($2y$) for Apache, Docker, Caddy, and Traefik — it's salted, adaptive, and far stronger than apr1 or SHA-1. Reserve apr1 for nginx only when bcrypt's reliance on the system crypt() makes it unreliable.
Store the File Outside the Web Root
Keep .htpasswd out of any served directory so it can never be downloaded over HTTP. Set chmod 640 and own it by the web-server user so the server can read it while other accounts cannot.
Always Serve Over HTTPS
Basic Auth transmits credentials as reversible base64 on every request. Without TLS, anyone on the network path can read the password. Never enable Basic Auth on plain HTTP — terminate TLS in front of the protected endpoint.
Use Unique, Strong Passwords
Each account should have its own high-entropy password, never reused across services. Generate one with our Random Password Generator and store it in a password manager rather than inventing it by hand.

Frequently Asked Questions

bcrypt vs apr1 — which should I choose?
Use bcrypt for Apache, Docker Registry, Caddy, and Traefik — it's a strong, salted, adaptive hash and is the modern standard. Use apr1 (Apache MD5) for nginx, because nginx hands bcrypt off to the system crypt() and that fails on many builds, while apr1 is implemented internally and works everywhere. If you control the runtime and know bcrypt is supported, bcrypt is always the stronger choice; apr1 is about portability, not security.
Does nginx support bcrypt?
Only indirectly, and not reliably. nginx doesn't hash passwords itself — for $2y$ entries it delegates verification to the C library's crypt() function, so support depends entirely on your libc. Alpine's musl and older glibc builds don't include the blowfish (bcrypt) scheme, so authentication silently fails. For portable nginx setups, use the apr1 format instead, which nginx verifies internally on every platform.
How do I fix the nginx error `crypt_r() failed (22: Invalid argument)`?
That error means nginx tried to verify a bcrypt ($2y$) hash on a libc that doesn't support the blowfish scheme — typically Alpine/musl or an older glibc. The fix is to regenerate the entry as apr1 (Apache MD5) instead of bcrypt, which nginx verifies internally on any platform. Alternatively, switch to a base image whose libc includes bcrypt support, but apr1 is the simpler, portable solution.
Where should I put the .htpasswd file and what permissions?
Store the .htpasswd file outside the web document root so it can never be served as a static file and exposed. A common location is /etc/apache2/.htpasswd or /etc/nginx/.htpasswd. Set permissions to 640 (chmod 640) and make it owned by the user the web server runs as (for example www-data or nginx), so the server can read it but other accounts cannot.
How do I configure Basic Auth in .htaccess / nginx?
For Apache, this tool generates a .htaccess block with AuthType Basic, AuthName, AuthUserFile pointing at your .htpasswd path, and Require valid-user. For nginx, it generates a location block with auth_basic "Restricted"; and auth_basic_user_file /path/.htpasswd;. Copy the config block that matches your server, adjust the file path, and reload — the snippets are ready to paste.
Are my passwords uploaded anywhere?
No. Every hash is computed entirely in your browser using JavaScript — no username, password, or generated hash is ever sent over the network. You can confirm this by opening your browser's Developer Tools (F12 → Network tab) while generating: there are zero outgoing requests. Nothing is stored or logged on any server, so it's safe to generate real production credentials here.
What's the difference between $2a$, $2b$, and $2y$ in bcrypt?
They are version prefixes for the same bcrypt algorithm and produce equivalent hashes; the differences trace back to historical bug fixes in how certain implementations handled high-bit characters and string length. Apache's htpasswd emits $2y$. Modern bcrypt libraries treat $2a$, $2b$, and $2y$ as interchangeable for verification, so a $2y$ entry generated here will validate correctly in Apache, Caddy, Traefik, and Docker Registry.
What bcrypt cost should I use?
Cost 12 is the modern default and a good balance of security and speed. The cost is a work factor: each increment doubles the time to compute and verify the hash, which slows down brute-force attacks but also adds latency to every login. Cost 10 is acceptable for low-traffic or low-risk endpoints; 12–14 is recommended for anything sensitive. Avoid going so high that legitimate authentication becomes noticeably slow.
htpasswd vs the Authorization: Basic header — what's the difference?
They sit on opposite ends of the same exchange. The .htpasswd file holds the server-side stored hash — a one-way digest the server uses to verify credentials. The Authorization: Basic header is the client-side request credential: the literal base64 of username:password the browser or curl sends on each request. The server base64-decodes the header, then checks the password against the stored hash. One is storage, the other is transport.
I don't have apache2-utils installed — how do I generate an htpasswd entry?
You don't need it — this tool generates valid bcrypt, apr1, and SHA-1 entries entirely in your browser. If you prefer the command line, OpenSSL ships on almost every system: run openssl passwd -apr1 to produce an apr1 hash, then prefix it with username: to form the line. On Debian/Ubuntu you can also install the htpasswd binary via apt install apache2-utils, or httpd-tools on RHEL/CentOS.
What do the htpasswd flags -B, -Bbn, -bnB mean?
Each letter is an independent flag: -B selects bcrypt, -n prints the result to stdout instead of writing a file, and -b takes the password as a command-line argument (rather than prompting). The order doesn't matter, so -Bbn and -bnB are identical. -Bbn is the common combination for piping a bcrypt entry into a Docker Registry htpasswd file.
Why does Docker Registry require bcrypt?
The Docker Registry's htpasswd authentication backend only accepts bcrypt-formatted entries; apr1, SHA-1, and crypt hashes are rejected and login will fail. Generate the entry with htpasswd -Bbn user password (or use the bcrypt option here), mount the file into the registry container, and point REGISTRY_AUTH_HTPASSWD_PATH at it. Always pair this with TLS, since Basic Auth credentials are otherwise readable in transit.
Is Basic Auth secure?
Only over HTTPS. HTTP Basic Auth sends credentials as base64(username:password) on every request, and base64 is reversible encoding — not encryption — so anyone who can read the traffic can recover the password instantly. Over TLS the header is encrypted in transit and Basic Auth is acceptable for simple gating. Never use it on plain HTTP, and prefer stronger schemes for high-value applications.

Related Tools

View all tools →