How to Set Up Basic HTTP Authentication on NGINX

Posted on

How to Set Up Basic HTTP Authentication on NGINX

setup Basic HTTP Authentication on NGINX on ubuntu and centos

HTTP authentication offers a straightforward and efficient mechanism for safeguarding sensitive content from unauthorized access. This article provides a comprehensive guide on how to implement basic HTTP authentication on an NGINX server operating on both Ubuntu and CentOS distributions. This is a foundational skill for any web server administrator. Learning How to Set Up Basic HTTP Authentication on NGINX is an essential part of securing your web applications.

Prerequisites

Before diving into the setup process, ensure you have the following:

  • An NGINX web server installed and configured on either Ubuntu or CentOS.
  • Root or sudo privileges to modify NGINX configuration files and create the authentication file.
  • Basic familiarity with command-line operations.

Step 1: Create an Authentication File

The initial step involves creating an authentication file, which will store the username and password combinations used for authentication. This file acts as the source of truth for verifying user credentials.

Begin by creating the authentication file using the htpasswd utility. Replace username with the desired username and password with the corresponding password. The -c flag creates a new file. Subsequent users should be added without the -c flag.

$ sudo htpasswd -c /etc/nginx/.htpasswd username

Upon execution, you will be prompted to enter and verify the password for the specified username:

Password: password
Verifying - Password: password

Repeat this process for each username and password combination you wish to add to the authentication file. Remember to omit the -c flag when adding subsequent users:

$ sudo htpasswd /etc/nginx/.htpasswd anotheruser

This command will add ‘anotheruser’ to the /etc/nginx/.htpasswd file, prompting you for a password.

Step 2: Configure NGINX

With the authentication file in place, the next step is to configure NGINX to utilize it. This involves modifying the NGINX configuration file to enforce authentication for specific locations.

Open the NGINX configuration file using a text editor. The default location is often /etc/nginx/sites-available/default.

$ sudo nano /etc/nginx/sites-available/default

The default configuration file typically contains a server block resembling the following:

server {
    listen 80 default_server;
    listen [::]:80 default_server;

    root /var/www/html;

    index index.html index.htm index.nginx-debian.html;

    server_name _;

    location / {
        try_files $uri $uri/ =404;
    }
}

To enable authentication, add the auth_basic and auth_basic_user_file directives within the desired location block. The auth_basic directive sets the authentication realm (the message displayed in the login prompt), and the auth_basic_user_file directive specifies the path to the authentication file. The modified location block should look similar to this:

location / {
    try_files $uri $uri/ =404;
    auth_basic "Restricted Content";
    auth_basic_user_file /etc/nginx/.htpasswd;
}

In this example, any attempt to access the root directory (/) will now require authentication. Adjust the location block to match the specific directory or resources you want to protect. For example, to protect the /admin directory, you would modify the location block to location /admin/ { ... }.

Save the changes to the configuration file and close the editor.

Step 3: Test the Configuration

After configuring NGINX to use basic HTTP authentication, it’s crucial to test the configuration to ensure it’s working correctly.

First, verify the NGINX configuration file for any syntax errors using the nginx -t command:

$ sudo nginx -t

If the configuration file is valid, you should see a message indicating that the syntax is okay and the test was successful. If there are errors, carefully review the configuration file and correct them before proceeding.

Once the configuration is validated, restart the NGINX service to apply the changes:

$ sudo systemctl restart nginx

Now, attempt to access the protected content through a web browser. You should be prompted for a username and password. Enter the credentials you created in Step 1. If the authentication is successful, you will be granted access to the content.

Conclusion

This article demonstrated How to Set Up Basic HTTP Authentication on NGINX, providing a simple yet effective method for securing sensitive content on your web server. By following these steps, you can implement basic HTTP authentication on an NGINX server running on Ubuntu or CentOS, restricting access to authorized users only. However, it’s important to remember that basic HTTP authentication transmits credentials in base64 encoding, which is not inherently secure. For enhanced security, consider using HTTPS to encrypt the communication channel.

Alternative Solutions for Authentication

While the htpasswd method is straightforward, here are two alternative approaches to implementing authentication in NGINX:

1. Using NGINX’s ngx_http_auth_request_module for Delegated Authentication

This module allows NGINX to delegate the authentication decision to an external service. Instead of NGINX directly handling user credentials, it sends a subrequest to a designated authentication endpoint. This endpoint can then perform any authentication logic (e.g., querying a database, verifying JWT tokens, using OAuth).

Explanation: The auth_request directive instructs NGINX to make an internal subrequest to a specified URL. This URL should point to a service that handles authentication logic. The service should return a 2xx HTTP status code if the authentication is successful, or a 401 or 403 status code if it fails. Based on the response from the authentication service, NGINX either allows or denies access to the requested resource.

Code Example:

First, configure the authentication endpoint. This example assumes you have a simple Flask application running on http://auth-server:5000/verify that handles authentication.

# Flask application (auth_server.py)
from flask import Flask, request, Response

app = Flask(__name__)

@app.route('/verify')
def verify():
    # Replace with your actual authentication logic
    api_key = request.headers.get('X-API-Key')
    if api_key == 'secretkey':  # example validation
        return Response(status=200)
    else:
        return Response(status=401)

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

Then, configure NGINX:

server {
    listen 80;
    server_name example.com;

    location /protected {
        auth_request /auth;
        proxy_pass http://backend; # Your backend server
    }

    location = /auth {
        internal; # Only accessible internally by Nginx
        proxy_pass http://auth-server:5000/verify; #Authentication server
        proxy_pass_request_body off;
        proxy_set_header Content-Length "";
        proxy_set_header X-Original-URI $request_uri;  # Optional: Pass original URI
        proxy_set_header X-API-Key "secretkey"; # Send Api key to auth server.
        proxy_set_header Host $host;  # Important for some auth services
    }
}

In this configuration:

  • /protected is the location requiring authentication.
  • auth_request /auth; tells NGINX to use the /auth location for authentication.
  • location = /auth defines the authentication endpoint, which proxies the request to the Flask application running on http://auth-server:5000/verify.
  • The internal; directive ensures that the /auth location is only accessible internally by Nginx.

This approach offers flexibility and allows you to integrate with more complex authentication systems.

2. Using Lua with NGINX (OpenResty) for Custom Authentication

If you need even more fine-grained control over the authentication process, you can use Lua scripting with NGINX, typically through the OpenResty distribution. This allows you to implement custom authentication logic directly within your NGINX configuration.

Explanation: OpenResty embeds the Lua interpreter into NGINX, allowing you to use Lua scripts to handle requests. You can use Lua to access request headers, query databases, perform complex authentication checks, and set custom response headers.

Code Example:

First, install OpenResty. Then, configure NGINX with Lua:

http {
    lua_package_path '/usr/local/openresty/luajit/share/lua/5.1/?.lua;;';

    server {
        listen 80;
        server_name example.com;

        location /protected {
            access_by_lua_block {
                local redis = require "resty.redis"
                local red = redis:new()

                red:set_timeout(1000) -- 1 sec
                local ok, err = red:connect("127.0.0.1", 6379)
                if not ok then
                  ngx.log(ngx.ERR, "failed to connect to redis: ", err)
                  ngx.exit(500)
                end

                local auth_token = ngx.req.get_headers()["Authorization"]
                if not auth_token then
                  ngx.status = ngx.HTTP_UNAUTHORIZED
                  ngx.header["WWW-Authenticate"] = "Bearer realm="Restricted""
                  ngx.exit(ngx.HTTP_UNAUTHORIZED)
                end

                local res, err = red:get("user:" .. auth_token)
                if not res then
                   ngx.status = ngx.HTTP_UNAUTHORIZED
                   ngx.header["WWW-Authenticate"] = "Bearer realm="Restricted""
                   ngx.exit(ngx.HTTP_UNAUTHORIZED)
                end
                -- Free up connection
                local ok, err = red:close()
                if not ok then
                    ngx.log(ngx.ERR, "failed to close redis connection: ", err)
                end
            }
            proxy_pass http://backend; # Your backend server
        }
    }
}

In this example:

  • The access_by_lua_block directive executes the Lua code for each request to /protected.
  • The Lua code retrieves the Authorization header (assuming a Bearer token).
  • It connects to a Redis server to validate the token. (You’d need to have Redis installed and running).
  • If the token is invalid, it returns a 401 Unauthorized response with a WWW-Authenticate header.

This approach provides ultimate flexibility for implementing complex authentication schemes, but requires more in-depth knowledge of Lua and Nginx internals. It allows you to integrate with various databases and authentication protocols.

Both of these alternative solutions offer more advanced and flexible authentication methods compared to the basic htpasswd approach. Choose the method that best suits your specific requirements and technical expertise.