Network 📖 30 min read

Linux Router Setup

Consumer routers are garbage. The firmware is years out of date, the "firewall" is a joke, and the manufacturer stopped pushing updates 6 months after launch. Building a router from a Linux box takes an afternoon and you'll never go back to a Netgear. I did it with a $60 Dell OptiPlex and a $12 PCIe NIC, and it handles my full 500Mbps connection without breaking a sweat.

What a Linux router gives you that a consumer router doesn't:

  • Real firewall rules — not a checkbox that says "enable firewall" and does nothing meaningful behind it
  • Actual logging — you can see every connection, every blocked packet, every DNS query. Consumer routers give you a page of DHCP leases and call it a day
  • Updates forever — as long as your distro gets kernel patches, your router gets security updates. No waiting for TP-Link to care about your three-year-old hardware
  • No phone-home telemetry — your Netgear is sending analytics back to the manufacturer. Your Linux box sends nothing unless you tell it to
  • VLANs without buying a $300 "gaming router" — any Linux box with an Intel NIC handles 802.1Q tagging out of the box

What I replaced:

A TP-Link Archer C7 that hadn't received a firmware update since 2021. The admin panel took 15 seconds to load a page. The "parental controls" were a DNS blocklist that hadn't been updated in two years. It would drop Wi-Fi connections under any real load and needed a power cycle every couple of weeks. After switching to the Linux box, my DNS resolution got faster because I'm running a local caching resolver, I stopped seeing random devices on my network phoning home to Chinese IP addresses, and the uptime counter is currently at 11 months. The only downtime was when I accidentally applied a firewall rule that blocked my own SSH session.

The hard part first

Getting IP forwarding and NAT right is where most people get stuck. If you enable net.ipv4.ip_forward=1 but forget the masquerade rule in iptables/nftables, your clients will get IP addresses but nothing will route to the internet. I stared at tcpdump output for 45 minutes before I caught that one. Consumer routers hide this from you, which is fine until something breaks and you have zero visibility into what's happening.

Requirements

  • Two NICs minimum — one for WAN, one for LAN. Intel NICs are the most reliable. Avoid Realtek if you can; the drivers are flaky under load
  • IP forwarding and masquerade NAT enabled — without both, nothing routes
  • systemd-networkd or Netplan for interface config — NetworkManager is overkill for a headless router

Network Interface Setup

Identify your interfaces:

ip link show

Typical setup:

  • eth0 - WAN (connects to ISP modem)
  • eth1 - LAN (connects to switch/devices)

Configure Interfaces

Edit /etc/netplan/01-netcfg.yaml:

network:
 version: 2
 ethernets:
 eth0:
 dhcp4: true # WAN gets IP from ISP
 eth1:
 addresses:
 - 192.168.1.1/24 # LAN gateway

Apply:

sudo netplan apply

Enable IP Forwarding

echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

This allows packets to flow between interfaces.

NAT with iptables

NAT translates internal IPs to your public IP. This is the part that consumer routers do automatically but won't let you customize. Three rules and you're done:

# Enable masquerading on WAN interface
sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

# Allow established connections back in
sudo iptables -A FORWARD -i eth0 -o eth1 -m state --state RELATED,ESTABLISHED -j ACCEPT

# Allow outbound from LAN
sudo iptables -A FORWARD -i eth1 -o eth0 -j ACCEPT

Make persistent:

sudo apt install iptables-persistent
sudo netfilter-persistent save

DHCP Server with dnsmasq

Most consumer routers intercept DNS queries and redirect them to the ISP's servers regardless of what you configure. You can set 1.1.1.1 in the DHCP settings all day long — the router silently rewrites the destination. With dnsmasq, DNS goes exactly where you tell it to go.

dnsmasq handles both DHCP and DNS in one package:

sudo apt install dnsmasq

Edit /etc/dnsmasq.conf:

# Listen on LAN interface
interface=eth1

# DHCP range
dhcp-range=192.168.1.100,192.168.1.200,24h

# Gateway
dhcp-option=option:router,192.168.1.1

# DNS servers to use
server=1.1.1.1
server=8.8.8.8

# Local domain
domain=home.lan

# Don't read /etc/resolv.conf
no-resolv

Restart:

sudo systemctl restart dnsmasq
sudo systemctl enable dnsmasq

Actual Firewall Rules

# Default policies
sudo iptables -P INPUT DROP
sudo iptables -P FORWARD DROP
sudo iptables -P OUTPUT ACCEPT

# Allow loopback
sudo iptables -A INPUT -i lo -j ACCEPT

# Allow established connections
sudo iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT

# Allow SSH from LAN only
sudo iptables -A INPUT -i eth1 -p tcp --dport 22 -j ACCEPT

# Allow DHCP/DNS from LAN
sudo iptables -A INPUT -i eth1 -p udp --dport 67 -j ACCEPT
sudo iptables -A INPUT -i eth1 -p udp --dport 53 -j ACCEPT
sudo iptables -A INPUT -i eth1 -p tcp --dport 53 -j ACCEPT

# Save rules
sudo netfilter-persistent save

Port Forwarding

On a consumer router, this is buried three menus deep and half the time it doesn't work because of some UPnP conflict. Here it's two lines:

# Forward port 8080 to internal server
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 8080 -j DNAT --to-destination 192.168.1.150:80
sudo iptables -A FORWARD -p tcp -d 192.168.1.150 --dport 80 -j ACCEPT

Traffic Shaping (Optional)

Consumer routers market "QoS" as a feature and then give you a slider that does almost nothing. Linux gives you tc and CAKE, which actually solve bufferbloat:

# Limit download to 100mbit
sudo tc qdisc add dev eth0 root tbf rate 100mbit burst 32kbit latency 400ms

# More sophisticated: use cake for anti-bufferbloat
sudo tc qdisc replace dev eth0 root cake bandwidth 100mbit

Wireless Access Point (Optional)

If your Linux box has a WiFi card that supports AP mode, you can run hostapd and ditch the consumer router entirely. Honestly though, I just use my old TP-Link as a dumb access point in bridge mode. It's the one thing consumer hardware does fine.

sudo apt install hostapd

Edit /etc/hostapd/hostapd.conf:

interface=wlan0
driver=nl80211
ssid=MyNetwork
hw_mode=g
channel=7
wpa=2
wpa_passphrase=YourSecurePassword
wpa_key_mgmt=WPA-PSK
rsn_pairwise=CCMP

Enable:

sudo systemctl unmask hostapd
sudo systemctl enable hostapd
sudo systemctl start hostapd

Bridge wlan0 with eth1 or add to dnsmasq for separate subnet.

Monitoring

# Real-time traffic
sudo apt install iftop
sudo iftop -i eth0

# Connection tracking
cat /proc/net/nf_conntrack | head

# DHCP leases
cat /var/lib/misc/dnsmasq.leases

Performance Tuning

# Increase connection tracking limits
echo "net.netfilter.nf_conntrack_max=131072" | sudo tee -a /etc/sysctl.conf

# Increase local port range
echo "net.ipv4.ip_local_port_range=1024 65535" | sudo tee -a /etc/sysctl.conf

# Apply
sudo sysctl -p

What about OPNsense or pfSense?

Fair question. OPNsense and pfSense are solid if you want a web GUI and don't mind running FreeBSD under the hood. I went with raw Linux because I wanted to run Pi-hole, a WireGuard server, and traffic monitoring on the same box without dealing with FreeBSD's package ecosystem. If you already know Linux, there's no reason to learn a second operating system just for routing.

The one thing I'd do differently: use nftables instead of iptables. The syntax is cleaner and it's where the kernel team is putting their effort. iptables still works fine, but nftables is the future.

Set this up on a weekend. Use your old consumer router as a dumb access point. Give it a month. You won't switch back.

💬 Comments