Nazeem.Me

A blog about technology, football and all the other random stuff in my life

Homelab hardening: what, where and how to start

Written by

in

·

You don’t need a security background to make your homelab a much harder target. You need an order of operations.

I spent an afternoon getting Claude to scan my homelab properly for the first time. I expected the scary findings to be at the edge: an open port, a forgotten forward. The edge was fine. The problems were all inside, in the boring places I’d never look at since things worked.

This is the order I wish I’d started in.

What “hardening” actually means at home

Hardening is three questions, asked of every box you run:

  • What can be reached? Which ports answer, and from where.
  • Who can log in? Passwords, keys, and accounts you forgot you created.
  • What happens when something does get in? Whether one compromised device can see everything else.

It is not buying a firewall appliance. Most of the fixes below are a config file and a restart.

Where to look first: from the outside in

Look at your network from the outside

Start with what the internet sees. List your port forwards, check whether UPnP is on, and note any dynamic DNS name pointing at your house.

Then scan your public IP. The catch that cost me twenty minutes: scanning your own public IP from inside your house gives a false result. The traffic never leaves your router, so you’re testing the LAN side of the firewall, not the WAN side. The tell is latency under a millisecond.

Scan from a machine that really is outside: a cheap VPS, a friend’s connection, or your phone’s hotspot.

# from a machine OUTSIDE your network
nmap -Pn -sT --top-ports 1000 --open <your-public-ip>

If the result shows anything you can’t name, that’s your first job.

Treat every remote-access path as a front door

Port forwards, tunnels, reverse proxies, VPN servers. Each one is a way in, and each one skips something.

The classic mistake is having two paths to the same service: a tunnel with a proper login wall in front of it, plus an old port forward that goes straight to the app and skips that wall. Your protection is only as good as the weakest path. Also delete forwards to machines that no longer exist. If something else picks up that IP later, it’s exposed without you knowing.

Map what’s listening on the inside

This is where most of my real findings were. Run a polite scan of your LAN:

nmap -sn 192.168.1.0/24                  # who is alive
nmap -sT -sV --version-light --top-ports 1000 --open 192.168.1.0/24

Keep it gentle. Cheap IoT devices, cameras and managed switches can lock up under an aggressive scan.

Then go through the list and ask, for each open port: does this need a password, and does it have one? You will find things. Mine included an admin dashboard with its login switched off, and a quick Python file server I’d started for one job and never stopped, serving a folder to the whole network.

On a Linux box you can also ask the machine directly:

ss -tlnp | grep -v 127.0.0.1

Anything bound to 0.0.0.0 is listening on every interface, including ones you didn’t think about.

The four things that cause most of the risk

1. Password logins for root over SSH

This was my biggest single finding. I’d hardened SSH on my servers months ago, and then added two more servers since. Neither got the same treatment. Hardening done once isn’t done; every new box needs it too.

Key-only SSH is one small file:

# /etc/ssh/sshd_config.d/10-hardening.conf
PermitRootLogin prohibit-password
PasswordAuthentication no
KbdInteractiveAuthentication no
MaxAuthTries 3

Check what sshd is actually running with, not what you think you wrote:

sshd -t && systemctl reload ssh
sshd -T | grep -E "permitrootlogin|passwordauthentication"

Add fail2ban on top, then prove it works. Newer OpenSSH versions log failures under a different process name, and a jail that never sees a failure looks exactly like a quiet network. Make one failed login from another machine and check the counter goes up:

fail2ban-client status sshd    # "Total failed" should increase

2. Tools you added yourself with no authentication

Self-hosted dashboards, automation services and AI tooling often ship with auth off, on the assumption that “it’s only on the LAN”. Some of them can do a lot more than display things: start and stop machines, change config, delete files.

If a tool can change things and has no login, treat it as the most dangerous thing on your network, because it is. Add authentication if the tool supports it. If it doesn’t, put a firewall allowlist in front of it so only the one or two machines that use it can connect:

# ufw example: only allow two clients to reach port 8000
ufw default deny incoming
ufw allow from 192.168.1.50 to any port 8000 proto tcp
ufw allow from 192.168.1.51 to any port 8000 proto tcp
ufw allow 22/tcp
ufw enable

Before you write the allowlist, check the service’s logs for who actually connects. Otherwise you’ll lock out a client you forgot about.

3. A flat network where everything trusts everything

If your smart TV, your guests’ phones and your NAS sit on the same network, then a compromised TV can reach your NAS. VLANs and a guest network fix this. Even one split, with IoT and guests on one side and everything you care about on the other, removes most of the risk.

Overlay VPNs need the same thinking. Tailscale’s default access policy lets every device reach every other device on every port:

{"src": ["*"], "dst": ["*"], "ip": ["*"]}

That’s convenient, and it quietly undoes your VLANs. If one of your devices faces the internet (a VPS running a website, say), it is now one hop from everything. Tag it and give it only the access it needs, which is usually none at all.

4. Firmware on boxes you never log into

Routers and NAS units update on their own schedule and don’t nag you the way a desktop does. Some vendors roll out security updates in stages, so you may not get a notification at all. Put a recurring reminder in your calendar to check the router and NAS update pages by hand.

How to start: a one-weekend order of operations

If you only have one weekend, do it in this order. Each step is worth more than the one after it.

  1. Outside scan and port forward review. Close or delete anything you can’t justify.
  2. Key-only SSH and fail2ban on every machine, including the ones you added last month.
  3. Allowlist or add auth to anything that can change things. Dashboards and automation tools first.
  4. Patch everything, firmware included.
  5. Segment: a guest/IoT VLAN, and access rules on your overlay VPN.
  6. Write down what you found and what you decided. Future you will run this again.

Make changes you can undo

The most useful habit from the whole exercise: before touching SSH or firewall rules on a remote machine, arm an automatic revert.

# undo the SSH change in 5 minutes unless I cancel it
systemd-run --on-active=300 --unit=ssh-rollback /bin/sh -c "rm -f /etc/ssh/sshd_config.d/10-hardening.conf; systemctl reload ssh"

# ...make the change, then test from a SECOND terminal...

systemctl stop ssh-rollback.timer   # only once the new session works

If you lock yourself out, you wait five minutes instead of walking to the machine with a keyboard. Keep your existing session open while you test from a new one; that session is your lifeline.

What I didn’t fix, and why that’s fine

Not every finding needs fixing today. A few of mine are low risk, already blocked by a firewall, or would cost more to change than they protect. The point isn’t to reach zero. It’s to make each risk a decision rather than an accident.

So write the decision down: what it is, why you accepted it, and when you’ll look again. Otherwise you’ll rediscover the same “finding” next time and argue with yourself about it all over again.

Next up

Start with the outside scan this weekend. It takes ten minutes and tells you whether the rest can wait.

In a follow-up post I’ll walk through the full command set I used, from the outside scan through to the rollback timers, so you can run the same audit on your own setup step by step.