Setting Up Basic HTTP Authentication with NGINX for Secure Access Control

HTTP Basic Authentication is a simple method to restrict access to web resources by requiring a username and password. The client sends encoded credentials with each request, which NGINX verifies against a password file to allow or deny access.

A common use case is protecting a staging environment (e.g., staging.example.com) to prevent public access while allowing easy authentication.

How It Works #

  1. Client sends a Authorization: Basic <base64(username:password)> header with each request.
  2. NGINX verifies the credentials against a password file.
  3. Access is granted or denied based on the result.

Security Considerations #

HTTP Basic Authentication is only suitable for simple, low-risk scenarios and must always run over HTTPS. For stronger security or complex access control, use more advanced methods.

1. Lack of Encryption

Base64 encoding is not encryption and can be easily decoded. When sent over HTTP, credentials are exposed to anyone monitoring the network, such as on public Wi-Fi or unsecured internal networks.

Mitigation: Always use HTTPS (TLS) to encrypt the entire request, including the Authorization header.

2. No Session Management

  • Credentials are sent with every request, increasing risk if intercepted.
  • Browsers may cache credentials without a logout option, so access persists until the browser is closed.

3. Static Credential Storage

  • Passwords are stored in an .htpasswd file, usually hashed with bcrypt or SHA-based algorithms.
  • Managing this file requires manual updates or automation.

Use strong, unique passwords hashed with bcrypt (e.g., via htpasswd -B).

4. No Built-in Protection Against Brute Force

Basic Auth does not prevent repeated login attempts or brute force attacks.

Mitigation:

  • Use NGINX features like limit_req or tools like fail2ban to limit repeated attempts.
  • Apply firewall rules (e.g., iptables, ufw) to restrict access to sensitive endpoints.

5. Audit and Logging

  • NGINX logs record accessed URLs but not credentials.
  • Avoid logging full headers or request bodies to prevent accidental exposure of sensitive data.

Workflow #

Step 1: Install Required Packages #

Install apache2-utils, which includes the htpasswd utility:

bash
sudo apt install apache2-utils -y

Step 2: Create Credentials File #

Generate the .htpasswd file with a strong password, storing it outside the web root:

bash
sudo htpasswd -c -B /etc/nginx/.htpasswd <user>

Explanation:

  • -c: Create a new password file (overwriting if it exists)
  • -B: Use bcrypt hashing for stronger security
  • /etc/nginx/.htpasswd: Path to the password file
  • <user>: Username to add or update

You will be prompted to enter and confirm the password.

Managing Users

Add another user:

bash
sudo htpasswd -B /etc/nginx/.htpasswd <another_user>

View credentials file:

bash
sudo cat /etc/nginx/.htpasswd
  • Each line contains a username and hashed password
  • Do not store this file in your web root

Change an existing user’s password:

bash
sudo htpasswd -B /etc/nginx/.htpasswd <user>
  • You will be prompted to enter and confirm the new password
  • Updates the password without affecting other users

Delete a user:

bash
sudo vim /etc/nginx/.htpasswd
  • Delete the line starting with the username
  • Save and exit

Step 3: Configure NGINX #

Edit site configuration:

bash
sudo vim /etc/nginx/sites-available/<site>

Add the following inside the relevant location block to enable Basic Auth:

/etc/nginx/sites-available/<site>
location / {
  auth_basic "Restricted Access";
  auth_basic_user_file /etc/nginx/.htpasswd;
  ...
}

Optional: Restrict Access by IP

Add IP restrictions for an extra security layer:

/etc/nginx/sites-available/<site>
location / {
  allow 123.4.567.8;  # Replace with your static IP
  deny all;

  auth_basic "Restricted Access";
  auth_basic_user_file /etc/nginx/.htpasswd;
}

Optional: Add rate limiting to reduce brute-force attacks

Limit requests per IP to reduce brute-force risks:

/etc/nginx/sites-available/<site>
http {
  limit_req_zone $binary_remote_addr zone=authlimit:10m rate=5r/m;

  server {
    location / {
      limit_req zone=authlimit;
      auth_basic "Restricted Access";
      auth_basic_user_file /etc/nginx/.htpasswd;
    }
  }
}

Explanation:

  • limit_req_zone creates a 10-minute zone tracking IPs, allowing 5 requests per minute.
  • limit_req enforces this limit in the location.
  • This slows repeated requests, adding security alongside Basic Auth with minimal setup.

Step 4: Secure the Credentials File #

Set ownership and permissions to restrict access:

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

Verify:

bash
ll /etc/nginx/.htpasswd

Step 5: Validate and Reload Nginx #

Run:

bash
sudo nginx -t && sudo systemctl reload nginx

Step 6: Test Access #

Open your site in a browser:

bash
https://example.com/
  • You should see a Basic Auth login prompt
  • Enter your credentials to access the site

Notes

  • No session or timeout: Basic Auth credentials are cached by the browser
  • To "log out", close the browser or clear its authentication cache
  • Use a private/incognito window to verify the login prompt is working
  • On failed login, NGINX returns: 401 Authorization Required