Nginx is an open source, lightweight, high-performance the fastest growing web server around the world. Nginx runs on Linux, Windows, Mac OS, and Solaris operating system. NGINX continues to rise in popularity, so means more and more NGINX deployments need to be secured.
In this tutorial, we will explain some popular Nginx server security tips and tricks.
Requirements
- A server running Ubuntu 18.04 or Debian 9.
- A root password is set up on your server.
Install Nginx
First, you will need to install Nginx to your system. You can install it by running the following command:
apt-get install nginx -y
Once the Nginx has been installed, you can check the status of Nginx with the following command:
systemctl status nginx
You should see the following output:
? nginx.service - A high performance web server and a reverse proxy server Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled) Active: active (running) since Sun 2019-03-10 02:43:14 UTC; 4min 40s ago Docs: man:nginx(8) Process: 2271 ExecStop=/sbin/start-stop-daemon --quiet --stop --retry QUIT/5 --pidfile /run/nginx.pid (code=exited, status=0/SUCCESS) Process: 2281 ExecStart=/usr/sbin/nginx -g daemon on; master_process on; (code=exited, status=0/SUCCESS) Process: 2274 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exited, status=0/SUCCESS) Main PID: 2285 (nginx) Tasks: 2 (limit: 1111) CGroup: /system.slice/nginx.service ??2285 nginx: master process /usr/sbin/nginx -g daemon on; master_process on; ??2290 nginx: worker process Mar 10 02:43:14 ubuntu1804 systemd[1]: Starting A high performance web server and a reverse proxy server... Mar 10 02:43:14 ubuntu1804 systemd[1]: nginx.service: Failed to parse PID from file /run/nginx.pid: Invalid argument Mar 10 02:43:14 ubuntu1804 systemd[1]: Started A high performance web server and a reverse proxy server.
Update Nginx
You will need to update your Nginx web server as there are many performance enhancement, new features and security fixes are being added. Most modern Linux distributions will not come with the latest version of nginx into their default package lists. So you will need to upgrade the latest version of nginx via a package manager. You can update your Nginx web server with the following command:
apt-get update -y
apt-get install nginx --reinstall -y
Prevent Information Disclosure
First, you will need to prevent the Nginx to disclose their version information.
By default, Nginx shows its name and version in the HTTP headers.
You can check it with the following command:
curl -I http://localhost
You should see the following output:
HTTP/1.1 200 OK Server: nginx/1.14.0 (Ubuntu) Date: Sat, 09 Mar 2019 15:28:01 GMT Content-Type: text/html Content-Length: 10918 Last-Modified: Fri, 01 Feb 2019 16:05:17 GMT Connection: keep-alive ETag: "5c546e3d-2aa6" Accept-Ranges: bytes
In the above output, you should see the Nginx and operating system version.
You can hide this information by editing /etc/nginx/nginx.conf file:
nano /etc/nginx/nginx.conf
Add the server_tokens off line inside http configuration part:
http { ## # Basic Settings ## server_tokens off;
Save and close the file, when you are finished. Then, restart Nginx web server to apply the changes:
systemctl restart nginx
Now, run the curl command again:
curl -I http://localhost
You should see the following output:
HTTP/1.1 200 OK Server: nginx Date: Sat, 09 Mar 2019 15:33:31 GMT Content-Type: text/html Content-Length: 10918 Last-Modified: Fri, 01 Feb 2019 16:05:17 GMT Connection: keep-alive ETag: "5c546e3d-2aa6" Accept-Ranges: bytes
Restrict the IPs from the Access
Nginx comes with a simple module called ngx_http_access_module to allow or deny a specific IP address.
If you want to allow Nginx form 172.16.0.0/16 and deny from other subnets. Then, open /etc/nginx/sites-enabled/default file:
nano /etc/nginx/sites-enabled/default
Make the following changes inside server block:
server { listen 80 default_server; listen [::]:80 default_server; allow 172.16.0.0/16; deny all;
Save and close the file, when you are finished. Then, restart Nginx to apply these changes:
systemctl restart nginx
Now, try to access your Nginx server from other IP address range like 192.168.0.102.
Next, check the Nginx log with the following command:
tail -f /var/log/nginx/error.log
You should get access forbidden in the following output:
2019/03/09 16:13:01 [error] 11589#11589: *1 access forbidden by rule, client: 192.168.0.102, server: _, request: "GET /test/ HTTP/1.1", host: "172.16.0.122"
Secure Nginx with TLS
TLS (Transport Layer Security) is the successor to SSL (Secure Socket Layer). It provides stronger and more efficient HTTPS and contains more enhancements such as Forward Secrecy, compatibility with modern OpenSSL cipher suites, and HSTS. This tutorials shows how to enable a self-signed SSL Certificate in Nginx. If you want to use a let's Encrypt certificate instead, take a look here: https://www.howtoforge.com/tutorial/nginx-with-letsencrypt-ciphersuite/
First, create a directory for SSL with the following command:
mkdir /etc/nginx/ssl/
Next, generate a key and a certificate with the following command:
cd /etc/nginx/ssl/
First, generate key with the following command:
openssl genrsa -aes256 -out nginx.key 1024
You should see the following output:
Generating RSA private key, 1024 bit long modulus ...++++++ .............................++++++ e is 65537 (0x010001) Enter pass phrase for nginx.key: Verifying - Enter pass phrase for nginx.key:
Next, generate csr with the following command:
openssl req -new -key nginx.key -out nginx.csr
Provide all the information as shown below:
Generating RSA private key, 1024 bit long modulus ...++++++ .............................++++++ e is 65537 (0x010001) Enter pass phrase for nginx.key: Verifying - Enter pass phrase for nginx.key: root@ubuntu1804:~# openssl req -new -key nginx.key -out nginx.csr Enter pass phrase for nginx.key: You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [AU]:IN State or Province Name (full name) [Some-State]:Gujarat Locality Name (eg, city) []:Junagadh Organization Name (eg, company) [Internet Widgits Pty Ltd]:IT Organizational Unit Name (eg, section) []:IT Common Name (e.g. server FQDN or YOUR name) []:HITESH Email Address []:admin@example.com Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []:admin An optional company name []:IT
Next, sign the certificate with the following command:
openssl x509 -req -days 365 -in nginx.csr -signkey nginx.key -out nginx.crt
You should see the following output:
Signature ok subject=C = IN, ST = Gujarat, L = Junagadh, O = IT, OU = IT, CN = HITESH, emailAddress = admin@example.com Getting Private key Enter pass phrase for nginx.key:
Next, open Nginx default virtual host file and define the certificate:
nano /etc/nginx/sites-enabled/default
Make the following changes:
server { listen 192.168.0.100:443 ssl; root /var/www/html; index index.html index.htm index.nginx-debian.html; server_name _; ssl_certificate /etc/nginx/ssl/nginx.crt; ssl_certificate_key /etc/nginx/ssl/nginx.key; ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
Save and close the file, when you are finished. Then, restart Nginx server to apply these changes:
systemctl restart nginx
Password Protect The Directory
When setting up an Nginx web server, you can also protect a specific directory with a password. You can do this using .htpasswd file.
To do so, create the passwd file and add the user to it with the following command:
mkdir /etc/nginx/.htpasswd
htpasswd -c /etc/nginx/.htpasswd/passwd admin
You should see the following output:
New password: Re-type new password: Adding password for user admin
Next, create a test directory inside Nginx web root with the following command:
mkdir /var/www/html/test
Next, give ownership to www-data user with the following command:
chown -R www-data:www-data /var/www/html/test
Next, open Nginx default virtual host file with the following command:
nano /etc/nginx/sites-enabled/default
Next, protect test directory as shown below:
location /test { auth_basic "Restricted"; auth_basic_user_file /etc/nginx/.htpasswd/passwd;
Save and close the file, when you are finished. Then, restart Nginx service to apply these changes:
systemctl restart nginx
Next, open your web browser and type the URL http://your-server-ip/test. You will be prompt to enter username and password to access the test directory as shown in the following page:
Congratulations! you have successfully secured your Nginx server on Ubuntu 18.04 server. I hope this will help you to protect your application hosted on the Nginx web server. Feel free to ask me if you have any questions. For more information, you can refer to the Nginx security doc.