I fell into the Homelab rabbit hole a while back. I like when things are organized neatly. And I like security. So I did my best to setup my network the right way.

Click here to know more about my Homelab

Picking an IP block

Because 192.168.0.0/24 is too mainstream

There are 3 IP blocks reserved for private networks: 10.0.0.0/8 (10.0.0.0 – 10.255.255.255), 172.16.0.0/12 (172.16.0.0 – 172.31.255.255) and 192.168.0.0/16 (192.168.0.0 – 192.168.255.255). If you want to know more.

For most of my life, the IPs I saw were all in the 192.168.0.0/16 block. It seems like it’s the default for all consumer products. But it’s ugly, annoying to read, annoying to remember. It just sucks.

Just look at ✨10.0.0.0/8✨ in comparison, how it sparkles, how neat and tidy it looks… The chosen one!

VLANs, let’s split things up

The main reason I use VLANs is to keep network devices separate, and control access. Why do I want that? Simple, I’m hosting websites that are publicly available, and I have IoT devices (you know, the things that have a reputation for getting hacked and being used to spy on you or being part of a botnet). Oh and also, seeing each device stored nicely in the network box it belongs to is weirdly satisfying. I’m using the term “device” broadly here, some are physical (laptop, smartphone), some are virtual (VMs, Docker containers).

I made an inventory of all my devices (current and future), and tried to divide them into categories that make sense, at least for me. I also decided on an IP block for each VLAN. Here’s what I came up with:

  • VLAN 1
    • 10.10.0.x
    • “default” VLAN
    • no actual devices are in there. In my case, it’s configured to have access to everything, so I can debug things if I mess up another VLAN config
  • VLAN 10
    • 10.10.10.x
    • Trusted devices with access to everything
    • E.g. my desktop computer
  • VLAN 20
    • 10.10.20.x
    • Important devices that are secluded and need “protection” from everything else
    • E.g. my NAS
  • VLAN 30
    • 10.10.30.x
    • IoT devices
  • VLAN 40
    • 10.10.40.x
    • Entertainment
    • E.g. TV, Playstation
  • VLAN 50
    • 10.10.50.x
    • Publicly accessible devices
    • E.g. Docker containers hosting public websites/apps
  • VLAN 60
    • 10.10.60.x
    • Private apps, services
    • E.g. Docker containers hosting apps that I only use at home
  • VLAN 70
    • 10.10.70.x
    • Guests
    • I have a WiFi network only for guests, secluded from the rest of the network.

See how those IP blocks are nice?! So satisfying

This isn’t perfect, but I think it makes sense.

WiFi

Not much to say. I created WiFi networks for VLANs that need one, VLAN 10, 30, 40 and 70.

I used the WiFi Analyzer Android app to determine the best channels to use as my area is very busy in terms of WiFi networks. WiFi stability and speed is affected if you pick a bad channel, so it’s something worth looking into.

Firewall

I’m using PFsense as my router & firewall. All the network and firewall configuration is done there.

By default, devices in VLANs (other than VLAN 1) cannot access anything outside their own network. Depending on what the VLAN is for, I’ve added some rules to allow access to specific things. When I add custom firewall rules, I always try to give the most restrictive access possible.

I gave all VLANs access to my router on port 53 for DNS, 853 for DNS over TLS and 123 for NTP. My router runs its own DNS server with custom local domains, allowing DNS traffic makes sure all apps can resolve my custom local domains.

I gave some VLANs access to the internet. That’s done by allowing full access to all IP addresses except any private IPs (the 3 IP blocks at the beginning of the article). I could be more restrictive here, and only allow traffic on port 80 (HTTP) and 443 (HTTPS), and maybe a few others. But “it’s fine”.

I’ve added access from certain VLANs to certain VLANs, on specific ports. Sometimes I had to give a specific IP address access to another specific IP address. For instance if a VM needs access to my NAS, as I’m not willing to give an entire VLAN access to my NAS, so the rule allows connection from the VM IP to the NAS IP on port 445 (for SMB, file share access).

Finding what ports to authorize can be tricky. Most of them are easy to find on the web, if you know what protocol your device/VM is trying to use. Here are the common ones I’m using:

  • 80 (HTTP)
  • 443 (HTTPS)
  • 53 (DNS)
  • 853 (DNS over TLS)
  • 123 (NTP)
  • 22 (SSH)
  • 445 (SMB)
  • 3306 (MySQL databases)

I’m not going to lie, getting the rules right required a lot of trial and error. Thankfully, it’s easy to see when things aren’t working, and adding/removing rules is quick.

Static IP addresses

By default, any new “device” (laptop, phone, VM) connecting to the network is automatically assigned an IP (via DHCP). That IP is technically not reserved for that device, and can change whenever the device disconnects & reconnects.

In PFsense, I’ve assigned static IP addresses to devices that I know I need fixed IP addresses for. Otherwise firewall rules that authorize access to certain IP addresses would become useless when those IP addresses would change.

It would also be an issue for my custom domains configuration (see below).

I’ve assigned static IPs to VMs hosting applications, my NAS, my IoT devices.

Reverse Proxy

By default, any self-hosted app has to be accessed using its server IP and port. In my case, it looks like 10.10.60.100:8300 or 10.10.20.8:8080. It works, but we can do better.

Using a reverse proxy allows me to use custom domains instead, which are easier to remember, but also, it can provide https access, which is pretty neat. I’ve decided to use *.lan.louwii.com sub-domains for everything. I’ve picked Nginx Proxy Manager as my local reverse proxy, running as a Docker container.

It took me a bit to understand how everything works together.

  • First step was to enable the DNS server in PFsense, with fallback to Cloudflare privacy friendly DNS servers.
  • I then added all my custom domains to PFsense DNS server, pointing to the IP address of the VM where Nginx Proxy Manager container is running.
  • In NPM, I’ve added the custom domains as well, with the corresponding IP and port number of the application each goes to.

And just because there’s nothing better than an example.

  • Configuration
    • Nginx Proxy Manager hosted on VM with IP 10.10.60.100
      • Exposes port 80 and 443
    • Configuration for my Jellyfin Docker container
      • Hosted in VM with IP 10.10.60.200
      • Container exposes port 8096
      • Domain configured in PFsense DNS: jellyfin.lan.louwii.com, with redirect IP 10.10.60.100 (the IP of Nginx Proxy Manager)
      • Domain configured in Nginx Proxy Manager jellyfin.lan.louwii.com, pointing to IP 10.10.60.200 and port 8096
    • The Nginx Proxy Manager VM needs to be able to access the Jellyfin VM on port 8096, you’ll see why
  • Process Breakdown
    • On my laptop, I type http://jellyfin.lan.louwii.com in my browser
      • A DNS request is sent to the router (via port 53 or 853) to determine the IP address of jellyfin.lan.louwii.com
      • Router checks the domain in its internal DNS server
      • jellyfin.lan.louwii.com is found, router DNS sends back 10.10.60.100
    • My browser sends an HTTP request to 10.10.60.100 on port 80 (default HTTP port) with host jellyfin.lan.louwii.com
      • The VM at 10.10.60.100 receives the request on port 80, it knows port 80 is used by the Nginx Proxy Manager container and “forwards” the request to that container
      • Nginx Proxy Manager receives the request
      • It finds jellyfin.lan.louwii.com in its list of configured domains
      • It sends an HTTP request to IP 10.10.60.200 on port 8096
      • That request is received by the VM hosting Jellyfin, the VM “forwards” the request to the Jellyfin container
      • Jellyfin returns a web page
      • Nginx Proxy Manager receives that web page, it returns it to my browser
      • My Browser displays the web page
    • All of this was done in 350ms
    • As the end user, I’m not noticing anything at all about that process, all I see is a page being displayed after I typed http://jellyfin.lan.louwii.com
    • Technology is beautiful, isn’t it?

Not had enough? Check out the other Homelab articles