VPS Security Checklist for Indie Hackers (The 30-Minute Hardening Pass)
The moment you put a VPS on the internet, bots start knocking. Here is the no-drama checklist I run before I deploy anything real.
VPS Security Checklist for Indie Hackers (The 30-Minute Hardening Pass)
The moment you put a VPS on the internet, it starts getting scanned.
No DNS. No announcement. No traffic. Still scanned.
If you're using a VPS because it's fast and simple (same), here's the minimum hardening pass that keeps you out of the "I got owned overnight" category.
This is extra relevant with the self-hosting wave (OpenClaw and friends). If your box is holding API keys, tokens, and access to your stuff, treat it like a wallet.
Kubernetes Brain, VPS Reality
Kubernetes is great. We run a cluster. Containerized workflows are real power.
But a lot of people bounce off it because:
- There is a learning curve before you ship anything
- You have more moving parts than a single server needs
- You can spend a weekend wiring YAML instead of shipping the feature
A VPS is the fastest path to a real deployment. Done right, it is also surprisingly safe.
My default deploy pattern is simple:
- Run the app on
127.0.0.1(Node/Next/Vite/Express) - Put Nginx in front of it
- Only expose
80and443to the internet
The Goal
Not "perfect security." Just:
- No password logins
- No root access over SSH
- A firewall that blocks everything you didn't explicitly ask for
- Automatic security updates
- Enough visibility to know when something is wrong
I'm going to assume Ubuntu or Debian because that's what most of us ship on when we want to move fast.
Before you start, open two terminals:
- One connected to the server (your current session)
- One ready to test logging in as your new user
Keep that original session open until the new login works. That one detail saves a lot of pain.
1) Create a non-root user and lock down SSH
Create a user and give it sudo:
Now switch to your laptop for the key step.
This is the part that trips people up: your SSH key lives on your machine, not on the VPS.
If you do not already have a keypair, create one locally:
Then copy your public key to the new user with ssh-copy-id:
That usually prompts for the dev user's password once, then appends your key to the right place automatically.
If you do not have ssh-copy-id, print your public key locally:
Then paste that single line into /home/dev/.ssh/authorized_keys for the dev user on the server. If you do it manually, keep the permissions tight: ~/.ssh should be 700 and authorized_keys should be 600.
Before you touch SSH config, make sure the new login actually works:
Only after that succeeds, edit SSH config:
Set (or ensure) these values:
Restart SSH:
Now, in that second terminal, make sure you can still log in:
If this part feels a little repetitive, good. This is the step that prevents most cheap compromises.
Optional: move SSH off port 22 to cut down bot noise
This is not a magic security trick. It will not stop a targeted attacker.
What it will do is cut down a lot of the dumb bulk scanner traffic that hammers port 22 all day with root, admin, and user login attempts.
If you want cleaner logs and less background noise, pick a different SSH port:
Add that to /etc/ssh/sshd_config, then update your firewall before you restart SSH:
Restart SSH:
Then test it from the second terminal before you close anything:
Treat this as a noise-reduction move, not a replacement for SSH keys, disabling password auth, and fail2ban.
2) Patch the box (and reboot if needed)
If the kernel updated, just reboot.
3) Turn on a firewall (default deny)
If you only need SSH + HTTPS:
If you changed SSH to a custom port, allow that instead of OpenSSH:
If you also need HTTP (for Let's Encrypt challenges or redirects), allow 80/tcp too:
The rule is simple: only open the ports you can explain.
Optional: if you have a static IP, lock SSH down to just you. If you moved SSH to 2222, replace port 22 below with 2222.
4) Enable automatic security updates
This is boring, and it saves you.
5) Install fail2ban (cheap brute-force insurance)
SSH key-only auth already blocks most of this, but fail2ban reduces noise and cuts down on log spam.
If sshd is not listed in the status output, enable it:
Make sure this exists:
Then restart:
6) Don't expose what you don't mean to expose
This is where most "I got hacked" stories actually come from.
- Don't bind admin panels to
0.0.0.0 - Don't run databases on public ports
- Don't expose Redis/Elasticsearch "temporarily"
- Don't publish ports without thinking
If you need something internal, bind it to localhost:
Or put it behind a private network / VPN / Tailscale.
If you are self-hosting anything with an admin UI, keep it off the public internet unless you really know what you are doing.
7) Put your app behind Nginx (keep the Node port private)
This is the pattern that keeps VPS deployments simple and safe.
Run your app on localhost:
Then proxy through Nginx so only web ports are exposed:
If your app is reachable on http://YOUR_SERVER_IP:3000, that is a smell. Fix it.
If you run Docker
Docker is fine. Just keep the same rule:
- Only expose
80/443publicly - Reverse proxy everything else
- Keep secrets out of
docker-compose.yml(env files or a secret manager) - Don't mount the Docker socket into random containers
- Update images regularly
8) Add the minimum monitoring so you can sleep
At minimum:
- SSH login notifications (email/Slack)
- Disk usage alerts (servers die from full disks more often than attacks)
- A simple uptime check for your public endpoint
You don't need enterprise monitoring. You need a smoke alarm.
The Fast Checklist
If you want the TL;DR:
- SSH keys only, disable root + passwords
- Patch and reboot
- UFW default deny incoming, allow only what you need
- Unattended security updates
- fail2ban
- Never expose internal services to the internet
- Nginx in front, Node on localhost
- Add basic monitoring and alerts
Security Doesn't End
This checklist is the baseline. It helps you not get wrecked by the bots scanning the internet 24/7.
But production is not a one-time checklist. Always gauge what risk you have on the server. If you are storing personal data, holding API keys, or connecting tools that can act on your behalf, you need to monitor and keep improving your setup.
Quick external checks (run these on your own domain)
These are not a pentest. They are just fast ways to catch common misconfigurations:
- SSL/TLS configuration: Qualys SSL Labs SSL Server Test
- Security headers and CSP: HTTP Security Headers Analyzer
- Non-intrusive web security scan: ImmuniWeb Website Security Test
I will expand this into a deeper monitoring and scanning post later along with some custom tools I wrote that monitor my NextJS, Vite, and Supabase backed applications for common misconfigurations and leaks. For now, this is a good start for getting your app online without paying "one-click cloud" prices.
Written from home, fueled by "why is this port open" paranoia.
Work With Us
Want to build something like this?
We scope and ship practical AI for SMB teams — voice agents, custom assistants, and workflow automations that actually get used. Real starting prices, no bloated discovery phases.
Enjoyed this post?
Get more build logs and random thoughts delivered to your inbox. No spam, just builds.

