Reverse Proxy

Having run a reverse proxy on my pi for a couple of months, I though it about time to write an article on how I did it.

First make sure your website is running on your private server. Running a basic apache2 test page will be enough to get you up and running.

Having installed nginx, either by compiling it from source code or installing it from apt, you need to create the configuration file, with the name to help you identify the config:

sudo nano /etc/nginx/sites-available/example.uk.conf

Inside the config file you need to setup the parameters, changing details for your setup.

# Main URL
server {
	listen 80;
	server_name example.uk;
	location / {
		proxy_pass http://IP_ADDRESS/;
	}
}

Save and exit the file.

Create a symbolic link to enable the new config file:

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

Test your nginx configuration:

sudo nginx -t

Reload nginx:

sudo systemctl reload nginx

Ensure that you have port forwarded port 80 on your router to your reverse proxy, and provided you have dynamic dns setup on your domain name you should be able to visit example.uk and see your site.

You can now configure your site to use HTTPS. You will need to install the free certbot client:

sudo apt-get install certbot -y

certbot needs port 80 to get the certificates, so you will need to stop your nginx service temperarily

sudo service nginx stop

Because port 80 is already forwarded to your reverse proxy, everything is in place to get your certificate. Replace example.uk with your domain name.

certbot certonly --standalone -d example.uk -d www.example.uk

After running these commands, you will be prompted to enter some details, such as your email address. These details are required for Let’s Encrypt to keep track of the certificates it provides and also allow them to contact you if any issues arrive with the certificate.

Once you have filled out the required information, it will proceed to grab the certificate from Let’s Encrypt. If you get any errors, make sure you have directed your domain to your IP address, make sure port 80 and port 443 are unblocked and forwarded, and make sure nginx and apache are not running.

The certificates that are retrieved the certbot client will be stored in the following directory. Each domain name has its own directory

/etc/letsencrypt/live/

You can now add the SSL certificate to your reverse proxy configuration. Navigate to your config folder, and open your config file you created earlier

cd /etc/nginx/sites-available

sudo nano example.uk.conf

Under your server {} block, create a new server block. You can copy the original block if your prefer. Update the listening port to port 443 and include the ssl_certificate and ssl_certificate_key instructions to link the SSL certificate.

server {
	listen 443 ssl;
	server_name example.uk;

	ssl_certificate /etc/letsencrypt/live/example.uk/fullchain.pem;
	ssl_certificate_key /etc/letsencrypt/live/example.uk/privkey.pem;

	location / {
		proxy_pass http://IP_ADDRESS/;
	}
}

Now edit the original server{} block to force your site traffic to use your SSL site rather than the original site. This creates a perminant 301 redirect to the https url.

server {
	listen 80;
	server_name example.uk;

	return 301 https://$host$request_uri;
}

In order to get wordpress working on my raspberry pi behind the reverse proxy, I have also had to include these lines in the 443 location block:

proxy_set_header X-Forwarded-Proto https;
proxy_buffering on;
proxy_buffers 12 12k;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
client_max_body_size 20M;

So my whole config file now looks like this:

# Main URL
server {
	listen 80;
	server_name example.uk;

	return 301 https://$host$request_uri;
}
server {
	listen 443 ssl;
	server_name example.uk;

	ssl_certificate /etc/letsencrypt/live/example.uk/fullchain.pem;
	ssl_certificate_key /etc/letsencrypt/live/example.uk/privkey.pem;

	location / {
		proxy_pass http://IP_ADDRESS/;
		proxy_set_header X-Forwarded-Proto https;
		proxy_buffering on;
		proxy_buffers 12 12k;
		proxy_redirect off;
		proxy_set_header X-Real-IP $remote_addr;
		proxy_set_header X-Forwarded-For $remote_addr;
		proxy_set_header Host $host;

 		client_max_body_size 20M;
	}
}