Securing Remote Access for Dedicated Servers
Remote server management with SSH, FTPS, and RDP through OpenVPN on a pfSense
I recently put together a Linux machine to run some Valheim dedicated server Docker images.
This is a follow-up to that article, but can be applicable to many other situations where you want to provide remote access to a machine without directly exposing myriad open ports to the internet at large. This approach can greatly minimize the attack surface and compartmentalize negative impact.
For my home network, my pfSense box is going to do the bulk of heavy lifting in this setup. It serves VLANs, performs all the inter-VLAN routing and firewalling, and can also serve OpenVPN including certificates.
Keep in mind though that these configurations can be done on other devices as well, although the specifics vary. So while some of the details that I'll be going over in this are specific to my own network configuration, this pattern of services can be a useful one to replicate for a wide range of remote access use-cases.
Before setting this up, if I wanted to do any server maintenance I'd have to physically be at the server. If any of the instances crashed, I'd have to go to it, open up a terminal, and restart it. With this setup, I can do this now from anywhere. Not just from my own home network, but even while I'm out and about. I have the VPN client installed on my phone, so I can pipe my phone connection through the VPN, start up a hotspot, and connect any ol' computer to my network through it.
This also means that I can give access to a few trusted friends. If they notice any problems, or have something they want to change themselves, they don't even need to wait on me to take care of it for them.
As a note of caution, though: The friends I have given access to are competent with this stuff. I can trust them to not do inexplicably strange things that break everything in unimaginable ways. I've taken steps to limit access to only necessary parts, which also has the effect of limiting their liability for things going wrong. But ultimately, I'm still placing trust in them to access my own personal equipment. This subject could be a whole rabbit hole of its own, so to keep it brief I'll just caution against giving out access to anyone and everyone.
With every new port opened in a firewall, the potential attack surface increases. While we can't eliminate the need for the open ports for the game's dedicated server (at least not without requiring VPN connections for each client, which would be a fairly ridiculous requirement for a game), we can isolate the server to its own VLAN (or alternatively, its own subnet).
Although, this raises the question: If our server is on its own isolated network segment, is there a need for hiding the open ports of the other services? If we want to run SSH for shell access and FTPS for file transfers, can't we just make sure to use strong passwords and certificates for those connections?
The first reason is perception. If you're scanning through addresses to find worthwhile targets, a private game server might not be very high on your list. Private shell access, remote desktop, and file transfer servers, on the other hand, can paint a more tantalizing story. "What do they have that's worth hiding? Why do they need remote access?" To be fair, this probably sounds a bit hyperbolic. If you start thinking in terms of automation, though, you can start to see why having certain ports exposed can be unappealing. Take a look at this honeypot analysis for a better illustration.
Using strong passwords and certificates for authentication will keep attackers at bay, but that won't stop them from constantly testing for weaknesses. The barrage of inbound connections only multiplies with each additional service added. Which brings us to the next reason.
Piping all of our remote access services through a VPN tunnel allows us to add or remove services as needed without having to worry about opening ports for each, and without having to worry as much about the security profile of exposing those ports. For starters, we'll only be implementing RDP, SSH, and FTPS. But down the line if we also want to deploy other services, we can spin them up without having to expose them directly to the web.
In short, it enables a direct encrypted tunnel solely to the server with whatever services it's running, while minimizing direct exposure to scanners and potential attackers.
Are VLANs required?
In short, no. Not VLANs specifically, although they are a convenient solution in my case.
The purpose that the VLAN serves in this situation is to segment the server access away from your local network traffic.
To ask another way though, is network segmentation required? That answer would be maybe.
The answer really depends on what trust factors to take into account. If the VPN is solely for your own use to remotely access your server, you have much less to worry about with limiting access. If you want to be able to have others remotely access the server, then you need to ask yourself if you also want them to be able to access the rest of your local network.
Using some sort of network segmentation allows for much more control of access. If the VPN is piped directly into a single LAN pool, the access through the VPN is equivalent to allowing access to the entire LAN. Setting up network segmentation enables strict limiting of what the VPN can and can't access.
Network segmentation can be accomplished with subnets and hardware configurations, or by using VLANs. In my own home network, hardware-based segmentation would be difficult as I would have to run an excessive amount of cable. VLANs made segmentation possible without having to spend the rest of my days in crawlspaces. If you're unfamiliar with them and would like to know more, I wrote a series describing VLANs that might be worth a read.
So if the remote access is just for you and you alone, don't worry about having to set up segmentation. But if you plan on having others be able to access it, I'd strongly suggest looking into implementing some sort of access control methodology such as network segmentation.
One last bit...
I originally wrote this out as a step-by-step walkthrough, but came to the realization that it would really only serve well as documentation of my own network and probably wouldn't be of much use to others. Instead, I'm going to take a more broad-brush approach to illustrate the general principles involved with this setup. By and large, there are quite a few good tutorials out there for a lot of the specifics being covered and I will drop those breadcrumbs as we go along.
Setting up the services
Before we get into setting up the VPN, let's just start up the services we're going to want to host if you don't have them set up already. I mostly just use SSH. FTPS makes it quick and easy to copy files to and from the server. And RDP lets me use the desktop from anywhere on the rare occasion that I want to use an application that's GUI based like VS Code.
Thankfully, these are all relatively quick and painless to set up.
SSH is as easy as running
sudo apt install openssh-server. You can double check that it's enabled in systemctl by running
sudo systemctl is-enabled ssh. If it isn't for some reason, you can enable it with
sudo systemctl enable ssh and start it up with
sudo systemctl start ssh. When connecting to it the first time, you'll be asked if you want to trust the provided certificate. After you accept the first time, that warning shouldn't pop up again when logging in from the same machine.
For FTPS, I used vsftpd.
If you run into issues with a systemd error code
systemd: vsftpd.service: main process exited, code=exited, status=2/INVALIDARGUMENT, check out the suggestions in this thread.
RDP gave me the most trouble out of all of them, but only because I didn't realize that I couldn't sign in as a user that was already signed in. Seems silly in retrospect, but it didn't give any errors or indication that it was an issue. It just immediately dropped the connection and left me scratching my head, trying all kinds of things. In the end, this was pretty much all I needed to actually get it to work.
sudo apt install xrdp
If you run into issues, you can take a look through this walkthrough.
There is also a wide variety of other options available for remote desktop. xrdp works well for me, but you can take a look through what's available and see if another might suit your needs better.
Setting up the VPN
There are a few different options when it comes to setting up a VPN server. OpenVPN is the most logical choice for me for a number of reasons, not the least of which is that its functionality is readily available through my pfSense as an add-on package. For clients, an OpenVPN application is needed which is available for free. Other platforms such as OPNSense, Firewalla, DD-WRT, OpenWRT, Teltonika, Ubiquiti, and Mikrotik can readily deploy an OpenVPN server. That's probably not even an exhaustive list. Some SOHO gateway routers might come with OpenVPN functionality built in as well, so if you aren't sure just do a quick search to see whether it's available on your existing equipment.
OpenVPN can also be set up on a server other than the firewall machine. It's available as the Community Edition or as the Access Server, which is the enterprise offering which can be used in a limited fashion for free or as a paid service.
In my case, it's an easy choice to install the VPN server on my pfSense. It's free, it's well integrated, and overall feels like a much cleaner topology than running the VPN server off of the dedicated server machine.
The guide I followed got me most of the way there. It offers a good general purpose configuration.
Unless you have strange use cases such as below, TUN mode is most likely the preferred mode. If you just want to be able to use things like SSH, FTPS, and RDP, go with TUN mode and feel free to skip this section.
The difference between TUN and TAP is similar to the difference between using layer 2 and layer 3 network communications. Kinda.
For TUN mode, a new subnet is created, and that subnet is then NATted to the destination network. Because it's based in a different subnet being piped through NAT, some protocols that only work within a local network's broadcast domain won't work properly.
In TAP mode, the VPN interface is bridged to an existing subnet and clients connecting in can obtain an address through DHCP to that subnet.
For the services I'm using (FTPS, SSH, and RDP), TUN mode works fine. But if remote access ends up being a requirement for other services (ie management of network hardware that utilizes hardware addressing protocols such as MAC-telnet, or services that use broadcast domain transmissions to communicate), TAP mode might be a better option. But keep in mind that TAP mode is incompatible with Android clients. It also won't work with the OpenVPN Connect app, and needs the OpenVPN 2 GUI to function properly.
The only reason I bring it up is that I also set up another management VPN so that I can access and maintain my network equipment remotely as well as access Windows network shares. I can even connect through just using my cell phone as a hotspot if I'm out and about. I can connect my laptop to my hotspot, VPN into my network, and do whatever I need to from wherever I am. (This is a nice trick for getting around the limitation of Android not being able to use TAP mode, if you happen to have a laptop on hand.)
The configuration for TAP differs slightly from TUN because TAP is bridged to an existing subnet while TUN is assigned its own. pfSense's documentation on setting up OpenVPN with TAP mode should clarify things though.
It can be difficult to keep things straight when planning out firewall rules that involve multiple interfaces. To that end, I put together a quick article on a simple diagram that helped me more effectively visualize what's going on. There are also some useful tips in general if you find yourself having issues sorting things out.
From an allow/deny perspective, you're going to want to at least allow traffic from the VPN subnet to server subnet, as well as from the server subnet to the VPN (which may already be covered by an allow all rule). You're also going to want to set up deny rules for any networks that you don't want the VPN to be able to talk to.
If the number of VLANs/subnets involved is minimal, this can be done in an orderly fashion by just going down the checklist of each interface and creating the appropriate rules. Note: Rules for the VPN's interface should go on the newly assigned interface itself, not on the OpenVPN interface.
If you find things starting to get unwieldy, you might want to consider mapping out some floating rules instead. In my case, having WAN, LAN, 4 VLANs, and 2 VPNs was the threshold where it became easier for me to to just use floating rules instead of mapping each interface individually.
Some odd stumbling blocks
In the trials and tribulations of getting my VPNs set up the way I wanted, I chewed through quite a few forum posts that were almost but not quite related. This took me down quite a few roads that turned out to be dead ends. I'll list out the ones I can remember.
Pushing routes: manually defining the gateway and routes using
push "route 10.10.0.0 255.255.255.0" and similar things were completely unnecessary with my setup. The gateway and routes should already defined in the server configuration. Sometimes I would get an error in connection attempts that would lead me to believe that I needed to manually set them, but every time it turned out to be another server setting somewhere that caused the conflict.
Hybrid NAT: I'll be honest in that I don't even remember what initially set me down the road of manually defining Outbound NAT rules in pfSense for the VPN. Something about trying to track down why I couldn't get internet breakout, or perhaps difficulty connecting to other devices. In any case, while the manually defined rules didn't hinder things, they didn't solve any problems either. The automatic Outbound NAT rules were sufficient.
Subnets and static routes: With the VPN hosted directly on the pfSense, its built in routing table is already aware of the subnets that it has generated. Setting up static routes might become necessary if the VPN server is not hosted directly from the pfSense though.
By and large, figuring out the limitations of TUN mode, getting my firewall rules sorted, and setting up a TAP VPN for the things I needed it for solved the issues I was running into that led me down those roads in the first place. Hopefully I've laid out enough breadcrumbs to help anyone else trying this out for the first time to avoid some of the same mistakes I ran into.