How to secure an Ubuntu server using Tailscale and UFW
Any server on the public internet is bound to be attacked by bots looking for weak or leaked passwords and unsafely configured services. Even security experts can misconfigure a database, or an unwitting member of the team can accidentally open up a vulnerability, leaving your devices or network open to attack.
If you have an existing server, you can view this bot traffic by running
sudo less /var/log/auth.log. If your server is like many on the web,
you’ll see lots of “invalid user admin” or “invalid user test”.
Tailscale simplifies network security by letting you keep your servers away from the public web, while keeping it easy to connect.
The best way to secure a server with Tailscale is to accept connections from Tailscale, and ignore any public internet traffic. Since your Tailscale network is invisible, except to those in your network, attackers won’t even be able to find it.
Before you begin this guide, you’ll need an Ubuntu server to secure. This guide assumes you’re setting up a DigitalOcean Ubuntu 18.04 server, but the steps should be similar for most hosting providers and versions of Ubuntu.
You’ll also need a Tailscale account. You can make a free solo account using a @gmail.com address.
Step 1: ssh into your new server
After spinning up a new server, ssh into it with your account details.
ssh <username>@<server host ip>
Step 2: Install Tailscale on your server
You can find instructions at the link below.
Once Tailscale is installed, and you’ve run
tailscale up on your server, continue to the next step.
Step 3: ssh over Tailscale
An important step — since we’re about to restrict ssh access to be only over Tailscale, we’ll exit the machine and re-ssh with our Tailscale IP.
First, find and copy your machine’s Tailscale IP. The easiest way to do this is to run
ip addr show tailscale0
And copy the 100.x.y.z address as shown below.
Once you’ve found it,
exit your ssh session, and start a new one with your
newly copied Tailscale IP.
ssh <username>@<copied 100.x.y.z address>
Step 3: Allow access over Tailscale
For this guide, we’ll use UFW (Uncomplicated Firewall) to restrict traffic to our server. It comes pre-installed on Ubuntu 18.04, so no installation is needed.
First, we’ll set a rule to accept any incoming ssh connections over Tailscale. Tailscale uses the tailscale0 interface and port 41641 for connections, so we’ll instruct ufw to allow any traffic over those
sudo ufw allow in on tailscale0 to any port 22 sudo ufw allow 41641/udp
Step 4: Enable UFW
Before we continue editing rules, you’ll need to enable UFW if it isn’t already.
sudo ufw enable
Step 5: Restrict all other traffic
Next, we’ll set up rules to reject all incoming traffic, and allow all outgoing traffic by default.
sudo ufw default deny incoming sudo ufw default allow outgoing
Now that we’ve set these defaults check your existing firewall rules you might need to keep.
sudo ufw status
You’ll see a list of firewall rules, like this:
To Action From -- ------ ---- 22/tcp ALLOW IN Anywhere 80/tcp ALLOW IN Anywhere 443/tcp ALLOW IN Anywhere 22 on tailscale0 ALLOW IN Anywhere 41641/udp ALLOW IN Anywhere 22/tcp (v6) ALLOW IN Anywhere (v6) 80/tcp (v6) ALLOW IN Anywhere (v6) 443/tcp (v6) ALLOW IN Anywhere (v6) 22 (v6) on tailscale0 ALLOW IN Anywhere (v6) 41641/udp (v6) ALLOW IN Anywhere (v6)
We want to limit this list to the minimum set needed.
To completely lock down your server while retaining ssh access, you could delete every rule except for the “22 on tailscale0” and “41641/udp” rules.
For the example above, I’ll delete all 22/tcp rules, which will remove the ability to ssh over regular connections:
sudo ufw delete 22/tcp
Now, only “22 on tailscale0” remains, meaning ssh can only occur over Tailscale.
To Action From -- ------ ---- 80/tcp ALLOW Anywhere 443/tcp ALLOW Anywhere 22 on tailscale0 ALLOW Anywhere 41641/udp ALLOW Anywhere 80/tcp (v6) ALLOW Anywhere (v6) 443/tcp (v6) ALLOW Anywhere (v6) 22 (v6) on tailscale0 ALLOW Anywhere (v6) 41641/udp (v6) ALLOW Anywhere (v6)
If you expose a web service (80/tcp, 443/tcp), you’ll want to keep those rules around. For less public services like FTP (21/tcp) or a database, consider connecting devices that rely on those services over Tailscale too.
This guide assumes ssh is running on the default port, 22. If you’ve changed your ssh port, you’ll need to change these instructions as well.
Step 6: Restart ufw and ssh
Once you’ve set up firewall rules to restrict all non-Tailscale connections, restart ufw and ssh
sudo ufw reload sudo service ssh restart
Done! Now your server will ignore any ssh requests, except for users who you have invited to your private Tailscale network.
Optional: enable MFA for all ssh connections
Now that your server can only be accessed via Tailscale, you can enforce login rules in using your Tailscale network’s identity provider, knowing they will apply to all your ssh connections too.
For example, you may want to configure your identity provider to require multi-factor authentication (MFA) for every sign-in.
Thanks to /u/mgozmovies whose experimentation and write-up on /r/tailscale inspired this article.