I was very intimitaded about using a VPS outside a VPC my web apps. I had never used a stand alone VPS without some kind of walled garden around it. At work everything is usually behind a VPC. And I have always worked with awesome security people to double check things! I don't have to worry so much about bots or people constantly trying to exploit my service (of course we follow guidence from our excellent security colleagues). But when you turn on your new VPS it immediately can be discovered and bots will immediately try to exploit vulnerabilities.
Recently I launched wishlistpalace.com which is running on a Hetzner VPS and I have come to find out that things are not quite a dire or dangerous as I had thought.
SSH vulnerabilities
One flavor of exploit that bots try against your VPS is to try a bunch of passwords to try to be able to ssh into your new VPS and do whatever (maybe start mining bitcoin or installing malware). Thankfully, VPS providers don't just spin up your box with weak passwords and call it a day. In fact it's even better than that on Hetzner. They let you explicit disable ssh password authentication so this exploit simply won't happen to your new box.
But then you might ask, how do I get into my box then? With the key of course. By default the setup wizard on the Hetzner site for new VPS asks you to provide a public ssh key. You can use
ssh-keygen -t ed25519 -f ~/.ssh/name_of_key -C "your new hetzner box"
to generate a public and private key pair. Then during the setup flow you upload the PUBLIC key.
Later once your box is up you will be able to get the IP for the VPS. Shelling into your box can be made super simple by setting up your ssh config. Add an entry to ~/.ssh/config so SSH uses it automatically:
Host someNameOfYourBox
HostName <your-vps-ip>
User root
IdentityFile ~/.ssh/name_of_key
Just replace the place holder values above of course!
Bot protection
Another probably unfounded fear was that as soon as I turned on my VPS there would be a DDoS or some other overwhelm attack. That I thought this probably means I think a little too highly of myself sure there will be pokes at the new IP but probably not a DDoS right out of the gate. Never-the-less I learned about a few bot protection measures.
Cloudflare
This is probably obvious to most, but if you are really worried about bots, the cloudflare is the way the go. And they have a free tier. I won't list the full instructions on how to setup here, but there are lots of good tutorials I found on line, and Claude was helpful in getting this setup.
I chose also to use nginx in front of my app so I needed to configure the handshake between cloudflare and nginx.
fail2ban
Something you can run on the new VPS is fail2ban which monitors login attempts and temporarily bans IPs that fail too many times. It's kind of fun to use because after a few days you can the thousands of failed attempts to get into your machine from bots.
The VPS I set up is using Ubuntu 24.04 LTS and setting up fail2ban is as simple as
apt install fail2ban
After about a week after I started the VPS here's what I see when I check in on fail2ban with sudo fail2ban-client status sshd to check attacks against ssh.
Status for the jail: sshd
|- Filter
| |- Currently failed: 1
| |- Total failed: 3487
| `- Journal matches: _SYSTEMD_UNIT=sshd.service + _COMM=sshd
`- Actions
|- Currently banned: 0
|- Total banned: 164
`- Banned IP list:
Wow! I'm so thankful bots wanted to try to shell into my VPS!
Firewall
Ubuntu has a firewall utility called ufw and is a quick way to help protect the service you want to run on the VPS. After all I wanted to host wishlist palace the application on the VPS that was the whole point. I chose Elixir's Phoenix framework as the web service part of the app and it exposes the port 4000. But as soon as I spin it up it is possible for people to try some exploit against this port.
But with a firewall and using cloudflare and nginx we can really lock down direct access to the app. The desired state would ensure that the only traffic to the app has to travel through our protective layer above, i.e., cloudflare and nginx.
graph LR
User -->|":443 HTTPS"| Cloudflare
Cloudflare -->|":443 HTTPS"| nginx
nginx -->|":4000 HTTP"| Phoenix
nginx -->|":80 HTTP redirect"| Cloudflare
To achieve this we can setup the firewall to limit to only the ports we need for this desired access pattern. With a few invocations of ufw you can lock access down. But it is important to leave the ssh port open so you can get back in.
ufw allow 22 # SSH — do this FIRST or you'll lock yourself out
ufw allow 80 # HTTP — needed for Certbot's verification step
ufw allow 443 # HTTPS — your app's public port
ufw enable
ufw status # confirm rules are active
This basically sets up an allow list then locks every other port down.
Maybe not so scary after all
That's all I did in the first week of having my VPS and so far it hasn't crashed so maybe I was wrong to be worried. I have no doubt there are other important security techniques I need to learn about but I wanted to share this setup.
I think I might follow up with more details about the cloudflare nginx setup in another post.
Top comments (0)