June 2018 – Unfortunately these instructions no longer work on the latest version of Raspbian. I have found an updated set of instructions at the link below, so rather than reinventing the wheel, please follow these instructions instead:
Building a reverse proxy server with Nginx, Certbot, Raspbian Stretch Lite and Raspberry Pi 3
The Goal
- Secure reverse proxy running on a Raspberry Pi at home (using the latest NGINX web-server), so that you don’t have to open multiple ports to the internet on your router.
- Dynamic DNS URL for various web applications at home, e.g RPi Web Cam Interface – http://elinux.org/RPi-Cam-Web-Interface
- Official HTTPS certification from letsencrypt.org for free
- So that you don’t have to login with your password being sent in the clear!
- Required because self-signed certs don’t work when trying to view recorded RPi Cam video on an iPhone/iPad
- Push notifications sent to your phone when events occur such as motion detection
- One Raspberry Pi for the proxy and separate Pis for multiple RPi Web Cam Interface cameras
To summarise how this will work once built, you will have a single external access point into your home network via the secure HTTPS port 443 using something like https://mydomain.com/mycamera/.
This method is called a Reverse Proxy and runs on a Raspberry Pi using the NGINX (Engine X) web server. This web server software is used on many official websites on the internet, and is therefore a secure barrier between the internet and your home network.
A file on the proxy Pi called /etc/nginx/services.conf is used to redirect custom URL sub-paths (such as “mycamera” in the example above) to another internal web server on whatever port you need, such as a Pi running the video surveillance dvr software RPi Web Cam Interface – http://elinux.org/RPi-Cam-Web-Interface
Pre-requisites
You will need to know how to do the following:
- Write a Jessie image to an SD card
- Configure a static IP (a link is included below)
- Edit text files from the command line
- Using an SSH client from your computer such as Putty to connect to the Pi
- Know how to configure your router for port forwarding
Set up the Pi and Install NGINX:
- Create a new Jessie image on an SD card (use whichever method is required for your computer).
- Once booted into the GUI, goto Preferences -> Raspberry Pi Configuration
- Change Boot to CLI
- Untick Auto Login
- Give it a new Hostname (eg proxypi)
- Set your timezone
- Enable SSH
- Press OK and reboot
- Log into the Pi using default user/pass (pi/raspberry)
- Determine assigned IP by running “hostname -I”. (The proxypi really should be connected via ethernet rather than wifi, and DHCP should have assigned you an IP)
- SSH to the Pi using this IP address from your computer (use Putty on Windows)
- Change the default password
- Set a static IP on the Pi using these instructions: https://www.modmypi.com/blog/how-to-give-your-raspberry-pi-a-static-ip-address-update
- Reboot and log back in using the Static IP
- Update the Pi
- Install the latest NGINX. Edit the sources.list and add the stretch branch of raspbian
- Edit the sources.list file
- Add the following to the last line:
sudo nano /etc/apt/sources.list
deb http://mirrordirector.raspbian.org/raspbian/ stretch main contrib non-free rpi
- Prevent all packages using stretch unless specified:
- Create a new file:
sudo nano /etc/apt/preferences
- Add the following lines:
Package: * Pin: release n=jessie Pin-Priority: 600
- Create a new file:
- Update:
sudo apt-get update
- Install NGINX:
sudo apt-get install -t stretch nginx
passwd
sudo apt-get update sudo apt-get upgrade reboot
Set up a Dynamic DNS Hostname
I’m using and paying for Dyn’s Dynamic DNS server due to it’s reliability: http://dyn.com/remote-access/
There are plenty of free options out there though so follow their instructions to set up a hostname and updater client if you prefer.
The instructions below explain how to install a client on the proxypi for automatic IP updates to Dyn. This assumes you’ve already created your dynamic hostname within “My Services -> DynDNS Pro”. (ddclient):
- Install ddclient
sudo apt-get install ddclient
- Answer the questions when prompted
– Other DNS Provider
– Dynamic DNS Server: members.dyndns.org
– Protocol: dyndns2
– Username/password
– Network: web
– URL name. - Generate your conf file from the following link: https://account.dyn.com/tools/clientconfig.html
- Within the webpage, select your host and client (ddclient)
- Compare the generated conf file with what was configured during setup (/etc/ddclient.conf) and update accordingly
daemon=600 protocol=dyndns2 use=web, web=checkip.dyndns.com, web-skip='IP Address' server=members.dyndns.org login=your_username password='your_password' your_hostname
- Test by running
sudo ddclient -daemon=0 -verbose
Configuring HTTPS with https://letsencrypt.org/
- You should already have a webpage that you can browse to on your local network:
- Configure your router to forward port 80 and 443 to your proxy raspberry Pi IP
- Add the Jessie backports to your sources.list by editing
- Then add the following line
- Update:
sudo apt-get update
(ignore any GPG errors)
- Install Certbot
sudo apt-get install certbot -t jessie-backports
- Run certbot
sudo certbot certonly --webroot -w /var/www/html -d your_domainname
It will ask you for your email address as part of the setup.
- You should see a Congratulations! message
- Now follow the next section “Configuring NGINX
http:///
This should give you the welcome nginx welcome page.
sudo nano /etc/apt/sources.list
deb ftp://ftp.uk.debian.org/debian jessie-backports main
Configuring NGINX Proxy:
- Create a new nginx configuration for reverse proxy by editing the following file:
sudo nano /etc/nginx/sites-available/main
- Copy the text below into the “main”text file and edit the entries as required.
- Create an ssl.conf file
- Copy the following text into it
- Create the services.conf file.
- Add as many entries as you need.
- Create a proxy.conf file:
- Copy the following text into this file
- Create a symbolic link to the main site
- (Optional) Strengthen HTTPS key exchange by running the commands below (it takes around 5 mins to generate on a RPi 3 – go make dinner if on a Pi1 – Original Instructions found here: https://bjornjohansen.no/optimizing-https-nginx)
- Test the config:
- Redirect Port 443 on your router to the proxypi
- Restart the nginx service
- Test your site security from here: https://www.ssllabs.com/ssltest/index.html
You should get an A rating! (if step 6 was also followed) - Test that certificate renewal will work
- Set up a cronjob to automate cert renewal. Start by opening the crontab file
- Enter the following line at the bottom of the file
access_log off; add_header Cache-Control public; server_tokens off; # HTTP 80 server { listen 80; server_name _; return 301 https://$request_uri?; } # HTTPS 443 server { listen 443 ssl; keepalive_timeout 70; server_name ; include /etc/nginx/ssl.conf; include /etc/nginx/services.conf; }
sudo nano /etc/nginx/ssl.conf
ssl on; ssl_certificate /etc/letsencrypt/live//fullchain.pem; ssl_certificate_key /etc/letsencrypt/live//privkey.pem; ssl_session_cache shared:SSL:20m; ssl_session_timeout 180m; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5; ssl_dhparam /etc/nginx/cert/dhparam.pem;
sudo nano /etc/nginx/services.conf
location /picam { proxy_pass http://internal-rpi-cam-ip2/html; include /etc/nginx/proxy.conf; } location /picam2 { proxy_pass http://internal-rpi-cam-ip2/html; include /etc/nginx/proxy.conf; } location /couchpotato { proxy_pass http://internal-cp-ip:4001/couchpotato; include /etc/nginx/proxy.conf; } location /sonarr { proxy_pass http://internal-sonarr-ip:8989/sonarr; include /etc/nginx/proxy.conf; }
sudo nano /etc/nginx/proxy.conf
proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; client_max_body_size 10m; client_body_buffer_size 128k; proxy_connect_timeout 90; proxy_send_timeout 90; proxy_read_timeout 90; proxy_buffers 32 4k;
sudo ln -s /etc/nginx/sites-available/main /etc/nginx/sites-enabled/main
sudo mkdir /etc/nginx/cert sudo openssl dhparam 2048 -out /etc/nginx/cert/dhparam.pem
sudo nginx -t nginx: [warn] conflicting server name "_" on 0.0.0.0:80, ignored nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
sudo service nginx restart
sudo certbot renew --dry-run
sudo crontab -e
* 1 * * 1 sudo /usr/bin/certbot renew
That’s it!!
If you have installed RPi Cam on another Pi and the internal URL/IP matches what you configured in /etc/nginx/services.conf, then you should be able to browse using this URL:
https://your-domainname/picam/
PLEASE NOTE – You must end the URL with a trailing forward slash “/”, otherwise the redirect won’t work properly
I built a new proxy pi as I wrote these instructions, so it should all work… I’ll be happy to answer any questions you have though.
Optional Extras for RPi Cam
Please see my other blog posts to add extra features to your setup:
- Set up push notifications for motion detection to receive alerts on your phone, with direct links to watch the video
- Ability to turn motion detection on/off using IFTTT Do buttons on your mobile
Thanks! That is a great guide! I will link to it on my blog if its ok for you 🙂
LikeLike
Will this work on Raspain Debian Stretch or will it only work on Jessie?
LikeLike
It should hopefully work ok – the nginx install used stretch anyway so that should work. I would ignore step 11 “Prevent all packages using stretch unless specified:”.
Letsencrypt step 4 and 6 will need to see if jessie-backports can be changed to see if stretch-backports would work.
The rest should be ok though. Let me know how it goes if you get chance please.
LikeLike
After you’ve got a cert from Let’s Encrypt, is it necessary to still keep port 80 open and forwarded to nginx?
LikeLike
Nope, you can close it back up, but you’ll need to re-open port 80 when renewing the certificate when the current one expires.
LikeLike
Hi, thanks for the guide! I have followed all the steps (including the optional one to strengthen the HTTPS key exchange), but I’m getting an error when testing the config and attempting to restart nginx.
When I run the nginx config check command, I receive the following error:
[emerg] PEM_read_bio_DHparams(“/etc/nginx/cert/dhparam.pem”) failed (SSL: error:0906D06C:PEM routines:PEM_read_bio:no start line:Expecting: DH PARAMETERS)
When attempting to restart nginx, I recieve the following error:
Job for nginx.service failed because the control process exited with error code.
When running the Strengthen HTTPS key exchange command, it executes, runs and completes and generates the DH PARAMETERS. I copied from —–BEGIN DH PARAMETERS—– to —–END DH PARAMETERS—– into /etc/nginx/cert/dhparam.pem ensuring that there was no white space and all characters were copied correctly.
I have gone through the Configuring NGINX Proxy section multiple times to ensure the configuration is correct and all files, settings and symbolic links exist.
I have a valid certificate from letsenrypt.
I have tried removing the /etc/nginx/cert/dhparam.pem and rerun the nginx config check command, but receive the same error.
Any help would be greatly appreciated as I am sure it’s something really simple!
LikeLike
Hi James – given it’s been a year since I wrote these instructions it seems they no longer work (tested myself on a new proxy build). I found an updated guide in the link below, so hopefully these will work instead: https://www.techcoil.com/blog/building-a-reverse-proxy-server-with-nginx-certbot-raspbian-stretch-lite-and-raspberry-pi-3/
LikeLike