Your iptables rules look correct at a glance, but there are a few common culprits that can break connectivity. Let’s step through the whole setup systematically.
Diagnosing the Issue
First, verify that IP forwarding is actually enabled. Run sysctl net.ipv4.ip_forward – it should return 1. If not, make sure you’ve edited /etc/sysctl.conf to set net.ipv4.ip_forward=1 permanently and rebooted or applied with sysctl -p.
Next, check your FORWARD chain default policy. By default, iptables often has a policy of DROP for the FORWARD chain. Even though you added ACCEPT rules, if the default is DROP, packets hitting the chain before your rules might still be dropped. Change the default policy to ACCEPT temporarily for testing: sudo iptables -P FORWARD ACCEPT. If that works, you can refine later.
Also, ensure that the WAN interface (enp0s3) has internet access. From the Ubuntu router itself, can you ping 8.8.8.8? If not, the issue is upstream.
dnsmasq Configuration
dnsmasq is often the source of DHCP problems. A minimal working configuration for your LAN interface would look like this:
interface=enp0s8
bind-interfaces
dhcp-range=192.168.1.50,192.168.1.150,12h
dhcp-option=3,192.168.1.1
dhcp-option=6,192.168.1.1
This tells dnsmasq to listen on the LAN interface, hand out IPs in that range, and advertise the router’s LAN IP as both gateway and DNS. Restart dnsmasq after saving.
Persistence
Your iptables rules will vanish on reboot. To make them permanent, you can install iptables-persistent or save the rules manually:
sudo netfilter-persistent save
Modern Alternatives
While a manual iptables setup is educational, you might consider these modern approaches:
- nftables: The successor to iptables, with simpler syntax and better performance. On Ubuntu 20.04+, nftables is the default. A basic NAT ruleset:
table ip nat {
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
oifname "enp0s3" masquerade
}
}
table ip filter {
chain forward {
type filter hook forward priority filter; policy drop;
iifname "enp0s8" oifname "enp0s3" accept
iifname "enp0s3" oifname "enp0s8" ct state related,established accept
}
}
- systemd-networkd: Can handle bridging and routing with simple config files, reducing the need for iptables altogether.
- Dedicated firewall distros: For production home networks, consider OPNsense or pfSense – they package firewall, DHCP, DNS, and VPN into a web interface.
Why Clients Fail to Reach the Internet
If dnsmasq hands out IPs but clients can’t ping external IPs, the issue is likely one of these:
- FORWARD chain default DROP – as mentioned.
- WAN interface not getting default route – check
ip route show on the Ubuntu router. Should have a default via your ISP’s gateway.
- Client gateway not set to 192.168.1.1 – verify on the client with
ipconfig (Windows) or ip route.
- ISP modem doing double NAT – if your modem is already a router, the Ubuntu machine is behind it, and you need to either put the modem in bridge mode or use a different subnet.
Final Thoughts
Setting up a Linux router is a fantastic way to learn networking deeply. Once you get past the initial hurdles, you’ll appreciate the control and flexibility. For a home network, you might also look into ad-blocking via Pi-hole running on the same machine, or VPN server for remote access. But get the basics stable first.
Test step by step: confirm WAN connectivity on the router, then check client can ping the router’s LAN IP, then ping 8.8.8.8, then check DNS resolution. That’ll pinpoint exactly where the chain breaks.