Securing Octoprint on your Raspberry PI with ssh

Why not just put the Pi on the Internet?
You know, I really hate the idea of exposing the Raspberry Pi to the internet. I cringe every time I hear about someone who just punches a port through to 5000 because they want remote access - it is fairly easy to do this securely, even if you don't use a VPN. When I was doing security work, we would always attack the webservers first when doing a penetration study. Our rule was, if it did more than serve static pages it probably was owned.

So a webserver is, by definition, a weak point. This does not mean it is bad, all security is a tradeoff. If you are running a youtube channel, maybe putting your pi on the web so that people can see your prints in real time is the right thing to do. But most people who install octoprint want to access it remotely so that they can see how their prints are going when they are away from home so that they can cancel prints if they mess up, to save material or to follow progress, and you don't need or want an exposed webserver for that.

Setting up
You need to assign a static address to your pi. Now you can configure that address in the pi, but almost every DHCP server (which is the service that supplies ip addresses from your router to things that connect to your home network) has a way to say, "when this device comes asking for an address, always give it this address and do not give this address to any other device". This is the same as a static address. It does not matter how the address is assigned as long as it is always the same.

It is arguable that no matter how you are going to access your octoprint server, you will want to give it a static IP address. So this is worth doing. Consider also doing this for your printers and such.

All versions of Raspian that I have seen come with ssh. If yours does not, install it with sudo apt-get install ssh

Once the static address is assigned, you can then forward a port. But don't forward port 5000, forward a random port to port 22 on your pi. How you forward a port is dependent on your router. Most routers have a web interface.

Port 22 is the "well known" ssh port. ssh provides a way to remotely log in to your system in a secure manner - you can also "tunnel" connections from the client to the server or vice versa using SSH. When you do that, they are hidden - encrypted. An outside observer can see that there is traffic but the contents are hidden. So you can get a command line on your pi, or, using port forwarding, you can access web servers on the pi - or on other systems behind your firewall. You can also tunnel the other way - expose ports on the pi that are relayed to the client's end. But what we are doing here is going from the device you have in your hand to the pi.

You need a ssh client on the system that you are going to use to access the raspberry pi through the firewall. For windows, consider putty. Or you can install cygwin, a Unix environment for Windows that comes with a ssh client and server, as well as an X server and many other things you might like. There are ssh clients for Android and other platforms. Make sure that the one you use allows for port forwarding of local ports to remote destinations.

Finally, you need to know the outside address of your system. You can get a static IP address (contact your provider, there is probably a fee) or you can use DynDNS or DDNS, which is a service that your router uses to register your dynamically assigned IP address under a name. Then, when you are not at home, you can use the name, and even if your ISP assigns you a different dynamic address, you can find your system by name.

All the pieces are in place. Now do the port forwarding setup.
I open a random port on my router, forwarded to port 22 on my pi - this is to run ssh. Port 22 is the standard ssh port. Why a random port and not port 22? Because I would rather not have door knockers and password guessers tickling my pi, even though I have used good passwords and don't expect to be randomly cracked.

''This is the only port I open on my router! ''The ssh client and server pass the web traffic through, but only for people who can authenticate to the Raspberry Pi's Raspbian system.

On my Pi, I run three copies of octoprint, on ports 5000, 5001 and 5002.

I port forward local port 5000, 5001, 5002, and 8080 (for video) from my phone and laptop to the pi's 5000, 5001 etc, using the following addresses:

Local port 5000 to remote address 127.0.0.1, port 5000. 127.0.0.1 is a special address that means "this machine". I do the same for 5001, 5002, and 8080. Different ssh clients have different ways of telling the client not to accept connections to these forwarded ports from other devices. The classic is not to tell it to bind to just 5000, but to tell it to bind to local address 127.0.0.1, which is a same special address as above, that means, "a port on the local machine" and that means that a port which is bound only to this address is only accessible from the local machine. Some ssh clients have different ways of specifying this, perhaps an option, perhaps a configuration setting. But it amounts to the same thing - you don't want to create a hole by allowing anyone at the coffee shop to connect to port 5000 on your phone and suddenly be connected through your firewall. People at coffee shops can and do run scanners looking for open ports on other devices. They look for clear text traffic on the wi-fi to try and intercept login credentials. That is why you want to encrypt. That is what ssh does for you. Of course, if you are only running one copy of octoprint, you would leave out the forwards for 5001 and 5002.
 * 127.0.0.1:5000 (local) -> 127.0.0.1:5000 (remote)
 * 127.0.0.1:5001 (local) -> 127.0.0.1:5001 (remote)
 * 127.0.0.1:5002 (local) -> 127.0.0.1:5002 (remote)
 * 127.0.0.1:8080 (local) -> 127.0.0.1:8080 (remote)

When I want to use the browser to access the remote port, I use the url http://127.0.0.1:5000 That accesses port 5000 on my local device - which is intercepted by ssh - and encrypted and goes to the random port on my firewall, and through my firewall to port 22 on the pi, where it is decrypted, and then a connection is made to local port 5000 on the pi. ssh does not make a new connection, it uses the same connection for multiple purposes.

It sounds complicated, but it is simple and it is as secure as it can be and still allow you remote access. You can access port 5000 but no one who is not on your device can access the port. Your communication to your system will be encrypted so that your password will be secure. Your initial connection password will be secure because the encryption is established before the password is sent - or you can use a private-public key pair for the authentication.

Conclusion
There are a ton of options. But one thing you should know is that a lot of the world's network security is based on ssh. ssh is very commonly used for establishing secure tunnels, for punching from one security zone through to another, for shielding communication contents from prying eyes where the underlying service does not provide such shielding, and so forth. It has been looked at carefully, and there are people (I am one of them) who believe that as long as ssh exists it is a bad idea to try and add one-off security to a lot of different products. As an example, VNC has sort of crappy security, but the answer is simple - if you need encryption and good authentication, just hide VNC in ssh. These days, X windows uses the same idea.

So ssh is perused and people actually look at it and on those rare occasions when a bug is found it is fixed. So if you are punching a hole through a firewall you could do worse than making it an ssh connection and then using that to tunnel other connections.

Now there are other good ways to access your home system. If you can set up a VPN, if your router supports VPN, it can give you a good, secure path in to your home network that lets you act like you are at home. My phone supports VPN, my laptop supports VPN, and I still tend to use ssh. Because if I do set up a VPN, first thing I do is to ssh to my pi.