Skip to content

Nginx Authentication and Access Control

Using Basic HTTP Authentication scheme ​

Note that basic HTTP auth can be unsafe. Specially if not using HTTPS, since the password might be readable by someone sniffing your network.

To configure basic auth for a specific path (eg. /admin) in nginx, see the configuration below:

server {
  listen       443 ssl;
  #...
  location /admin {
      auth_basic           "Authorized Personnel Only";
      auth_basic_user_file /path/to/.htpasswd;
      #...
  }
}

/path/to/.htpasswd should point to a file generated using the htpasswd tool from Apache (in Debian, package apache2-utils).

sh
htpasswd -c /path/to/.htpasswd USERNAMEHERE

The tool will ask for a password and the file will be generated storing a hash of that password.

Reload nginx and you should be asked the user and password credentials when attempting to access the URL.

Restrict based on IP Address ​

If you always access your service from a fixed IP address (eg. from a local network) One interesting way to control access is filtering by IP address.

The below configuratin will grant access to the 192.168.178.1/24 network, excluding 192.168.178.2.

location /admin {
    #...
    deny  192.168.178.2;
    allow 192.168.178.1/24;
    allow 127.0.0.1;
    deny  all;
    #...
}

If your nginx installation has the ngx_http_geo_module module you may also respond differently to the requests based on the IP. Like for example offering a redirection.

geo $authorizedIP {
  default          0;
  192.168.178.2    0;
  192.168.178.1/24 1;
  127.0.0.1        1;
}

server {
  #...
  location /admin {
    if ($authorizedIP != 1) {
      rewrite ^ http://www.example.com/test;
    }
    #...
  }
}

Client Certificate ​

Another way to secure the access would be using a client certificate.

This will require that your server uses HTTPS (which you should already be using anyway if you want to be protected)

You can generate a client key and certificate as below (the sample uses 3650 days as expiration for the certificates, change that number to customize it to your situation).

sh
# Generate a CA certificate
openssl genrsa -out client-ca.key 4096
openssl req -x509 -new -nodes -key client-ca.key -sha256 -days 3650 -out client-ca.crt

# Create the Client key and sign it with the CA
openssl genrsa -out client.key 4096
openssl req -new -key client.key -out client.csr
openssl x509 -req -days 3650 -in client.csr -CA client-ca.crt -CAkey client-ca.key -set_serial 01 -out client.crt

# Generate PFX file to import in the client browser
openssl pkcs12 -export -out client.pfx -inkey client.key -in client.crt

The resulting client.pfx file can then be imported into the browser from where you wish to access (check your browser settings).

server {
  listen  443 ssl;
  #...
  ssl_client_certificate client-certs/client-ca.crt;
  ssl_verify_client on;
  #...
}

This will make it so ALL requests without a proper client certificate will receive a "400 Bad request - No required SSL certificate was sent" response.

But this will apply to every path on the server. If we want it to only apply to the specified path, we may set ssl_verify_client to optional and add a check in the path we want so we can either redirect the request to a different page (eg. using 301), or return with an 403 error.

server {
  listen  443 ssl;
  #...
  ssl_client_certificate client-certs/client-ca.crt;
  ssl_verify_client optional;
  #...
  
  location /admin {
    if ($ssl_client_verify != SUCCESS) {
      return 301 /;
    }
    #...
  }
}

Other security measures ​

Remove support for older SSL/TLS protocols ​

Protocols such as TLSv1 or TLSv1.1 are vulnerable to attacks.

To make sure you only support v1.2 and v1.3, you may use the ssl_protocols option as below:

server {
  listen  443 ssl;
  ssl_protocols TLSv1.2 TLSv1.3;
  #...
}

You can test if it works or not with curl.

sh
curl -I -v --tlsv1 --tls-max 1.0 https://myserver/
curl -I -v --tlsv1.1 --tls-max 1.1 https://myserver/

Personal page