A cryptominer lived on my server for 11 days before I noticed. This is the checklist I wish I'd had.
Save it and go through it once a month ✅
1 · Lock the door
- SSH and admin pages reachable only over Tailscale
- Tailscale rules start from "nothing allowed", 2FA on the login
2 · Fewer ways in
- Unused apps, ports and debug pages gone
- Automatic security updates on, Dependabot alerts fixed the same day
3 · Watch everything
- An outside uptime check every minute
- Alerts for stuck CPU, new logins, error floods, a full disk
4 · Secrets
- Nothing in your code or git history
- Env files readable only by the app, keys masked in logs
5 · Backups
- Nightly, encrypted, off-site
- A restore actually tested this month
6 · Least privilege
- No app runs as admin
- One account and one key per job
7 · The front door
- Every input type-checked, never pasted into a query
- Rate limits, security headers, form tokens
8 · The accounts above
- 2FA by app or key on email, registrar, DNS, GitHub, hosting, payments
- Domain transfer lock on, old tokens removed
Want an AI to run this audit on your own server? The skill is in the reply below 👇
Security series 9/9
An article with the full security series plus the skill is at:
rodesia.org/blog/how-i-secur…
Whoever gets into your email doesn't need your servers. They just reset every password you have.
So guard the accounts that own everything else
- email first, it's the reset button for the rest
- 2FA with an app or a hardware key, never SMS (a SIM swap steals those codes)
- recovery codes kept offline
- the transfer lock on at your domain registrar
- old tokens and connected apps you forgot about, removed
This week I rotated my keys for GitHub, Cloudflare, email and my AI provider. Each key does one job, so I knew exactly what each change would touch.
Security series 8/9 🔑
My site's text editor took almost 1.4 seconds to open.
So I profiled it. Stack Overflow's Stacks Editor was building a brand new markdown parser for every line of text. One long page meant hundreds of them.
Now it reuses one. With a few smaller fixes on top, the editor opens in under half a second.
What's the weirdest slowdown you've found inside a library?
Security, part 7. Your web app's front door 🔒
This week a bot fired 62 SQL-injection attempts at one of my sites in 2 minutes. Every one bounced, and I had no idea that bot was coming. The front door was simply built to say no.
What makes it say no
1. Check the type of every input. The page number must be a number, so "?page=2 UNION SELECT…" was rejected before it got anywhere near the database. Use your framework's validation, and never paste what a visitor typed into a database query.
2. Rate limits. More than 40 requests in 10 seconds from one visitor gets "slow down". Logins have their own limit, so nobody can guess passwords at full speed.
3. Security headers. A few lines of config tell browsers to use HTTPS only, not to guess file types, and not to let other sites show my pages inside theirs (a common trick to steal clicks).
4. Forms carry a hidden token, so another site can't submit a form as you while you're logged in.
5. A shield in front. Cloudflare sits before my servers, hides their address and soaks up floods before they arrive.
That bot taught me something too. At first my monitoring saw 62 attackers. It was one, faking a new address on every request. Cloudflare adds the real address last, and I had been reading the whole list. Now I only trust the last one.
Be careful what you trust. Anything a visitor sends you can be faked, even their address.
Security, part 6. Give everything only the access it needs 🔒
The intruder from part 5 got full control of one app and still never reached the rest of my server. That's least privilege. When something is broken into, what else can it touch? Keep that answer as short as you can.
How I do it
1. Apps don't run as admin. My sites run as a plain user made just for them, with no special system powers. The app that was broken into now also has read-only files and a CPU limit.
2. Each app sees only its own files. A site's container gets its own folders and nothing else on the disk.
3. Servers can't talk to each other freely. My Tailscale rules start from "nothing allowed", and each server may open only the few connections it needs.
4. One account and one key per job. I log in with my own account, and the software that runs the sites has its own. Every service has its own API key, so a leak opens one door and I can change that key without breaking the rest.
5. Tools get the smallest permission that works. A tool that only reads gets read access. A deploy key covers one repo, never your whole GitHub account.
For people
- SSH keys, never passwords.
- Two-factor login on every account that offers it.
- Remove access the day someone no longer needs it.
Ask this of everything you run. If it were broken into tomorrow, what else could it reach?
A customer's site took 12 s to load through Cloudflare yesterday. Same server, direct, 30 ms.
I blamed my config first. But Cloudflare's own trace page was slow too, and my free plan sites were going from Helsinki through Warsaw.
So my admin now times both paths from a few places, my Pi in Lisbon too. If Cloudflare drags, DNS skips it. Once it's been fast for 30 min, it goes back.
Security, part 5. When something still gets through 🔒
The attacker who got into my server through that unpatched tool did something clever. They closed the hole behind them, so no one else could use it. Then they mined crypto on my CPUs for about 10 days before I noticed.
What I did, in this order
1. Kept the evidence. I copied what they'd planted and the CPU history off the server.
2. Checked the whole server. Logins, services, scheduled jobs, outgoing connections. It had never left the tool's container.
3. Updated the tool and removed their files.
4. Changed every secret they could have seen. Passwords, keys, tokens. Then I gave the other apps new API keys.
5. Locked the app down with no admin rights, read-only files and CPU limits. Next time a miner can't take the whole machine.
Backups are what made it calm instead of scary.
- Every night, encrypted, stored off the server. If the server dies or is wiped, the backups don't go with it.
- Databases are copied safely, never mid-write, and checked after each copy.
- I keep 7 daily, 4 weekly and 6 monthly copies, so I can go back to before a break-in even if I notice late.
- I can restore one site at a time, and every restore first saves the current state, so a restore can't make things worse.
Remember 3-2-1. Three copies, on two kinds of storage, one of them off-site. Even better, give your backups credentials that can add copies but never delete them.
And if you're ever broken into, rebuild from a clean copy. Don't try to "clean" the broken one.





