If you’ve used Linux for any amount of time, you’re familiar with ssh. It’s a wonderous protocol/tool that allows one to do all sorts of magical things.
For over a decade, I’ve had various home servers’ SSH daemons exposed on port 22 to the publc Internet. In this blog, we’ll look at some essential best practices to ensure your public SSH server is secure.
1. Disable Insecure SSHv1
If your distro still has protocol v1 enabled by default, find another distro. To disable it, just set this in your SSH config file:
Protocol 1 is not secure anymore, don’t use it. It was removed from OpenSSH in 2017.
2. Disable direct root login
Most Linux distros and unices I’ve come across will already have this disabled, but you should check your sshd.conf file and ensure that the
PermitRootLogin directive is set to
Allowing users to login directly as root from the public Internet is not worth the risk. Login as an unprivileged user and use
sudo to escalate your privileges. You can also just login as root after logging in as a privileged user.
It’s nobody else’s fault, so don’t do it!
3. Disable Password Login, Use Keys
Yeah, so some of you might bristle at this, but SSH keys are so much cooler, and so much safer than old school passwords.
SSH key-based authentication is far more secure than traditional password-based authentication. The keys are larger and more complex than your password, and thus harder to brute force.
They do require a bit of setup, but it’s not difficult and there are guides all over the Internet. Make sure to password protect your SSH key. If you don’t, anyone with your private key can login to any server you’ve configured with your public key, without entering a password.
Make sure to disable password auth on the server config file after you setup your keys:
ChallengeResponseAuthentication no PasswordAuthentication no UsePAM no
You need all three to completely disable interactive password options.
~/.ssh/ for an
id_rsa file, this is your private key.
id_rsa.pub is your public key. They might be named differently on your distro, you can easily check with the
$ file ~/.ssh/* authorized_keys: OpenSSH RSA public key config: ASCII text id_rsa: PEM RSA private key id_rsa.pub: OpenSSH RSA public key known_hosts: ASCII text, with very long lines
If you don’t see a public/private key pair, run this to create one. You should set a password when prompted, as this will encrypt the key. If it’s not encrypted and someone gets it, they can login to any server you can login to with that key:
Demystifying SSH Keys
Now, the easiest way to think about SSH keys is like this:
- The public key is like a physical lock.
- The private key is like the physical key to open that lock.
To authenticate via private key, you prove to the server that you can unlock the lock (through a crypto exchange), which proves you’re holding the private key. You can give out your “lock” to any server you want to login to with the key. They can use that to verify anyone logging in with your key.
Distributing your Public Key
So, you need to distribute your public key (your lock) to the servers you want to login to. You can do this really easily with a script included in the OpenSSH package:
$ ssh-copy-id user@remote_host
You’ll get prompted for a password. The script logs in to
remote_server and copies
id_rsa.pub from the client machine, to
/home/user/.ssh/authorized_keys. This file is a list of public keys allowed to authenticate for that user on that machine.
Anyways, easy peasy, just run
ssh-copy-id against any server you’d like to add your public key to.
4. Setup fail2ban to Block Bots
fail2ban is a great program that helps protect your SSH server by blocking IPs attempting to brute force it. It watches for login failures in log files, and then bans the offending IP address when conditions are met. For example, if someone fails to login to my SSH server 3 times in 10 minutes, I ban their IP in iptables for a half hour.
I don’t run any public SSH servers without the peace of mind of fail2ban.
Anyways, fail2ban is different enough between distros that you’ll probably just have to google “fail2ban ssh $YOUR_DISTRO” to get a good guide.
Setup on Ubuntu (18.04 and up)
If you’re on Ubuntu (I’m on 18.04), you can probably get it going with this:
$ sudo apt-get install fail2ban $ sudo systemctl enable fail2ban
sshd jail is setup by default.
5. Setup Dynamic DNS to Get in from Anywhere
This isn’t necessary from a security standpoint like 1-4, but it will make your experience much better if you’re running your SSH from a server on your home ISP connection.
You can get a real domain name from a registrar for a few bucks a year. Services like Namecheap support dynamic DNS protocols so you can always access your SSH server via the hostname, even if your IP is dynamic and changes.
I use a cheap domain from NameCheap, and
ddns to update it, but there are a ton of guides out there, and your DNS provider will surely have one.
You should be pretty solid with the above. Of course, make sure to keep your server up to date. You’re still susceptible to SSH zero-days, but so is everyone else, and there are probably bigger targets than you.
If you want to take it further, consider these exercises for the reader:
Country IP allow/deny
- Allow only your country, or block others. I don’t know how accurate these lists are.
Turning off SSH when you know you won’t be logging in:
if your bluetooth device is in range
if you’re logged in on console (and not idle)
So yeah, sleep soundly while your SSH is sitting out there waiting for you to call.
- Out on the run and need a file, SSH in and SCP it down, with LFTP.
- On some sketchy public wifi? Setup an SOCKS proxy through your SSH server for secure browsing.
- I SSH home all the time to get passwords out of my cli-based password manager.
- Use SSH as the main entrypoint for all the other services you want to run, but aren’t willing to expose publicly. With a quick SSH tunnel, you can access them securely from anywhere, with only SSH expoed.