Articles / Security

  • security
  • threat-modelling
  • self-hosting
  • home-lab
  • reverse-proxy
  • networking

Threat Model Your Home Server Before You Open Port 443

Forwarding port 443 is one line in a router, and it quietly changes what your house is. Before it, nobody outside could talk to your server. After it, every machine on the internet can send bytes to one process, which sits a few cables away from your NAS, your laptop and your partner's phone.

This is a one-page exercise to do first. It takes about twenty minutes, needs a text file, and tends to change what you decide to expose.

Start with what you would be sad to lose

Write the assets down, because the list is usually different from what you assumed. Mine would look something like this:

  • Data on the server itself: photos, documents, a password manager vault.
  • Credentials stored on it: API tokens, SSH keys, database passwords, backup keys.
  • Other machines on the same network that trust it.
  • Your home IP address and the fact that you are home.
  • The server's own capacity, which an attacker may want for spam or crypto mining.

The third item is the one people forget. The server is rarely the prize; it is the foothold. A compromised photo gallery is annoying. A compromised photo gallery with a route to your NAS and a saved SSH key is a different afternoon.

Be realistic about who knocks

Forget the targeted state-level adversary for a home server. The realistic list is automated scanners, opportunists running exploits for whatever CVE was published last week, and credential stuffers trying default logins. They do not care who you are. They care that a version string matches.

Quick detour, because this surprised me the first time: hiding on an obscure hostname does not help much. Public certificates are logged in Certificate Transparency logs, so a name you obtain a certificate for can be found by anyone watching those logs. A wildcard certificate keeps the individual subdomain names out of the logs, which is a small, cheap win. It is not a defence, just less of a signpost.

List every door, not just the one you meant

Port 443 is the front door, but what answers behind it matters more. Check what is actually listening, rather than what you think is:

ss -tlnp
# anything bound to 0.0.0.0 or [::] is reachable from other hosts;
# 127.0.0.1 and [::1] are local only

Then walk the chain a request takes: router, reverse proxy, application, database, whatever the application can call out to. Each hop is a place for a mistake. Typical ones:

  • An admin panel served on the same hostname as the public app.
  • A database or metrics port bound to all interfaces because a container example said so.
  • Default credentials on a setup wizard nobody finished.
  • An app that is months out of date because updating is manual.

Check the IPv6 side separately

Your port forward is an IPv4 NAT rule. IPv6 usually has no NAT: devices get globally routable addresses, and whether the world can reach them depends entirely on your router's firewall. Some routers default to allowing inbound, some do not, and some let you pick per device.

So test both families, from outside your network (a phone on mobile data, or a cheap VPS):

nmap -Pn -p 1-1024,3306,5432,6379,8080 your.host.example
nmap -6 -Pn -p 1-1024,3306,5432,6379,8080 your.host.example

If the second command shows ports the first does not, you have found a door you never opened on purpose.

Assume the app gets compromised

This is the step that earns the exercise. Stop asking "can they get in?" and ask "they are in, now what?". For the process behind 443, answer these:

  1. Which user does it run as, and can that user read anything but its own data?
  2. Which secrets are in its environment or config files?
  3. Which other hosts on the LAN can it open connections to?
  4. Can it make outbound connections to anywhere, so it can fetch tools and send data out?
  5. If it were deleted and rebuilt tonight, what would you lose?

Most home setups fail question three. Everything shares one flat network, so the web app can talk to the NAS, the printer and the router's admin page. Put the internet-facing machine on its own network segment (a VLAN, or a separate router port) and block it from initiating connections to the rest of the LAN. Allow the few specific flows it needs, and nothing else.

Containers or a small VM help with questions one and two, but they are not a substitute for network separation. A container with access to the LAN still has access to the LAN.

Cut the list down to what strangers need

Now go back to your services and sort them. Does a stranger need to reach this, or only you and your family? Photos for the family, the admin interface and the monitoring dashboard are almost certainly the second kind.

For those, skip 443 entirely and put them behind a VPN such as WireGuard, so the only public listener is the VPN's UDP port, which does not respond to packets that lack a valid key. That is a much smaller thing to defend than a web application with a login page. Whatever stays public gets the proper treatment: a reverse proxy in front, automatic updates, and rate limiting on logins.

Write the page, then test it

The output is a small table in a text file. One row per threat, three columns: what could go wrong, what stops it, how you would notice. For example:

  • Outdated app exploited: automatic updates, pinned image tags reviewed monthly; notice via unexpected outbound traffic.
  • Server owned, pivots to NAS: separate VLAN, deny rule to LAN; notice via firewall drops logged.
  • Stolen backup key: key not stored on the server; notice never, so do not store it there.

The last row is the useful kind of uncomfortable. If you cannot say how you would notice, that is a gap to fix, or at least to accept knowingly.

Then verify the controls instead of trusting them. From the server, try to reach the NAS and expect a timeout. From outside, rerun the scans above. Revisit the page whenever you add a service, because each one adds a door, and the router rule never reminds you.