Introduction: In this tutorial, you will learn how to enhance the security of your website by configuring NGINX server blocks and location directives. You will discover how to block specific client IP addresses, restrict access based on geographical locations (geo-based restriction), and implement password-based authentication using HTTP Basic Authentication. These measures can provide additional protection for your web server while allowing you to control access to specific web pages.
Prerequisites:
- An Ubuntu server with sudo privileges
- NGINX installed on your server
- Basic understanding of NGINX and its configuration
Note: For password-based restriction, it's recommended to have HTTPS enabled for your server. You can follow this tutorial to set up HTTPS.
Formatting Conventions:
- In some configuration examples, ellipsis (...) may be used to indicate omitted parts.
- The term "server" refers to your Ubuntu server with NGINX installed, while "server block" refers to the NGINX configuration block that looks like this:
server {
...
}
Configuration Places: You should be aware of where NGINX stores its configuration files:
/etc/nginx
is the NGINX configuration directory where all configuration files are placed./etc/nginx/nginx.conf
is the main NGINX configuration file, where NGINX starts reading its configuration./etc/nginx/sites-enabled
is where you can place your HTTP(S) server configuration files. After NGINX is started or reloaded, all files from this directory are loaded by NGINX./etc/nginx/sites-available
is where you can place your HTTP(S) server configuration files, but they won't be loaded by NGINX unless you create a symbolic link in the/etc/nginx/sites-enabled
directory.
Log Files: NGINX generates two default log files:
/var/log/nginx/access.log
: Logs all requests./var/log/nginx/error.log
: Logs error conditions and status information.
Error on Reload: If you encounter an error when reloading your NGINX configuration with sudo systemctl reload nginx
, you can view the specific error by running sudo nginx -t
.
Step 1 - Locating the Server Block File
To configure restrictions, you need to find the server block file that corresponds to your domain. Use the following command to list server block files:
ls -al /etc/nginx/sites-available/
Assuming you want to add restrictions to a server block that responds to example.com
, locate the server block with the line server_name example.com;
. For example:
server {
...
server_name example.com;
...
}
Ensure that the listen
directive matches the port you intend to restrict (e.g., listen 80;
for HTTP).
Step 2 - Using IP Addresses to Allow or Deny Access
NGINX provides allow
and deny
directives to control access based on client IP addresses. You can block access to specific IP addresses, including your own for testing.
Step 2.1 - Finding Your Public IP Address To block your own IP address, you first need to determine your public IP address. Run the following command:
curl -4 https://2ip.io
You'll receive your public IP address as output (e.g., 15.1.1.1
). If the command fails, you can find your IP address through a Google search.
Step 2.2 - Blocking Access To block your IP address, add the following line to the appropriate location context in your server block, replacing 15.1.1.1
) with your public IP:
deny 15.1.1.1
);
Here's an example configuration snippet:
server {
listen 80;
server_name example.com;
location / {
deny 15.1.1.1
) } }
After making this change, reload NGINX to apply the configuration:
sudo systemctl reload nginx
Now, if you run the same command to access your website from your IP:
curl -4 --head http://example.com
You should receive an HTTP 403 Forbidden error, indicating that access has been denied.
Note: You can specify multiple allow
and deny
directives. The first directive that matches will be applied. For instance:
allow 15.1.1.1
; allow 15.1.1.2
; deny all;
In this example, access is allowed for 15.1.1.1
and 15.1.1.2
, while all other IP addresses are denied.
Step 3 - Using the Geo Module to Allow or Deny Access
NGINX's geo
module offers a flexible way to control access based on geographical locations using IP databases. To enable this feature:
- Install the
libnginx-mod-http-geoip2
package:
sudo apt update && sudo apt install libnginx-mod-http-geoip2
- Ensure that
/etc/nginx/nginx.conf
contains the following line:
include /etc/nginx/modules-enabled/*.conf;
- Download a GeoIP2-compatible IP database. You can use the provided command or create an account on the MaxMind website and download the GeoLite2 Country database:
cd /etc/nginx && sudo curl --fail -LO https://github.com/P3TERX/GeoLite.mmdb/releases/latest/download/GeoLite2-Country.mmdb
- Edit your NGINX configuration to include the GeoIP2 directives:
geoip2 /etc/nginx/GeoLite2-Country.mmdb {
$user_country country iso_code;
}
map $user_country $not_allowed {
CA 1; # Canada
US 1; # United States
default 0; # Allow all other countries
}
server {
listen 80;
server_name example.com;
location / {
if ($not_allowed) {
return 403 "You're not allowed to access.";
}
}
}
In this example, access is denied for users from Canada (CA) and the United States (US), while all other countries are allowed.
Reload NGINX to apply the changes:
sudo systemctl reload nginx
Step 4 - Password-Based Authentication (HTTP Basic Authentication)
To restrict access based on username and password, you can use HTTP Basic Authentication. Ensure you have HTTPS enabled for your server.
- Create a file to store usernames and hashed passwords:
sudo touch /etc/nginx/users
- Add users using the following command (replace
user
andpassword
with your desired username and password):
python3 -c 'from subprocess import *; import sys; print("Username: ", end="", file=sys.stderr); user = input();
passwd = run(["openssl", "passwd", "-6"], encoding="utf-8", stdout=PIPE).stdout.strip();
print("Username or password is empty. Try again!", file=sys.stderr) if user == "" or passwd == "" else print(user + ":" + passwd)' | sudo tee -a /etc/nginx/users
This command adds a user to the /etc/nginx/users
file and outputs the username and hashed password as user:password
pairs. The password is not stored in plain text on the server.
- Modify your server block configuration to include HTTP Basic Authentication:
server {
server_name example.com;
location / {
}
auth_basic "Protected area!";
auth_basic_user_file /etc/nginx/users;
listen 443 ssl; # Managed by Certbot
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # Managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # Managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # Managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # Managed by Certbot
}
Make sure to replace example.com
with your actual domain.
- Reload NGINX to apply the configuration:
sudo systemctl reload nginx
You can test the new configuration with curl
. Accessing the site without a username and password should result in an HTTP 401 Unauthorized error, while providing valid credentials should grant access.
Restricting Access to a Single URL
To restrict access to a specific URL, add the auth_basic
and auth_basic_user_file
directives directly to a location context within your server block. For example:
server {
server_name example.com;
location / {
}
location /admin {
auth_basic "Protected area!";
auth_basic_user_file /etc/nginx/users;
}
listen 443 ssl; # Managed by Certbot
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # Managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # Managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # Managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # Managed by Certbot
}
In this example, the /admin
URL is protected by HTTP Basic Authentication.
Logging Wrong Access Details
NGINX logs incorrect access attempts to the /var/log/nginx/error.log
file. This includes incorrect passwords and non-existent usernames, providing additional visibility into unauthorized access attempts.
Example Log Entries:
- Incorrect password:
2023/03/28 12:06:49 [error] 1865#1865: *14 user "root": password mismatch, client: 15.1.1.1
, server: example.com, request: "GET / HTTP/1.1", host: "example.com"
- Non-existent username:
2023/03/28/12:08:21 [error] 1865#1865: *16 user "root" was not found in "/etc/nginx/users", client: 15.1.1.1
, server: example.com, request: "GET / HTTP/1.1", host: "example.com"
Conclusion: This tutorial has equipped you with the knowledge to enhance the security of your website using NGINX. By configuring server blocks, controlling access based on IP addresses, implementing geographical restrictions, and setting up password-based authentication, you can better protect your web server and control access to specific resources. NGINX's flexibility and powerful features make it a valuable tool for securing your web applications. For further guidance, refer to the official NGINX documentation and mailing list archives.