Blue locked door
Photo by Maxim Zhgulev on Unsplash

I do not proĀ­fess to know everyĀ­thing when it comes to server adĀ­minĀ­isĀ­traĀ­tion. After all, I am a front-end deĀ­velĀ­oper who simĀ­ply enĀ­joys messĀ­ing with servers. Thereā€™s a cerĀ­tain kind of novĀ­elty to it. šŸ˜€

I thought it would be inĀ­terĀ­estĀ­ing to write about what I usuĀ­ally do to seĀ­cure my VPS, and take inĀ­puts from the comĀ­muĀ­nity on how to betĀ­ter this - even if for a hobby.

The post is priĀ­marĀ­ily for my own refĀ­erĀ­ence, but an avĀ­erĀ­age Linux user might also ļ¬nd it useĀ­ful as a birdā€™s eye view of where to start.

Some comĀ­mands might be speĀ­ciļ¬c to Debian/Ubuntu as thatā€™s what I use on my servers.

Letā€™s beĀ­gin.

Securing a Cloud VPS

Create the VPS with an SSH key.

Any cloud VPS provider will let you add your SSH key(s) to your acĀ­count setĀ­tings and then alĀ­low you to seĀ­lect which key(s) to bootĀ­strap the serverā€™s root acĀ­count with when creĀ­atĀ­ing it usĀ­ing their UI and API.

If you donā€™t use an SSH key, you will typĀ­iĀ­cally get an email with a plain-text passĀ­word to loĀ­gin to the root acĀ­count with.

Use only pubĀ­lic-key auĀ­thenĀ­tiĀ­caĀ­tion.

Using key auĀ­thenĀ­tiĀ­caĀ­tion is an exĀ­celĀ­lent step to strong seĀ­cuĀ­rity. Combine it with disĀ­abling passĀ­word loĀ­gins and youā€™re reaĀ­sonĀ­ably seĀ­cure alĀ­ready.

This is quite easy to conĀ­ļ¬gĀ­ure in the /etc/ssh/sshd_config ļ¬le. Make the folĀ­lowĀ­ing two changes. These might be comĀ­mented out so it might simĀ­ply be a case of unĀ­comĀ­mentĀ­ing them.

PasswordAuthentication: no
PubkeyAuthentication: yes

Thatā€™s it. You should restart the SSH daeĀ­mon now: sudo systemctl restart ssh.

Create a new user with a strong passĀ­word.

A sysadĀ­min might have noĀ­ticed I did not sugĀ­gest disĀ­abling root loĀ­gin in the preĀ­viĀ­ous step.

Well, you do need a regĀ­uĀ­lar user acĀ­count with sudo privĀ­iĀ­leges that works or you end up lockĀ­ing yourĀ­self out. Since weā€™ve alĀ­ready disĀ­abled passĀ­word auĀ­thenĀ­tiĀ­caĀ­tion, itā€™s a good idea to add your SSH pubĀ­lic key manĀ­uĀ­ally to the new acĀ­count.

To do all the above:

  • Create a new user: adduser purple
  • Add to sudo group: usermod -aG sudo purple
  • Add an SSH pubĀ­lic key for loĀ­gin. You have two ways to go about this, so Iā€™ll deĀ­tail them next.

Add an SSH pubĀ­lic key for loĀ­gin

I preĀ­fer to simĀ­ply copy it.

On my loĀ­cal maĀ­chine:

xcopy -sel copy ~/.ssh/id_ed25519_personal_laptop.pub

On the server, paste into an authorized_keys ļ¬le unĀ­der your userā€™s .ssh diĀ­recĀ­tory. No exĀ­tra spaces anyĀ­where, no line breaks. Save the changes and youā€™re done. šŸ™‚

If youā€™d like to avoid this miĀ­nor headache, you can also use ssh-copy-id comĀ­mand line utilĀ­ity from your comĀ­puter but must keep passĀ­word auĀ­thenĀ­tiĀ­caĀ­tion enĀ­abled unĀ­til this is sorted out.

ssh-copy-id -i ~/.ssh/id_ed25519_personal_laptop.pub <username>@<host>

The -i ļ¬‚ag points to the idenĀ­tity ļ¬le.

Disable root loĀ­gin once user loĀ­gin sucĀ­cessĀ­ful.

Once youā€™re able to loĀ­gin usĀ­ing your SSH key on your acĀ­count, open the /etc/ssh/sshd_config ļ¬le again and disĀ­able root loĀ­gin:

PermitRootLogin: no

And ļ¬Ā­nally, restart the ssh daeĀ­mon.

Set up a ļ¬reĀ­wall and deny all inĀ­comĀ­ing reĀ­quests.

ufw is a very easy-to-use soĀ­luĀ­tion and availĀ­able on Ubuntuā€™s reĀ­pos.

sudo apt install ufw

You can deny all inĀ­comĀ­ing reĀ­quests to start with. Based on what you want to use the server for, you can open those ports specifĀ­iĀ­cally later on. We alĀ­ready know weā€™ll need the SSH port (22) so we make sure to add it to the ļ¬reĀ­wall rules beĀ­fore enĀ­abling it.

Youā€™ll need to use sudo now since youā€™re no longer opĀ­erĀ­atĀ­ing as root.

sudo ufw deny incoming
sudo ufw allow ssh
sudo ufw enable

Set up fail2ban.

fail2ban is a simĀ­ple utilĀ­ity to block pesky brute-force loĀ­gin atĀ­tempts. It temĀ­porarĀ­ily bans an IP if it ļ¬nds that a bot/ā€‹huĀ­man beĀ­hind it is tryĀ­ing to break in. The time of the ban inĀ­creĀ­menĀ­tally inĀ­creases with each ban.

If you use the deĀ­fault SSH port (22) to log in to your server, this is abĀ­solutely esĀ­senĀ­tial. I ļ¬nd that within minĀ­utes of creĀ­atĀ­ing a cloud server, a steady stream of loĀ­gin atĀ­tempts beĀ­gin.

Ubuntu has fail2ban availĀ­able in its reĀ­pos. Install it, conĀ­ļ¬gĀ­ure your jails, and enĀ­able it.

Upgrade sysĀ­tem packĀ­ages.

Thereā€™s nothĀ­ing fancy to do here. Just upĀ­grade your sysĀ­tem packĀ­ages and any user-inĀ­stalled packĀ­ages regĀ­uĀ­larly.

Port knockĀ­ing

I had read about port knockĀ­ing on Mike Stoneā€™s blog post. At ļ¬rst, it wasĀ­nā€™t quite clear to me why someĀ­one might want to use it or what it reĀ­ally is. While reĀ­searchĀ­ing whether itā€™s a good idea to change the deĀ­fault SSH port (more on that beĀ­low), I came across the idea once again and deĀ­cided to read up more.

Essentially, you send a seĀ­ries of reĀ­quests to pre-deĀ­ļ¬ned ports, which then inĀ­structs the ļ¬reĀ­wall to open the SSH port for this userā€™s IP adĀ­dress. You can then lock the SSH port again by sendĀ­ing the reĀ­quests in a reĀ­verse orĀ­der afĀ­ter you loĀ­gout of the server.

Keep in mind this is just one more layer to your seĀ­cuĀ­rity setup. Relying on this alone is not a good idea. How-To Geek has a pretty deĀ­cent arĀ­tiĀ­cle on how to conĀ­ļ¬gĀ­ure this.

Change the deĀ­fault SSH port?

This is a conĀ­troĀ­verĀ­sial subĀ­ject. Youā€™ll ļ¬nd it has pros, but also cons. Some say itā€™s bad, some say you can use it as anĀ­other layer in a multi-layĀ­ered setup.

That said, I probĀ­aĀ­bly have no recĀ­omĀ­menĀ­daĀ­tion to give out here. Please do your own reĀ­search. šŸ˜‰


Optionally, deĀ­pendĀ­ing on your use case, thereā€™s more you can do. Letā€™s say you are setĀ­ting up a web server usĀ­ing NGINX - the folĀ­lowĀ­ing apĀ­plies:

Hide NGINX verĀ­sion from server reĀ­sponse headĀ­ers.

Linodeā€™s guide on setĀ­ting up NGINX is well writĀ­ten and I should add, well reĀ­searched! I had been folĀ­lowĀ­ing the pracĀ­tice of makĀ­ing symĀ­links beĀ­tween the sites_available and sites_enabled diĀ­recĀ­toĀ­ries up unĀ­til now. I was surĀ­prised to know thatā€™s acĀ­tuĀ­ally Apacheā€™s workĀ­ļ¬‚ow.

The guide also deĀ­tails how to disĀ­able the server_tokens in your NGINX conĀ­ļ¬g. Doing so proĀ­tects you against verĀ­sion-speĀ­ciļ¬c atĀ­tacks.

Letā€™s check the HTTP reĀ­sponse headĀ­ers in two difĀ­ferĀ­ent sceĀ­narĀ­ios by usĀ­ing curl:

curl -i <yourdomain.com>

Before disĀ­abling server_tokens:

Server: nginx/1.17.10 (Ubuntu)
Date: Sun, 28 Jun 2020 05:53:06 GMT
Content-Type: text/html
Content-Length: 179
Connection: keep-alive

After disĀ­abling server_tokens:

Server: nginx
Date: Sun, 28 Jun 2020 05:53:52 GMT
Content-Type: text/html
Content-Length: 179
Connection: keep-alive

Follow Mozilla Observatoryā€™s recĀ­omĀ­menĀ­daĀ­tions.

Mozilla has an exĀ­celĀ­lent and a very enĀ­joyĀ­able page on Web Security.

You can test your curĀ­rent server conĀ­ļ¬g by headĀ­ing to the Observatory and workĀ­ing your way up based on their recĀ­omĀ­menĀ­daĀ­tions and test reĀ­sults. You get to reĀ­fresh a test every ļ¬ve minĀ­utes. Aim for an ā€˜Aā€™ ratĀ­ing.

Thereā€™s a ton of stuff to learn:

  • setĀ­ting up a Content Security Policy (CSP),
  • disĀ­abling frame-emĀ­beds of your site,
  • inĀ­structĀ­ing the browser not to deĀ­tect a conĀ­tent-type on its own,
  • setĀ­ting up a reĀ­ferĀ­rer polĀ­icy to proĀ­tect your visĀ­iĀ­torā€™s priĀ­vacy,
  • conĀ­ļ¬gĀ­urĀ­ing Cross Origin Resource Sharing (CORS),
  • conĀ­ļ¬gĀ­urĀ­ing HTTP to HTTPS rediĀ­recĀ­tions on both NGINX and Apache,
  • enĀ­abling HSTS,
  • and more!

Seriously, even if all you have the time for is readĀ­ing through the page, do it. Itā€™s well worth it.


Wrapping Up

So what do you think? Is there anyĀ­thing I can add to this list? What can I do betĀ­ter if itā€™s alĀ­ready on the list? šŸ™‚