The Problem
Every few weeks, my entire house would lose the internet. Not the ISP. Not the WiFi. Everything, all at once, including things that have nothing to do with the internet. DNS stopped resolving, so none of my internal services could find each other. DHCP stopped handing out addresses, so anything that rebooted came up with no network at all. My phone would sit there spinning. My wife would ask, in a tone I have come to recognize, whether the internet was broken again.
The culprit was a small fanless N100 mini PC I bought off AliExpress for about the price of a nice dinner. It ran pfSense CE perfectly well, right up until it didn't.
And the recovery ritual is what really got me. My rack is mounted on the wall, so bringing the network back meant climbing a ladder, carrying an HDMI cable, a wireless keyboard and a display up with me, plugging all of it into a firewall, and restarting the thing. At which point it would come up perfectly happily, as if nothing had ever been wrong, and I would climb back down and unplug it all again.
Here is the part that made it maddening. Just pressing reset did not work. Reset with a monitor and a keyboard attached worked every time. It was as though the box only agreed to boot if somebody was watching.
I ran last reboot one evening to see how bad the pattern was. Thirteen unclean shutdowns. That is not a router. That is a coin flip with an ethernet port.
I never chased down the root cause, but writing this up I went looking, and it turns out to be an extremely well travelled road. The UEFI firmware on a lot of consumer mini PCs simply refuses to complete boot when it cannot detect a display. Netgate's own forum has been collecting these for years: 2.4.0 does not boot without Monitor, Can't boot without monitor, a Shuttle DH110 doing the same thing, and an HDMI console going dark when pfSense boots with the monitor off.
There are real fixes, and they are cheap. An HDMI dummy plug is a couple of dollars and makes the firmware believe a monitor is present. Disabling the serial ports in BIOS clears it on some boards. So does enabling CSM, or flipping the UEFI OS type. Any one of those might well have ended my ladder trips for the cost of a coffee.
I did not do any of them, and I want to be honest about why. It was not that I could not find the fix. It was that I no longer wanted to keep patching around a machine I had stopped trusting. Every workaround would have been another thing propping up a box that had already cost me thirteen outages and an unknown number of ladder climbs, and I would still never really know why it went down in the first place.
What I wanted instead was equipment from the people who actually make pfSense, which reviews consistently said was good. I had resisted spending money on that for a long time, because a firewall is deeply boring and there is always something more fun to buy. But once I added up what the cheap one had actually cost me in time and irritation, the maths stopped being close. If the new one simply does not break, it will have paid for itself.
So I bought a Netgate 4200.
The Plan
Here is the arc, so you can see where this is going:
- [x] Back up the existing config
- [x] Bench the new box behind the live firewall
- [x] Update it before touching anything
- [x] Restore the config
- [x] Two cable swap cutover
- [x] Verify everything
Six steps. It took few hours, and almost none of that time was spent on the parts I expected.
What I Was Replacing
Let me be fair to the N100 box for a moment, because it was not a bad machine.
Intel N100, 16 GB of RAM, four 2.5 GbE ports, completely silent, drew almost no power. It ran pfSense CE 2.8.1 with zero packages installed, which turned out to matter enormously later. It routed my whole network for a long time without complaint. For the money it was genuinely good.
The problem was never performance. The problem was that when it failed, I had no way to diagnose it and nobody to ask, so my only tool was a ladder.
What I actually wanted was boring. A box whose entire job is to be a firewall, built by people whose entire job is building firewalls, that I never have to look at.
The Question I Actually Started With
Before I plugged anything in, I had one question I could not find a clean answer to anywhere:
Do I update the new appliance first, or restore my config first?
This sounds trivial. It is not, and getting it backwards can waste an afternoon.
The rule, once you find it buried in Netgate's documentation, is about the configuration revision, not the version number. Every pfSense release stamps a revision into config.xml. My CE 2.8.1 box was on revision 24.0.
And the rule is one directional:
| Direction | Supported? |
|---|---|
| Older config onto a newer release | Yes, and it gets upgraded automatically |
| Newer config onto an older release | No, rejected outright |
So if my new appliance had shipped with something older than my config's revision, restoring first would have simply failed. Update first, and the direction is always safe.
There is a second ordering rule I have never seen written down anywhere, and it is arguably more important:
The restore has to be the very last thing you do before cutover.
The instant that config lands, the new box believes it is your gateway. It claims your gateway IP, starts a DHCP server, and starts answering DNS for all your internal hostnames. If it is connected to your live network at that moment, you now have two devices fighting over the same address and two DHCP servers racing to answer every request. That is a genuinely bad afternoon, and it is entirely avoidable by unplugging one cable.
So the sequence is: update, then unplug WAN, then restore, then cut over.
The Free Safety Net Nobody Mentions
This is the best practical tip in this entire post, so I am putting it in its own section.
My LAN runs on 10.10.10.0/24. The Netgate ships with a factory default LAN of 192.168.1.1/24. Those do not overlap.
Which means I could plug the new firewall's WAN port into a switch port on my existing network, plug my laptop into the new firewall's LAN port, and run the whole thing as a lab behind my live firewall while my house carried on completely unaware. The new box got internet through double NAT, which is perfectly fine for pulling updates. My laptop sat on 192.168.1.x on one side and 10.10.10.x on the other, with no conflict.
[ISP] → [old firewall] → [switch] → [new firewall PORT1/WAN]
↓
[new firewall PORT2/LAN] → [laptop]
Nobody's Netflix was harmed. I could take as long as I wanted.
Here is the opinionated version: this is the single strongest argument for replacing a firewall with a second physical box rather than reinstalling the one you have. There is no equivalent safety net when you are reformatting your only router. You are committed the moment you boot the installer. With two boxes, you can fumble around for hours and roll back with two cables.
Check your subnets before you rely on this. If your LAN happens to be on 192.168.1.0/24 you will need to temporarily move the new box to something else first, which is a five minute detour and still worth it.
The Port Labels Are Lying To You
Here is the trap that would have cost me an hour if I had not read the docs first.
On the Netgate 4200, the front panel port numbers run in the opposite direction to the underlying device names:
| Front label | Device name |
|---|---|
| PORT1 WAN | igc3 |
| PORT2 LAN | igc2 |
| PORT3 | igc1 |
| PORT4 | igc0 |
My old box had WAN on igc0 and LAN on igc1.
Read those two things together and you will see the problem. Those device names exist on the new box. They are just physical ports 4 and 3. So restoring my config unmodified does not throw an error, does not prompt for anything, and does not warn you. It quietly wires your WAN to the port silkscreened PORT4 and then sits there passing no traffic while you check cables and question your life choices.
Even the MAC addresses run backwards:
PORT1 / igc3 00:00:5e:00:53:a0 ← this is the MAC printed on the label
PORT2 / igc2 00:00:5e:00:53:a1
PORT3 / igc1 00:00:5e:00:53:a2
PORT4 / igc0 00:00:5e:00:53:a3
The fix is trivial once you know. My entire 31 KB config file contained exactly two hardware specific strings, on lines 70 and 83. Everything else refers to wan and lan as logical names that do not care what silicon they land on.
# Remap WAN igc0 → igc3 and LAN igc1 → igc2 before restoring
sed -i '' 's|<if>igc0</if>|<if>igc3</if>|; s|<if>igc1</if>|<if>igc2</if>|' config-remapped.xml
# Always confirm you did not corrupt the XML
xmllint --noout config-remapped.xml
Two lines. That is the entire hardware migration. It is worth pausing on how good that is: a firewall config with 36 DHCP reservations, 34 DNS overrides, NAT rules and a dynamic DNS client moved between completely different hardware by changing two strings.
The reason it was that easy is that I had zero packages installed. No pfBlockerNG, no HAProxy, nothing. Packages are where migrations get ugly, because they carry their own state and their own version compatibility. If you are planning a hardware swap someday, the cheapest thing you can do today is resist installing packages you do not truly need.
Then Nothing Worked At All
I had a plan. The plan was good. Let me tell you about the four hours in the middle.
The brand new appliance did not finish booting
I unboxed it, plugged in PORT1 to my switch and PORT2 to my laptop, powered it on, and waited. The status LED did its blue flashing thing, which the documentation says means "OS boot in progress." Then it stopped flashing.
My laptop got a self assigned 169.254.x.x address. Nothing was serving DHCP. I could not reach the web interface. The old firewall saw no sign of the new box on the network at all, not a single frame.
Both ethernet ports had link lights. This turned out to be the most misleading fact of the entire day.
Ethernet link lights come from the PHY, which powers up with the hardware and negotiates link whether or not the operating system has booted. A completely wedged box with a dead OS will still light up both ports and negotiate gigabit. I confirmed this later by accident: with the appliance fully shut down into standby, my laptop still reported status: active, 1000baseT <full-duplex> on that cable. Link lights tell you the hardware has power. They tell you nothing else. I will never trust them again.
The test that actually isolated the problem
I spent too long chasing whether the cable was bad, whether the switch port was dead, whether I had the wrong port. All of it was guesswork.
Here is the test that ended the guessing, and I recommend it any time you are stuck between "the network path is broken" and "the service is broken":
# Same source address, same destination, different ports
nc -z -v -s 192.168.1.100 192.168.1.1 53 # Connection succeeded
nc -z -v -s 192.168.1.100 192.168.1.1 443 # Operation timed out
nc -z -v -s 192.168.1.100 192.168.1.1 80 # Operation timed out
A full TCP handshake completed on port 53. A real DNS query came back in 0 msec. So the cable was fine, the switch was fine, the host was alive, and TCP worked. Ports 80 and 443 specifically had nothing listening.
That one paired result replaced about ninety minutes of theorizing. When you cannot tell whether the path or the service is broken, find a port on the same host that does work. If anything answers, the path is proven and you can stop looking at cables.
The diagnosis: the box had booted, Kea DHCP was running, unbound DNS was running, and the web server had simply never started. On a factory fresh appliance, out of the box.
The fix was embarrassingly boring
A power cycle. Short press the power button, wait for the LED to go to pulsing orange, press it again. Ten minutes later the web interface answered.
I checked afterward whether slow certificate generation was to blame, since that can hold up the web server on a low power CPU. It was not. The GUI certificate had been issued at the factory weeks earlier. That first boot was just genuinely stuck.
I do not have a satisfying explanation, and I am suspicious of write ups that manufacture one. Sometimes brand new hardware needs to be turned off and on again, and the honest lesson is that a factory fresh appliance failing its first boot is a thing that can happen to you too.
macOS will lie to you about DHCP
This bit me three separate times, so it is worth its own warning.
When the DHCP server appears after macOS has already given up and self assigned a 169.254.x.x address, macOS does not promptly try again. It sits there, contentedly wrong, for a long time. The box being fixed does not reach back and poke your laptop.
Reseating the USB-C end of my ethernet adapter fixed it every time. sudo ipconfig set en7 DHCP does the same thing without the physical fiddling.
The nastier version of this problem: while your interface is on 169.254.x.x, it has no route to the subnet you are trying to reach. So every ping, curl and port check you run silently falls through to your default route and goes out over WiFi instead. I did exactly this and briefly concluded the new firewall was unreachable when in fact I had never sent it a single packet. If you take one thing from this post, make it this: verify which interface your test actually used before you believe its result.
route -n get 192.168.1.1 # says which interface will be used
arp -an | grep 192.168.1.1 # says which MAC answered, and on which interface
ping -b en7 192.168.1.1 # forces the test onto a specific interface
I restored the wrong file, and the symptom told me exactly which one
This is my favourite failure of the day, because the evidence was so clean.
After the restore, I could not get an address on PORT2 where LAN was supposed to be. I moved the cable to PORT1, nothing. Moved it to PORT3, and immediately got a proper lease with the right gateway and the right DNS server.
I logged in and looked at the interface assignments:
WAN → igc0
LAN → igc1
Those are my old box's values. Which meant I had uploaded the original backup instead of the remapped one. The two files were sitting next to each other in the same directory with identical timestamps, and I grabbed the wrong one in the file dialog.
And it explains the symptom perfectly. LAN = igc1 = PORT3, which is exactly the port that gave me a lease. The mistake announced itself.
The fix did not need another restore. Interface assignments are two dropdowns in the web interface:
- Change WAN from
igc0toigc3, save. Nothing breaks, since WAN has no cable in it. - Change LAN from
igc1toigc2, save. Your connection dies immediately, which is success rather than failure. The change applies server side; the reply just cannot reach you because LAN is no longer on the port you are plugged into. - Move your cable to PORT2 and reconnect.
Do those as two separate saves rather than one. There is no reason to lose connectivity before you have to.
The Cutover
By this point the new box was sitting on my bench with the full config, correct interface assignments, and no WAN cable. My house was still happily running on the old flaky box, which had the decency not to switch itself off during any of this.
The one thing I got right without being told: I had to physically move the appliance into the rack, which meant powering it down and unplugging it. My first instinct was to shut down, move it, cable everything up, and power on. That would have meant sitting through a ten minute boot with my whole house offline, hoping it came up correctly this time.
Instead:
- Clean shutdown, move it into the rack, reconnect power, leave both network ports disconnected
- Let it fully boot and confirm the web interface answered, with my laptop on PORT2
- Only then power off the old firewall
- Move the WAN cable to PORT1 and the LAN cable to PORT2
- Power cycle the modem
The slow, uncertain part happened while I was still safely online. Actual downtime was the cable swap plus waiting for a DHCP lease from my ISP. A couple of minutes.
Power cycle the modem. Your WAN MAC address just changed, and many ISPs bind the lease to it. Mine handed out an address after a modem restart with no further persuasion. If yours does not, pfSense lets you spoof the old MAC under Interfaces then WAN, which is why you should write the old one down before you unplug the box you can no longer read it from.
Did It Work
My public IP changed during the cutover, from one address to a completely different one. This is exactly why I had recorded the old one before starting. Without that baseline I would have spent an hour wondering whether a changed public IP was a symptom of something I had broken.
The Cloudflare dynamic DNS client picked it up on its own and updated my VPN hostname within a few minutes. There were some alarming errors in the log during the cutover window:
ERROR [phpDynDNS] (vpn.example.com) Could not determine the request IP address
(using "wan", "igc3"): gateway not online
Those were transient. The WAN gateway simply had not come up yet. Once it did, the update went through. Worth knowing so you do not panic at your logs the way I briefly did.
Everything else came across intact:
| Check | Result |
|---|---|
| WAN and LAN | Both negotiated 2500Base-T, correct addresses |
| DNS | Every internal hostname resolving, recursion working |
| DHCP | All 36 reservations honoured |
| NAT | WireGuard forward rebound to the new public IP automatically |
| Kubernetes | All three nodes reachable through the API VIP |
| Internal services | Every one of them answering |
| WireGuard from cellular | Working |
That last one is the test worth doing deliberately. Connecting over WireGuard from your phone on mobile data exercises the NAT port forward and the dynamic DNS update at the same time, and it is the only check you cannot fake from inside your own network. If your DDNS had silently failed, that is where you would find out, ideally before you are in an airport rather than after.
One false alarm worth mentioning, because it nearly sent me chasing nothing: my first sweep reported Home Assistant unreachable. Home Assistant listens on 8123, not 443. I had probed the wrong port. Through the load balancer it returned a perfectly healthy 200. Check what port a service actually listens on before you declare it broken.
What I'd Tell You
Learn the config revision rule. Older config onto newer release works and gets upgraded. Newer onto older is rejected. Update the appliance first and you are always going the safe direction.
Restore last, cut over immediately after. The moment that config lands, the new box thinks it owns your network. Do not let it touch the live wire until the old one is off.
Bench the new box behind the old one. If your subnets do not overlap, this costs nothing and buys unlimited time. It is the best reason to migrate onto a second box rather than reinstall your only one.
Ethernet link lights mean nothing. They tell you the hardware has power. Not that the OS booted, not that anything is listening.
Find a port that works before you blame the cable. One successful connection on any port proves the entire path and saves you from an hour of cable swapping.
Check which interface your test used. A self assigned address means no route, which means your test silently went out a different interface and lied to you.
Write down the old WAN MAC before you unplug anything. You cannot read it off a box you have already disconnected, and you may need it if your ISP is fussy.
Keep the old box as a cold spare. Mine is sitting powered off with its config intact. Rollback is two cables and a button. That safety net is why the cutover was relaxed instead of terrifying.
Resist installing packages. My migration was two lines of sed because there was nothing else to carry.
The part I keep coming back to is that almost nothing that went wrong was the thing I had prepared for. I had researched the port mapping trap carefully and it never bit me, precisely because I had researched it. What actually cost me the afternoon was a brand new appliance failing its first boot, an operating system that would not re-request DHCP, and me grabbing the wrong file out of a folder.
Which is roughly how all of these go. The known risks get handled because they are known. The time disappears into the things nobody thought to write down.
So I wrote them down.
Featured Image Prompt
I used this prompt to generate the featured image.
A rack mounted white security gateway appliance seated cleanly in a home server rack, four ethernet ports with two blue cables plugged into the leftmost ports, small blue status LEDs glowing. Beside it on the shelf sits a small unbranded generic mini PC, powered off, cables coiled, clearly retired. Shallow depth of field, moody low key homelab lighting, teal and amber color grade, photographic realism, no text, no logos, no visible branding.