Protecting a staging site, internal dashboard, or administrative path with a quick credential challenge blocks casual browsing before requests ever reach the application. Basic authentication in Nginx is a practical way to put that gate in front of one location or an entire server block without changing the app itself.

The auth_basic directive tells Nginx to return an HTTP Basic challenge, and auth_basic_user_file points at the password file that holds allowed usernames and password hashes. Current Nginx documentation still uses the Apache htpasswd utility for that file, with apache2-utils on Debian and Ubuntu systems and httpd-tools on RHEL-family systems.

Basic authentication should only protect content served over HTTPS because the credentials are encoded, not encrypted, on their own. Keep the password file outside the public document root, restrict its permissions so Nginx can read it without exposing it to other local users, and use nginx -s reload instead of systemctl only when the service is not managed by systemd.

Steps to enable basic authentication in Nginx:

  1. Open the Nginx server block or included configuration file that serves the path to protect.
    $ sudoedit /etc/nginx/sites-available/example.com.conf

    Common edit locations include /etc/nginx/nginx.conf, /etc/nginx/conf.d/, and /etc/nginx/sites-available/ depending on distribution packaging.

  2. Install the password-file utility on Debian or Ubuntu.
    $ sudo apt update && sudo apt install --assume-yes apache2-utils
    Reading package lists... Done
    Building dependency tree... Done
    Reading state information... Done
    apache2-utils is already the newest version (2.4.58-1ubuntu8.11).
    0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

    Nginx documentation still lists apache2-utils for Debian and Ubuntu, and httpd-tools for RHEL, CentOS, and Oracle Linux.

  3. Create the password file and add the first allowed user.
    $ sudo htpasswd -c /etc/nginx/.htpasswd admin
    New password:
    Re-type new password:
    Adding password for user admin

    The -c flag creates or truncates the password file. Omit it when adding more users so existing entries are not overwritten.

    Add another user with sudo htpasswd /etc/nginx/.htpasswd alice.

  4. Check which user Nginx workers run as before setting password-file permissions.
    $ sudo grep -E '^user\s+' /etc/nginx/nginx.conf
    user www-data;

    Packaged defaults commonly use www-data or nginx as the worker account.

  5. Restrict the password file so root keeps ownership and the Nginx worker group can read it.
    $ sudo chown root:www-data /etc/nginx/.htpasswd
    $ sudo chmod 640 /etc/nginx/.htpasswd

    Replace www-data with the worker user or matching group shown in /etc/nginx/nginx.conf.

    World-readable permissions expose the password hashes to other local users on the host.

  6. Add the authentication directives to the location or server block that should require credentials.
    location /admin/ {
        auth_basic "Restricted area";
        auth_basic_user_file /etc/nginx/.htpasswd;
    }

    Place the directives at the server level to protect the whole virtual host. Use auth_basic off; inside a child location when one subpath must stay public.

    If access should depend on both client address and credentials, combine auth_basic with allow, deny, and satisfy. Related: How to restrict access by IP in Nginx

  7. Test the Nginx configuration before reloading it.
    $ sudo nginx -t
    nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
    nginx: configuration file /etc/nginx/nginx.conf test is successful

    A clean result confirms syntax and referenced-file access, including the password file path used by auth_basic_user_file.

  8. Reload Nginx so the protected location starts challenging requests.
    $ sudo systemctl reload nginx

    Use sudo nginx -s reload on hosts where systemd is not managing the service.

  9. Confirm the protected URL now returns an authentication challenge when no credentials are supplied.
    $ curl -I -sS http://127.0.0.1:8080/admin/
    HTTP/1.1 401 Unauthorized
    Server: nginx/1.24.0 (Ubuntu)
    Date: Thu, 09 Apr 2026 13:25:10 GMT
    Content-Type: text/html
    Content-Length: 188
    Connection: keep-alive
    WWW-Authenticate: Basic realm="Restricted area"

    Use the real hostname, port, and protected path for the site being changed. The decisive result is the 401 Unauthorized status plus the WWW-Authenticate header.

  10. Confirm the same URL returns the expected response when valid credentials are supplied.
    $ curl -I -sS -u admin:s3cretpass http://127.0.0.1:8080/admin/
    HTTP/1.1 200 OK
    Server: nginx/1.24.0 (Ubuntu)
    Date: Thu, 09 Apr 2026 13:25:10 GMT
    Content-Type: text/html
    Content-Length: 13
    Last-Modified: Thu, 09 Apr 2026 13:25:09 GMT
    Connection: keep-alive
    ETag: "69d7a8b5-d"
    Accept-Ranges: bytes

    Run the final check against HTTPS on any non-local host so the credentials are not exposed in transit.