Running your own web server (Part 1)
Blog: 30th Jan 2024
I recently decided to run my own web server after several years of using a web hosting service. The decision was mostly based around saving money (my hosting service had just announced a big price rise). Plus, I had some dev plans in mind which needed more than just access to a web server. Anyway, running your own server is geeky fun.
Years ago, I used to run this site on a FreeBSD box at home serving over my home router, so I wasn't daunted by the idea in principle. But I was very out-of-date and knew I needed to catch up with modern security practices. And I wanted to try nginx instead of Apache because learning new stuff is fun too.
So why not build another home server? That initially looks like a a very cheap solution. All you need is an old PC, and, if your IP address is subject to change, a dynamic DNS subscription with no-ip for less than £20 per year. But there are hidden costs too. Electricity here currently costs around £0.29 per kW/h so a typical old PC drawing around 100 W/h running 24x365 would cost me around £250 extra per year on my electricity bill. That’s about the same cost as renting a small virtual server. And I didn’t really want every script kiddie and internet thug out there battering my old home router trying to get in. Or have site crawlers and bots clogging up my home bandwidth. So a rented virtual server looked like the best option for me.
Plan A was to get a FreeBSD virtual server because that’s what I knew best. But I soon learned that FreeBSD seems to have lost some popularity over the years, and few of the big-name companies are offering it pre-installed any more. That’s a real shame! I used to love its simplicity; everything you needed for common server tasks was fully explained in the excellent FreeBSD Handbook. And it was all on one site, easy to find, and very well-written. A really tight one-stop server shop, not a big unruly mess like so many of the Linux distros
But despite the unruliness, I decided to go with Linux, mainly because support for it is universal these days. But which distro to choose? I wanted a free, respected, and stable distro. And I wanted to avoid the possibility of any nasty commercial shenanigans like the rug-pull that Red Hat did with Centos.
So Debian was the obvious choice really. It’s stable and reassuringly distant from the cutting edge—a bit like me. And it's got no commercial entanglements of any kind.
After doing the rounds of the various cloud providers, I ended up choosing Hetzner, mainly on price. They offer really cheap cloud servers—mine cost less than €18 ($20 / £15) per month. That gets me a pre-installed Debian 12 server with 8GB RAM, 80GB storage, 20TB bandwidth, with daily backup and a super-easy to configure Hetzner firewall. Just the job for a small website like mine. You can find cheaper if you dig deeper, but I wanted a big well-known company which was unlikely to go out of business any time soon, and located in the same part of the world as me.
The onboarding was painless. A nice touch is that they offer to pre-install an SSH key during the initial build/deploy process. You just generate an SSH key pair locally (make sure to enter a passphrase to protect against key theft), then paste the public key into the Hetzner site admin page, then create the server. That gives you an SSH key-protected server from the get-go. I didn’t realise how important this was until I started looking at the SSH logs. Within minutes of booting for the first time, I was getting hammered with SSH login attempts, presumably from randomised IP address attacks. Welcome to the world of internet-facing servers.
I’m writing this some 50 days after first boot, and it’s a case of so far, so good. Linux is not so different from FreeBSD at my low level of expertise, so I soon felt at home. I was curious to see how many login attempts had been made since first boot. It turns out that in 50 days of uptime I’ve had 143,948 failed SSH login attempts. That means I’m averaging around 120 login attempts every hour around the clock. And that’s with sshguard blocking the repeat offenders. So the decision to use only SSH key authentication was fully justified: the bad boys are all trying to piss into my tent but the SSH key makes it piss-proof—whereas passwords are merely piss-resistant.
The first job after the birth of the server was to do the obvious low-hanging security stuff:
- I made sure the server was fully updated (it was)
- I double-checked that root login and password logins were disabled in sshd_config
- I set up the firewall in the Hetzner admin panel to allow only incoming traffic on ports 22, 443 and 80 (the latter was only needed for automated TLS certificate renewal)
- I checked that that no unnecessary services were running—there weren’t any because the default Hetzner Debian install is very basic, which is exactly what I wanted
- I set up two-factor authentication on the Hetzner admin page login
- I installed sshguard to block repeated login attempts (more on this in part 2)
- I subscribed to an extra option to get an automated daily backup to enable recovery from disaster
OK, we’ve now got a reasonable starting point: an up-to-date firewalled server listening only for web traffic and SSH, with SSH key authentication using a key protected with a passphrase to protect against the remote possibility of physical key theft. And backups in case of problems. So I could now install nginx and Let's Encrypt TLS with some confidence and take my time to set it up and test it all properly.
In part 2, I’ll talk about the biggest problem for any beginner or wannabe server admin like me: how to find authoritative best security practices.