Secure access to home IP cameras over the web with SSL

IP cameras are cheap these days. I have a few Foscam FI8910W cameras at home as part of my home security system. A friend recently gave me a Foscam C1 to be used as a baby monitor. I try to avoid using the manufacturer’s mobile device apps for viewing the video feeds because 1) I don’t want my private information (video, IP address, credentials, etc) exchanged or leaked to the manufacturer and 2) I don’t want to have to use multiple apps if I buy multiple cameras from different manufacturers. I currently use tinyCam Monitor PRO on my Android device to view the video feed both on the home network and while I’m away. It works very well, is customizable, and supports many different manufacturers.

I took precautions when setting up the cameras on my home network since I know these cameras could be easily hacked with a default setup:

Secure home network with a router running Tomato Firmware

Use the latest firmware on the cameras

Change the default username and password on the cameras

Avoid using any of the manufacturer’s services on the camera that makes it easy to view the video feed on the web (eg, DDNS)

Use SSL (https) to encrypt the internet traffic/video feed

Regarding the use of SSL, newer cameras like the Foscam C1 should support it by default, so making it world-accessible is as easy as setting up a port forward on the router to the IP camera port 443 (or whatever the https port is). However, for older cameras like the Foscam FI8901W that don’t support SSL, one could set up an encrypted reverse proxy using a web server like nginx. Luckily, nginx is available on my router running Tomato Firmware so I don’t have to use a separate Linux server. Here’s how I set this up on my router running Tomato:

On the Administration page of the router running Tomato, enable both http and https access to the router’s administration. Check the “Save to NVRAM” box. The point of this is to create a certificate and key on the router that we could use with nginx so we don’t have to generate these files elsewhere. I ssh’d into the router and found the following files: /tmp/etc/cert.pem and /tmp/etc/key.pem.

Go to the Web Server page of the Tomato router, and follow this guide step by step to incrementally set up a reverse proxy on nginx. Paste the final server code inside the “http” section of the web server page on Tomato (assuming we want port 1234 to be the external port for the camera, 192.168.1.100 is the camera’s IP address internally, and 88 is the web port of the camera internally):

server {
listen 1234; # doesn't have to be port 443 - could be any port (say 8080) if you
# connect via https://192.168.0.101:8080 . But on port 443
# you can just use https://192.168.0.101
ssl on;
ssl_certificate /tmp/etc/cert.pem;
ssl_certificate_key /tmp/etc/key.pem;
# certificate and private key where you just placed them

Set up port forwarding: external 1234 to 192.168.1.1:1234, where 192.168.1.1 is the IP address of the router.

To make the router respond to the ports (eg, 1234) when requested from the outside world, we need to add a rule to iptable by pasting the following in the “Firewall” section of the Administration > Scripts page (to have it run immediately without reboot, ssh into the router and execute):

iptables -t filter -A INPUT -p tcp --dport 1234 -j ACCEPT

Do the previous step for each camera or port. If this is not done, then the external port will not work when we access it outside the home network (the point of all this!).

Turn on the nginx web server on the Web Server page.

When away, go to a web browser or mobile app and point to https://external_ip:1234 (enable SSL if using a mobile app) and the video feed should be encrypted and available.