Cryptography

nginx Basic Auth: How to Set Up .htpasswd Authentication

7 min read
By
nginx Basic Auth: How to Set Up .htpasswd Authentication

Photo by Tima Mironichenko from Pexels

nginx is not Apache. It does things differently. But when it comes to password protection, the two servers have more in common than you might think. Both use the same .htpasswd file format for storing credentials. The difference is in how you configure the server to enforce the protection.

Let's walk through setting up Basic Authentication on nginx.

The Key Difference: No .htaccess Files

The first thing to understand is that nginx does not support .htaccess files. This is a deliberate design decision. Apache reads .htaccess files on every request, which allows per-directory configuration overrides but adds overhead. nginx instead requires all configuration to be in the main config file. This is more efficient but means you need to edit the server config to protect a directory, rather than just dropping a file in a folder.

This is not a disadvantage. It is actually more secure, because there is no way for someone with write access to a directory to change the server configuration. And it is more performant, because nginx does not need to check for config files on every request.

The tradeoff is convenience. With Apache, you can protect a directory by creating a .htaccess file. With nginx, you need to edit the server config and reload nginx. If you do not have access to the server config (shared hosting), you may need to use a different approach or ask your hosting provider.

Step 1: Generate the .htpasswd File

This step is identical to Apache. You need a .htpasswd file with usernames and password hashes. You can generate it with the htpasswd command-line tool:

bash htpasswd -cB /etc/nginx/.htpasswd admin

The -B flag forces bcrypt, which is the recommended algorithm. Add more users without the -c flag:

bash htpasswd -B /etc/nginx/.htpasswd editor

Or generate entries in your browser with our htpasswd generator, which produces the same format.

Put the .htpasswd file somewhere nginx can read it but that is not served to the public. /etc/nginx/ is a common location. Make sure the file permissions allow the nginx worker process to read it:

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

## Step 2: Configure nginx

Open your nginx server block configuration. This is typically in /etc/nginx/sites-available/ or /etc/nginx/conf.d/, depending on your setup. Add the auth_basic and auth_basic_user_file directives to the location you want to protect:

nginx server { listen 80; server_name example.com;

location /private/ { auth_basic "Restricted Area"; auth_basic_user_file /etc/nginx/.htpasswd; } }

Let's break this down:

**auth_basic "Restricted Area"** — This enables Basic Authentication for the /private/ location. The string "Restricted Area" is the realm name, which appears in the browser's login dialog. Setting auth_basic to off disables authentication, which is useful for excluding specific sub-locations.

**auth_basic_user_file /etc/nginx/.htpasswd** — This points to the .htpasswd file. The path must be absolute. nginx reads this file on each request (or caches it, depending on the version), so changes to the file take effect immediately without needing to reload nginx.

Step 3: Protect the Entire Site

If you want to protect the entire site instead of just one location, put the directives in the server block instead of a location block:

nginx server { listen 80; server_name example.com;

auth_basic "Restricted Area"; auth_basic_user_file /etc/nginx/.htpasswd;

location / { # Serve content here } }

This applies authentication to every request. You can then selectively disable it for specific locations:

nginx location /public/ { auth_basic off; # This location is public }

This is useful when you want most of the site protected but need a few public endpoints (like a health check or a login page).

Step 4: Reload nginx

After making changes to the config, test the configuration for syntax errors:

bash sudo nginx -t

If the test passes, reload nginx:

bash sudo systemctl reload nginx

nginx reload is graceful: it does not drop existing connections. New connections will use the updated configuration immediately.

Step 5: Test the Setup

Visit the protected URL in your browser. You should see a login dialog. Enter the credentials from your .htpasswd file.

Test with curl as well:

bash curl -I https://example.com/private/

You should get a 401 Unauthorized response with a WWW-Authenticate header:

HTTP/1.1 401 Unauthorized Server: nginx WWW-Authenticate: Basic realm="Restricted Area"

Then authenticate:

bash curl -u admin:password https://example.com/private/

This should return the protected content with a 200 status.

Algorithm Compatibility

nginx supports the following hash formats in .htpasswd files:

- **Bcrypt ($2y$, $2a$, $2b$)** — Supported. This is the recommended algorithm. - **APR1 ($apr1$)** — Supported. The legacy default, still widely used. - **Crypt (no prefix)** — Supported but should not be used.

nginx does **not** support the {SHA} format that Apache supports with the htpasswd -s flag. If you are migrating from Apache and your .htpasswd file contains SHA entries, you need to regenerate those entries with bcrypt or APR1.

For new entries, always use bcrypt. It is the most secure option and is fully supported by nginx. See our htpasswd bcrypt vs APR1 comparison for details on why.

Common Issues

**401 even with correct credentials:** Check that the path in auth_basic_user_file is correct and that nginx can read the file. Check file permissions. Check that the hash format is supported by nginx (no {SHA} entries).

**No login prompt at all:** The auth_basic directive might not be in the right location block, or there might be a more specific location block that is matching the request without auth_basic. nginx uses the most specific location match, so make sure your protected location is the one being matched.

**Login works but returns 403:** Authentication succeeded but the file or directory does not exist or nginx does not have permission to serve it. This is a file permission issue, not an authentication issue.

Use HTTPS

Just like with Apache, Basic Authentication on nginx sends credentials as base64-encoded text. This is not encrypted. You must use HTTPS. If you are using Basic Auth over HTTP, your passwords are being transmitted in cleartext and can be intercepted by anyone on the network path.

Set up HTTPS with Let's Encrypt (free) before enabling Basic Auth. We cover the security implications in our HTTP Basic Auth security post.

The Bottom Line

Setting up Basic Authentication on nginx is straightforward once you know where the directives go. Generate a .htpasswd file with bcrypt hashes, add auth_basic and auth_basic_user_file to the right location block, reload nginx, and test. The .htpasswd file format is the same as Apache's, so you can use the same tools and generators.

Generate your .htpasswd entries with our htpasswd generator, and for the full Apache setup guide (if you are also running Apache), see our Apache .htaccess guide.

Frequently Asked Questions

Does nginx support .htaccess files?

No, nginx does not support .htaccess files. Unlike Apache, nginx does not read per-directory configuration files. All configuration goes in the nginx server or location blocks in the main config file. However, nginx does use the same .htpasswd file format for storing credentials. You generate the .htpasswd file the same way, but you configure the protection in nginx config, not in a .htaccess file.

What is the nginx equivalent of Apache Require valid-user?

The nginx equivalent is the auth_basic directive. Setting auth_basic to any string (like "Restricted Area") enables Basic Authentication for that location. Setting it to off disables it. The auth_basic_user_file directive points to the .htpasswd file, similar to Apache AuthUserFile.

Can I use the same .htpasswd file for both Apache and nginx?

Yes. The .htpasswd file format is the same for both servers. You can generate entries with the Apache htpasswd tool, with our online htpasswd generator, or with any tool that produces the standard format. Both servers support bcrypt and APR1 hashes. Note that nginx does not support the {SHA} format that Apache supports.

How do I password protect only a specific location in nginx?

Use a location block with auth_basic. For example, to protect /admin but leave the rest of the site public, add a location /admin/ block with auth_basic and auth_basic_user_file directives. Everything outside that block remains unprotected. You can also use auth_basic off inside a nested location to exclude a sub-path from authentication.

Try NovelCrypt Tools

Experience military-grade encryption for your sensitive data. Create self-destructing messages, encrypt files, or explore our experimental lab tools.

Explore NovelCrypt