Last night I went to DigitalOcean and spun up a tiny new, $4/month droplet – on my own dime! It sounds crazy, but I’ve never actually wanted to pay for hosting myself before. But I have a fun little web app cooking up, one that might eventually pay that $4/month back with interests, and I decided, why not, it’s time to finally put some of my own skin in the game with this whole sysadmin thing.
Last night, and this morning, I think we managed to successfully set up SSH in a way which is protected against most attackers who are not specifically motivated to attack me. Script kiddies and the like. As a dutiful bureaucrat I always like to make checklists out of complicated processes I’m too dumb to remember myself, so here it is: My “common-sense SSH security” checklist.
We’re starting with the “worst-case” scenario here: root
is both enabled,
and has a password-based SSH login.
chpasswd
on root to a random, 32-character password.- Create a non-root, sudoers (if applicable) user, with the following params:
- Username: 16 randomly-chosen alphanumerics.
- Password: 32 randomly-chosen characters.
- Disable root SSH.
- Exit the root SSH session.
- Test: Try to enter the root SSH session again. This should fail.
- Test: SSH in to the non-root user with your password. This should work, but not for long.
ssh-copy-id
to the non-root user, so that you can log in without password- based SSH.- Explicitly enable pubkey-based SSH.
- Explicitly disable password-based SSH. (Make sure to do this after the previous step.)
- Test: SSH into the non-root user with your SSH key. This should work.
- Test: SSH into the non-root user explicitly stating you do not want
to user your SSH key (ssh lets you do this with the
-o
params). This should not work. - Set your SSH
AllowUsers
to be only the 16 randomly-chosen alphanumerics username you have chosen. (This protects against anyone in the future who creates e.g. apostgres
user with the passwordpostgres
.) - Test: Create another random non-root user. Try to SSH in as them. This should fail. Delete the user after doing so.
If you now want to install fail2ban for a little extra peace of mind, go ahead, just know it is no replacement for real, robust security which the above list is a poor imitation of. Here’s my fail2ban coda:
- Install fail2ban. Make sure to copy any
*.conf
files to*.local
. - Ensure fail2ban is
enabled
for SSH. - Set
mode = aggressive
(for peace of mind, remember). - Enable IPv6 (it’s 2024).
- Set
bantime = -1
(infiniban, because who else besides you is trying to get in here anyway?!). - Test: SSH into your server andc watch the ssh.service logs, the
fail2ban logs, and the
fail2ban-client status sshd
line. Try to trigger fail2ban on another device you don’t care about.