Nginx Reverse Proxy

Nginx Reverse Proxy

This is a guide on how to install nginx as a reverse proxy.

Arch

1
2
sudo pacman -Sy #Update repository
sudo pacman -S nginx #Install package

Ubuntu

1
2
sudo apt-get update #Update repository
sudo apt-get install nginx #Install package

Unlink defult configuration on ubuntu (optional)

1
sudo unlink /etc/nginx/sites-enabled/default
1
sudo nvim /etc/nginx/sites-available/default

Copy and paste

1
2
3
4
5
6
7
8
9
server { 
	listen 80;
	listen [::]:80;
	access_log /var/log/nginx/default-access.log; #Change name
	error_log /var/log/nginx/default-error.log; #Change name
	location / { 
		proxy_pass http://127.0.0.1:8000; #Address to host
	}
}

Save and exit

1
sudo cp /etc/nginx/sites-available/default /etc/sites-available/example.com.conf

Edit configuration

1
sudo nvim /etc/nginx/sites-available/example.com.conf

Symlink configuration file

1
sudo ln -s /etc/nginx/sites-available/example.com.conf /etc/nginx/sites-enabled/example.com.conf
1
sudo nginx -t
1
2
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Important: Make sure your domain name points towards your server ip (A or AAAA record).

With the current setup, all incoming traffic on the standard, non-securized, HTTP port is anserwered by Nginx, which passes it to the web application on the Instance.

For security reasons, it is recommended to add an encryption layer with TLS/SSL and to use HTTPS. Whilst it is technically possible to use self-signed certificates, it may cause inconveniences as a warning is displayed by default in a user’s web browser when a self-signed certificate is used. A certificate authenticity (CA) can issue trusted certificates which are recognized by most modern web browsers. The CA Let’s Encrypt provides TLS certificates for free and the configuration of Nginx can be done easily with Certbot, a tool provided by the EFF.

  1. Install Certbot on your Instance by using the APT packet manager:
1
2
3
4
5
apt-get update
apt-get install software-properties-common
add-apt-repository ppa:certbot/certbot
apt-get update
apt-get install python3-certbot-nginx
  1. Certbot provides a plugin designed for the Nginx web server, automatizing most of the configuration work related with requesting, installing and managing the TLS certificate:
1
certbot --nginx
  1. Answer the prompts that display on the screen to request a valid Let’s Encrypt TLS certificate:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator nginx, Installer nginx
Which names would you like to activate HTTPS for?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: your.domain.com
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate numbers separated by commas and/
or spaces, or leave input blank to select all options shown 
(Enter 'c' to cancel): 1
Obtaining a new certificate
Performing the following challenges:http-01 challenge for your.domain.com
Waiting for verification...Cleaning up challenges
Deploying Certificate to VirtualHost /etc/nginx/sites-enabled/reverse-proxy.conf
Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: No redirect - Make no further changes to the webserver configuration.
2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
snew sites, or if you're confident your site works on HTTPS. You can undo this
change by editing your web server's configuration.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
Redirecting all traffic on port 80 to ssl in /etc/nginx/sites-enabled/reverse-proxy.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-Congratulations! You have successfully enabled https://your.domain.com
You should test your configuration at: https://www.ssllabs.com/ssltest/analyze.html?d=your.domain.com
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Note:  When asked if you want to redirect HTTP traffic automatically to HTTPS, choose the option 2. This enables the automatic redirection of all incoming requests via an unencrypted HTTP connection to a secure HTTPS connection. Providing an additional layer of security for the Web application running behind the Nginx reverse proxy.

You can set up your Nginx configuration file using different parameters and headers.

The following example shows common parameters used in nginx.conf with a reverse proxy configuration:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
location/ {
	proxy_pass http://127.0.0.1:3000;
	proxy_http_version    1.1;
	proxy_cache_bypass    $http_upgrade;
	proxy_set_header Host              $host;
	proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
	proxy_set_header X-Real-IP         $remote_addr;
	proxy_set_header X-Forwarded-Host  $host;
	proxy_set_header X-Forwarded-Proto $scheme;
	proxy_set_header X-Forwarded-Port  $server_port;  }

Where:

  • proxy_http_version - Defines the HTTP protocol version (the default is set to 1.0)
  • proxy_cache_bypass - This configuration allows responses to bypass cache.
  • Host $host - The $host variable contains, in order of precedence: the host name from the request line, or the host name from the “Host” request header field, or the server name matching a request.
  • X-Forwarded-For $proxy_add_x_forwarded_for - Defines the address of the client connected to the proxy.
  • X-Real-IP $remote_addr - Contains the client IP address. It forwards the real visitor remote IP address to the proxied server.
  • X-Forwarded-Host $host - Defines the original host requested by the client.
  • X-Forwarded-Proto $scheme - If defined in an HTTPS server block, the HTTP responses from the proxied server are rewritten to HTTPS.
  • X-Forwarded-Port $server_port - Defines the original port requested by the client.

When you install nginx, it automatically includes many modules. Currently, you cannot choose modules at runtime. To disable certain modules, you need to recompile nginx. We recommend that you disable any modules that are not required as this will minimize the risk of potential attacks by limiting allowed operations. 

To do this, use the configure option during installation. In the example below, we disable the autoindex module, which generates automatic directory listings, and then recompile nginx.

1
2
3
# ./configure --without-http_autoindex_module
# make
# make install

By default, the server_tokens directive in nginx displays the nginx version number. It is directly visible in all automatically generated error pages but also present in all HTTP responses in the Server header.

This could lead to information disclosure – an unauthorized user could gain knowledge about the version of nginx that you use. You should disable the server_tokens directive in the nginx configuration file by setting server_tokens off.

To prevent potential DoS attacks on nginx, you can set buffer size limitations for all clients. You can do this in the nginx configuration file using the following directives:

  • client_body_buffer_size – use this directive to specify the client request body buffer size. The default value is 8k or 16k but it is recommended to set this as low as 1k: client_body_buffer_size 1k.
  • client_header_buffer_size – use this directive to specify the header buffer size for the client request header. A buffer size of 1k is adequate for most requests.
  • client_max_body_size – use this directive to specify the maximum accepted body size for a client request. A 1k directive should be sufficient but you need to increase it if you are receiving file uploads via the POST method.
  • large_client_header_buffers – use this directive to specify the maximum number and size of buffers to be used to read large client request headers. A large_client_header_buffers 2 1k directive sets the maximum number of buffers to 2, each with a maximum size of 1k. This directive will accept 2 kB data URI.

Note: Some sources suggest that setting such limits may prevent potential buffer overflow attacks if such vulnerabilities are found in nginx.

We suggest that you disable any HTTP methods, which are not going to be utilized and which are not required to be implemented on the web server. If you add the following condition in the location block of the nginx virtual host configuration file, the server will only allow GET, HEAD, and POST methods and will filter out methods such as DELETE and TRACE.

1
2
3
location / {
	limit_except GET HEAD POST { deny all; }
}

Another approach is to add the following condition to the server section (or server block). It can be regarded as more universal but you should be careful with if statements in the location context.

1
2
if ($request_method !~ ^(GET|HEAD|POST)$ ) {
    return 444; }

ModSecurity is an open-source module that works as a web application firewall. Its functionalities include filtering, server identity masking, and null-byte attack prevention. The module also lets you perform real-time traffic monitoring. We recommend that you follow the ModSecurity manual to install the mod_security module in order to strengthen your security options.

Note that if ModSecurity does not meet your needs, you can also use other free WAF solutions.

The nginx access and error logs are enabled by default and are located in logs/error.log and logs/access.log respectively. If you want to change the location, you can use the error_log directive in the nginx configuration file. You can also use this directive to specify the logs that will be recorded according to their severity level. For example, a crit severity level will cause nginx to log critical issues and all issues that have a higher severity level than crit. To set the severity level to crit, set the error_log directive as follows:

1
error_log logs/error.log crit;

You can find a complete list of error_log severity levels in official nginx documentation.

You can also modify the access_log directive in the nginx configuration file to specify a non-default location for access logs. Finally, you can use the log_format directive to configure the format of the logged messages as explained in nginx documentation.

To additionally harden your nginx web server, you can add several different HTTP headers. Here are some of the options that we recommend.

You use the X-Frame-Options HTTP response header to indicate if a browser should be allowed to render a page in a <frame> or an <iframe>. This could prevent clickjacking attacks. Therefore, we recommend that you enable this option for your nginx server. 

To do this, add the following parameter to the nginx configuration file in the server section:

1
add_header X-Frame-Options "SAMEORIGIN";

HTTP Strict Transport Security (HSTS) is a method used by websites to declare that they should only be accessed using a secure connection (HTTPS). If a website declares an HSTS policy, the browser must refuse all HTTP connections and prevent users from accepting insecure SSL certificates. To add an HSTS header to your nginx server, you can add the following directive to your server section:

1
add_header Strict-Transport-Security "max-age=31536000; includeSubdomains; preload";

Content Security Policy (CSP) protects your web server against certain types of attacks, including Cross-site Scripting attacks (XSS) and data injection attacks. You can implement CSP by adding the following example Content-Security-Policy header (note that the actual header should be configured to match your unique requirements):

1
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;

The HTTP X-XSS-Protection header is supported by IE and Safari and is not necessary for modern browsers if you have a strong Content Security Policy. However, to help prevent XSS in the case of older browsers (that don’t support CSP yet), you can add the X-XSS Protection header to your server section:

1
add_header X-XSS-Protection "1; mode=block";

The default configuration of nginx allows you to use insecure old versions of the TLS protocol (according to the official documentation: ssl_protocols TLSv1 TLSv1.1 TLSv1.2). This may lead to attacks such as the BEAST attack. Therefore, we recommend that you do not use old TLS protocols and change your configuration to support only newer, secure TLS versions.

To do this, add the following directive in the server section of the nginx configuration file:

1
ssl_protocols TLSv1.2 TLSv1.3;

Additionally, you should specify cipher suites to make sure that no vulnerable suites are supported. To select the best cipher suites, read our article on TLS cipher hardening and add a ssl_ciphers directive to the server section to select the ciphers (as suggested in the article on cipher hardening). We also recommend that you add the following directive to the server section:

1
ssl_prefer_server_ciphers on;

This directive will let the decision on which ciphers to use be made server-side not client-side.

As with any other software, we recommend that you always update your nginx server to the latest stable version. New updates often contain fixes for vulnerabilities identified in previous versions, such as the directory traversal vulnerability (CVE-2009-3898) that existed in nginx versions prior to 0.7.63, and 0.8.x before 0.8.17. Updates also frequently include new security features and improvements. On the nginx.org site, you can find security advisories in a dedicated section and news about the latest updates on the main page.

Gixy is an open-source tool that lets you check your nginx web server for typical misconfigurations. After you prepare your nginx configuration, it is always a good idea to check it with Gixy. You can find Gixy here.

If you don’t want to configure nginx manually, you can use a free online visual configuration tool made available by DigitalOcean. You can find this tool here.