Why generate a bcrypt hash online?
HTTP Basic authentication is still the fastest way to close off an admin area, a staging environment or an internal dashboard. It relies on a .htpasswd file where each line maps a username to a hashed password - never a plaintext one.
Since Apache 2.4, htpasswd -B produces bcrypt, and that is the format the official documentation recommends. The catch: that command assumes you installed apache2-utils on Debian or httpd-tools on RHEL. On a Windows machine, on shared hosting or from a web panel, it is often missing.
Three situations where this generator helps:
- Protect a staging environment → Close access to a test site before Google indexes it
- Add an account without SSH access → Build the line in your browser and paste it through your host's file manager
- Modernise an existing file → Gradually replace
$apr1$entries with$2y$ones
How to use the generator in 3 steps
Step 1: Enter the username and password
Type the account name, then its password. The field is masked by default; click the eye icon to re-read your input before submitting. The "Generate a password" button draws a random 16-character string if you do not have one yet.
Step 2: Set the cost factor
The slider starts at 10, the htpasswd -B value. Raise it to 12 for sensitive access. Every step doubles the computation time: at generation, and at every check the server performs.
Step 3: Copy the line
Two results are shown: the hash on its own, and the complete .htpasswd line. Copy the latter, paste it into your file, then reload your server configuration.
Anatomy of a bcrypt hash
A .htpasswd line splits into two fields separated by a colon:
admin:$2y$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy
The second field breaks down like this:
| Part | Example | Role |
|---|---|---|
| Algorithm identifier | 2y | Tells the server this is bcrypt |
| Cost factor | 10 | Exponent: the computation runs 2^10 = 1,024 rounds |
| Salt + digest | N9qo8uLOickgx2ZMRZoMye... | 53 characters: 22 for the 128-bit salt, 31 for the digest |
Unlike APR1-MD5, the salt does not sit in its own field: it is glued to the digest in the last block. It stays readable in plaintext, which is expected - its job is not to be secret, but to stop a precomputed table from recovering the password.
Understanding the cost factor
The cost is an exponent, not a multiplier. A cost of N runs 2^N key-derivation rounds:
| Cost | Rounds | Indicative time | Use |
|---|---|---|---|
| 8 | 256 | ~15 ms | Too weak today |
| 10 | 1,024 | ~60 ms | htpasswd -B default, fine |
| 12 | 4,096 | ~250 ms | Recommended for sensitive access |
| 14 | 16,384 | ~1 s | Noticeable latency on every login |
Two things to keep in mind. First, that time is paid on every check, so on every HTTP Basic request: a cost of 14 on a page whose browser replays authentication for each asset is felt immediately. Second, the right setting depends on your hardware: measure rather than copy a number, the usual target being 100 to 250 ms on the server that will run the check.
Protecting a directory with Apache
1. Create the file
Put your .htpasswd file outside the web root, so it is never served over HTTP:
/var/www/secrets/.htpasswd
2. Declare the protection
In the .htaccess of the directory to protect, or in the <Directory> block of your VirtualHost:
AuthType Basic
AuthName "Restricted area"
AuthUserFile /var/www/secrets/.htpasswd
Require valid-user
3. Reload the configuration
sudo apachectl configtest && sudo systemctl reload apache2
For nginx, the same pair of files is declared this way:
location /admin/ {
auth_basic "Restricted area";
auth_basic_user_file /var/www/secrets/.htpasswd;
}
nginx reads bcrypt from version 1.0.3 onwards on systems whose crypt_r() supports it, which covers every common Linux distribution.
bcrypt against the other .htpasswd formats
| Format | Prefix | Computation cost | Verdict |
|---|---|---|---|
| bcrypt | $2y$ | Adjustable, 2^cost rounds | Recommended for any new project |
| APR1-MD5 | $apr1$ | 1,000 MD5 iterations | Acceptable, maximum compatibility |
| SHA-1 | {SHA} | 1 iteration, no salt | Avoid: no salt, breakable by table |
| crypt() DES | none | 25 iterations, truncated to 8 characters | Obsolete, stop using it |
In short: bcrypt is the only .htpasswd format whose cost adjusts to the hardware of the day. The other three have a fixed cost, decided in the 1990s or 2000s, that GPU progress has made trivial. Keep APR1-MD5 only if your server cannot read $2y$.
Verifying the hash from the command line
This tool returns a standard bcrypt hash, verifiable with system utilities:
# Generate the equivalent with htpasswd (apache2-utils / httpd-tools package)
htpasswd -nbB admin myPassword
# Force a cost factor of 12
htpasswd -nbB -C 12 admin myPassword
The two strings will not be identical - the salt differs on every draw - but both validate the same password. To check that:
# Replay the verification using the salt of an existing hash
python3 -c "import bcrypt,sys; print(bcrypt.checkpw(b'myPassword', sys.argv[1].encode()))" '$2y$10$...'
FAQ - Frequently asked questions
Q: What is the $2y$ format?
A: It is the bcrypt marker inside a .htpasswd file. A full hash follows the pattern $2y$<cost>$<salt><digest>: an algorithm identifier, a two-digit cost factor, then 53 characters holding the 128-bit salt and the digest. That is what htpasswd -B writes.
Q: What is the difference between $2a$, $2b$ and $2y$?
A: None that matters, they are three markers for the same algorithm. $2y$ was introduced by PHP in 2011 to flag an implementation fixed for a non-ASCII character bug, a bug absent from the library used here. Apache and nginx accept all three.
Q: Which cost factor should I pick?
A: 10 by default, 12 for sensitive access. The right reflex is to measure on the server that will run the check and aim for 100 to 250 ms: slow enough to hamper a dictionary attack, fast enough to go unnoticed in daily use.
Q: Why can I not go past 15?
A: Since the cost is an exponent, 16 already demands several seconds of computation and would outlast the budget of an HTTP request. For a higher cost, generate the hash locally with htpasswd -B -C 18.
Q: Is bcrypt better than APR1-MD5?
A: Yes, clearly. APR1-MD5 chains 1,000 MD5 iterations, which specialised hardware computes by the billion every second. bcrypt demands memory and non-sequential access, which severely limits a GPU's parallelism. For a new .htpasswd file, bcrypt without hesitation.
Q: Can I use a password longer than 72 characters?
A: No, and that is not a limit of this tool: bcrypt simply ignores anything past 72 bytes. An 80-character password would therefore be equivalent to its first 72. Careful, an accented character counts as two bytes in UTF-8.
Q: Is the password stored anywhere?
A: No. It travels over HTTPS to the CaptainDNS API for the duration of the computation, then it is discarded. No database, no log holding the plaintext password.
Q: Where should the .htpasswd file live?
A: Outside the web root, for instance in /var/www/secrets/. If it sits in a directory served over HTTP, a visitor could download it and attack the hashes offline - which is precisely what the cost factor makes expensive, though not impossible.
Related tools
| Tool | Purpose |
|---|---|
| APR1-MD5 generator | Produce a .htpasswd line in the historical Apache format |
| Password generator | Draw a strong password before hashing it |
| Hash generator | Compute MD5, SHA-1, SHA-256 and SHA-512 of a text |
| Base64 encoder | Encode the Authorization header of a Basic request |
| HTTP headers viewer | Check the headers returned by a protected area |
Useful resources
- Apache documentation - htpasswd (command options, including -B and -C)
- Apache documentation - Authentication (setting up Basic authentication)
- A Future-Adaptable Password Scheme (the founding bcrypt paper, Provos and Mazieres, 1999)
- RFC 7617 - The Basic HTTP Authentication Scheme (specification of the Basic scheme)
Privacy commitment
Your password is sent to the CaptainDNS API solely to compute the hash, over an encrypted connection. It is never stored or logged. Only anonymous technical metrics are kept (processing time, response code).