Htpasswd Generator→Specialized Version
πŸ”’

Nginx Basic Auth Password Generator

Generate nginx basic auth credentials

Salted and iterated 1000 times. Portable across every platform Apache runs on and the default for `htpasswd -m`.

Hashing runs in this tab and nothing is uploaded β€” but generate credentials you intend to use with htpasswd on the server rather than in a browser.

nginx configuration
location /internal/ {
    auth_basic           "Restricted";
    auth_basic_user_file /etc/nginx/.htpasswd;
}

Reload with nginx -s reload after changing the file. Keep .htpasswd outside the document root so it cannot be requested over HTTP.

bcrypt is not offered here. It needs a native implementation that browsers do not provide. If your Apache supports it, htpasswd -B -c .htpasswd user is the stronger choice β€” APR1 is the portable fallback, not the best one.

nginx Reads htpasswd Files

nginx's auth_basic_user_file uses the same format Apache does β€” one user:hash line per entry. It supports APR1 ($apr1$) and {SHA} on every build; bcrypt support depends on how nginx was compiled, which is why APR1 remains the safe default here.

Configuration

``nginx server { location / { auth_basic "Restricted"; auth_basic_user_file /etc/nginx/.htpasswd;

proxy_pass http://app; }

# Leave health checks and ACME open, or you lock out your own monitoring location = /healthz { auth_basic off; proxy_pass http://app; } location /.well-known/ { auth_basic off; root /var/www; } } `

The two exceptions matter. A basic-auth gate over the whole server blocks Let's Encrypt renewals and every uptime probe, and you find out when the certificate expires.

File Placement

`bash sudo chown root:www-data /etc/nginx/.htpasswd sudo chmod 640 /etc/nginx/.htpasswd `

Never place it under a served root. If /var/www/html/.htpasswd exists, someone can download your hashes and attack them offline at their leisure.

Only Over TLS

Basic auth sends Authorization: Basic base64(user:pass) on every request. Base64 is encoding, not encryption β€” anyone on the network path reads the credentials directly. Over HTTPS it is acceptable for a staging gate or an internal tool; over HTTP it is equivalent to publishing the password.

What Basic Auth Cannot Do

MissingConsequence
LogoutThe browser caches credentials until it is closed
Lockout / rate limitingAdd limit_req yourself, or it is brute-forceable
MFANo second factor exists in the protocol
Per-user auditThe access log has the username and nothing else
It is a gate, not an authentication system. Use it to keep staging out of Google, not to protect user accounts.

Testing It Works

`bash # Should return 401 curl -I https://staging.example.com/

# Should return 200 curl -I -u admin:password https://staging.example.com/

# What the browser actually sends printf 'admin:password' | base64 # YWRtaW46cGFzc3dvcmQ= β†’ Authorization: Basic YWRtaW46cGFzc3dvcmQ= `

That last line is the whole security model: base64, no key, reversible by anyone who sees the header. Over TLS it is fine; over plain HTTP it is equivalent to publishing the password.

Keeping Machines Out but Letting the Right Ones In

A blanket auth gate breaks things you rely on. Exempt them explicitly:

PathWhy
/.well-known/acme-challenge/Let's Encrypt renewal fails otherwise, silently, until the certificate expires
/healthzLoad balancer and uptime probes
/api/webhooks/Third-party callbacks cannot authenticate

Blocking Crawlers Properly

Basic auth keeps a staging site out of search results, and it is worth pairing with the other two signals so that nothing leaks through a link:

` # robots.txt User-agent: * Disallow: / `

` X-Robots-Tag: noindex, nofollow `

Note that robots.txt alone does not prevent indexing β€” it prevents crawling, and a URL linked from elsewhere can still appear in results without a snippet. The noindex header is what actually removes it.

CI and Scripts

`bash # curl curl -u "$STAGING_USER:$STAGING_PASS" https://staging.example.com/

# Playwright await context.setHTTPCredentials({ username, password }); ``

Keep the credentials in secrets, never in the repository β€” a password committed to git stays in the history after you delete it.

Frequently Asked Questions

Does nginx support bcrypt in htpasswd files?

Only on builds compiled with the relevant crypt support, which many distribution packages lack. APR1 works on every nginx build, which is why it is the default here.

Where should the .htpasswd file live?

Outside any served root β€” /etc/nginx/.htpasswd is conventional. Owned by root, group-readable by the nginx user, mode 640.

Why does my Let’s Encrypt renewal fail after adding basic auth?

Because the ACME challenge under /.well-known/acme-challenge/ is behind the auth gate. Add a location block with auth_basic off for that path.

Related Tools

Explore other tools you might find useful:

More Htpasswd Generator tools

You might also need