A secure home gateway on the Raspberry Pi in four parts. Part four, proxying to your devices
I have some very nifty devices lying around in my home:
- A couple of computers
- A very smart router with the Tomato firmware
- A Raspberry Pi model B (the only one you can get right now)
- A Popcorn Hour A200
The amount of cool things you can do with this is enormous. However, until yesterday morning, these devices were working with most of their default settings (BOOOORING). Here's how I made it awesome in one evening.
Part four, proxying to your devices.
- Part one - Dynamic DNS
- Part two - nginx on the Raspberry Pi
- Part three - free HTTPS to the rescue
So far we used all of the devices above, except for the Popcorn Hour. This device offers, amongst other things, a torrent client over the web. If you go to http://192.168.1.133:8077, or whatever IP your popcorn hour has, you'll get redirected to http://192.168.1.133:8077/transmission/web, and you will see the Transmission Web UI. But that's only accessible over the internal network. It'd be nice if we could control our torrents over the web. (Torrents are great for downloading large files like open source linux distro's!).
So in our nginx configuration file, we add a location directive:
server {
server_name home.waleson.com;
listen 443 ssl;
error_log /var/log/nginx/home.error;
access_log /var/log/nginx/home.access;
ssl on;
ssl_certificate /usr/local/nginx/conf/home.waleson.com.crt;
ssl_certificate_key /usr/local/nginx/conf/home.waleson.com.key;
root /srv/www;
index index.html /index.html;
location /transmission {
proxy_pass http://192.168.1.133:8077;
}
}
Now restart nginx:
/etc/init.d/nginx restart
And voila, we can access the transmission interface securely over the web from https://home.waleson.com/transmission/web. Great!
I said securely, but it's not really. No one can eavesdrop on the connection itself, but anyone will be able to access our torrent server! Not good, not good!
We need to password protect everything under /transmission.
To do that, we add two lines to the location directive:
server {
....
location /transmission {
auth_basic "Are you l33t enough to torrent?";
auth_basic_user_file htpasswd;
proxy_pass http://192.168.1.133:8077;
}
}
The auth_basic_user_file is a list of usernames and crypted passwords. It is important to realize that the path is relative to the main nginx.conf file in /etc/nginx.
You can easily create a login entry from bash like so:
printf "USER:$(openssl passwd -crypt PASSWORD)\n" >> /etc/nginx/htpasswd
To see what this does, run
printf "USER:$(openssl passwd -crypt PASSWORD)\n"to display the output in the terminal itself. It will be:
USER:CRYPTEDPASSInstead of displaying it directly, we want to append that line to a file, so we use >> /etc/nginx/htpasswd to append the line to the /etc/nginx/htpasswd file. If it does not exist, it will be created.
Restart nginx, and now when you go to https://home.waleson.com/transmission/web, you'll be prompted for a password.
We're not done yet.
Torrenting is fun, but what about accessing the router settings? As said earlier, this is something that would be cool to do, but you need security. We have https now, so if we work with passwords, they can't be eavesdropped. Let's make it so.
We could simply add another location like this:
server {
....
location /router {
auth_basic "Are you l33t enough to access the router?";
auth_basic_user_file htpasswd;
proxy_pass http://192.168.1.1;
}
}
But if you try this, you will get a 404. The request you made will be sent directly to the router. However, the router's web server has no idea what /router means. The admin interface is available under /, not under /router/. So instead, we'll have to use a location like this (notice the trailing slashes after /router and after the ip):
server {
....
location /router/ {
auth_basic "Are you l33t enough to access the router?";
auth_basic_user_file htpasswd;
proxy_pass http://192.168.1.1/;
}
}
This will strip the /router bit from all of the requests.
Another problem arises, unless you've been careless. Your router's admin interface will prompt you for a password, but nginx has already prompted you for a password. You can only specify one username/password for the entire connection though. If you chose the exact same username/password combination, nginx will probably pass the credentials along with the requests. This could be what you want, but the problem is that it is an implicit contract, which makes it hard to debug when things go awry. Furthermore, I'm not sure that the basic auth attributes aren't stripped from the request by nginx. Fortunately, we have two options to make this work anyway.
- No nginx authentication for /router
- Let nginx fill in the router credentials for you
I chose the second option, by putting the router's credentials in the nginx directive:
server {
....
location /router/ {
auth_basic "Are you l33t enough to access the router?";
auth_basic_user_file htpasswd;
proxy_pass http://192.168.1.1/;
proxy_set_header Authorization "Basic XXXXX";
}
}
Of course you shouldn't put XXXXX there, you should base64 encode the string "USER:PASS" and put it there. Something like this:
jt@augustine:~$ python
Python 2.7.3 (default, Aug 1 2012, 05:14:39)
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import base64
>>> base64.b64encode("USER:PASS")
'XXXXX'
>>>
So there you have it, I can now safely manage my home devices from over the internet! Thank you for reading, and please be thankful for the RaspberryPi foundation and all of the open source packages I used.
Comments
Post a Comment