Categories
Tech

Nginx SSL Reverse Proxy

Short version

sudo apt install nginx -y
Create a .conf file in /etc/nginx/conf.d/
See full config section for template
sudo nginx -t
sudo systemctl reload nginx

The example in this post uses test.acceptdefaults.com running nginx 1.18.0 on Ubuntu 22.04.
You may need to change commands/paths based on your distro.

Install

Update system

sudo apt update && sudo apt upgrade -y

install nginx

sudo apt install nginx -y

start nginx service

sudo systemctl start nginx

enable (run on startup) nginx service

sudo systemctl enable nginx

conf file

You’ll most likely want to disable the default config file.

sudo rm /etc/nginx/sites-enabled/default

Open a new conf file. You can name it anything. It’s a good idea to name to use the domain name.
See the config location note below if you want to use sites-enabled instead.

sudo nano /etc/nginx/conf.d/test.acceptdefaults.com.conf

Paste the config in the .conf file. Press ctrl+x then Y to save and enter to confirm the filename.
See the config notes below for more details.

server {
	listen 80;
	listen [::]:80;
	
	server_name test.acceptdefaults.com test2.acceptdefaults.com;
	
	location / {
		proxy_pass http://<IP>:<port>;
	}
}

You may need additional proxy options depending on the target application. Most applications will list reverse proxy settings if they need it.

Test the config with sudo nginx -t

sudo nginx -t

Reload nginx to load the new config

sudo systemctl reload nginx

SSL

Obtaining a cert

If you don’t have an SSL cert you can get one from Let’s Encrypt using certbot. Here’s a link to the certbot setup steps.

You can also use a self-signed cert for staging.

sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/ssl/private/nginx-selfsigned.key -out /etc/ssl/certs/nginx-selfsigned.crt

Add SSL Config

If you used certbot this part was already done for you.

Add the lines below to your server directive.
The ssl_protocols and ssl_ciphers can be adjusted as needed. I used the defaults from certbot.

	# SSL
	listen 443 ssl;
	listen [::]:443 ssl ipv6only=on;
	ssl_certificate /path/to/cert.pem
	ssl_certificate_key /path/to/private_key.pem
	ssl_protocols TLSv1.2 TLSv1.3;
	ssl_prefer_server_ciphers off;
	ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384"; 

Move the listen 80 (and listen [::]:80; if using ipv6) to another server directive. Copy the server_name line from the 443 block.

server {
	listen 80;
	listen [::]:80;
	server_name test.acceptdefaults.com test2.acceptdefaults.com;		
}

HTTPS redirect

If you want to redirect HTTP traffic to HTTPS add the line below to your server directive listening on port 80.

	return 301 https://$host/;

Test your config with sudo nginx -t

sudo nginx -t

Reload the config with sudo systemctl reload nginx

sudo systemctl reload nginx

Full config example with SSL

server {
	server_name example.com;
	location / {
		proxy_pass http://<ip>:<port>;
	}

	# SSL
	listen 443 ssl;
	listen [::]:443 ssl ipv6only=on;
	ssl_certificate /path/to/cert;
	ssl_certificate_key /path/to/private.key;
	ssl_protocols TLSv1.2 TLSv1.3;
	ssl_prefer_server_ciphers off;
	ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384"; 
}

server {
	listen 80;
	listen [::]:80;
	server_name example.com;

	# HTTPS redirect
	return 301 https://$host/;
}

Notes

Engine-X not N-Jinx

conf file location

Depending on your OS the default /etc/nginx/nginx.conf file may look in multiple locations for configuration files. You can find this in the http directive (surrounded in {}).
Here’s the default includes from a Ubuntu 22.04 install.

include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;

The internet likes to fight about this but they both work.
Debian based systems also include the sites-enabled directory. You can use /etc/nginx/conf.d/*.conf on Debian based systems.

One benefit of the sites-available and sites-enabled method is having disabled configs in the sites-available directory without having the config active. You can also accomplish this in /etc/nginx/conf.d/ by renaming .conf files to .conf.disabled.

/etc/nginx/conf.d

/etc/nginx/conf.d is pretty straight forward. Any .conf files in this directory will be loaded.

sites-available and sites-enabled

Any files in /etc/nginx/sites-enabled/ will be loaded. Files are typically symlinks (ln -s) from /etc/nginx/sites-available/.

Files are not required to be in the sites-available directory to be loaded and do not need to be a link. This is just a method to keep things organized.
You need to use the full path when creating the symlink or nginx will give an error when loading the config.

sudo ln -s /etc/nginx/sites-available/example.com.conf /etc/nginx/sites-enabled/example.com.conf

config notes

listen: This listens on the IP and port. If no IP is given it will listen on all ports. You can comment out [::]:<port> lines if you do not want IPv6.

server_name: You can use a space separated list if you need multiple domains. The ; is at the end of the list, not each domain.

location /: This uses the “/” location (ex:https://test.acceptdefaults.com/). You can use a different location (/app, /web, etc.) if you do not want to use the root location.

Nginx can also do load balancing but that’s a topic for another post. You could setup the reverse proxy using an upstream with only one server if you plan on load balancing it in the future.