This is an updated version of my 2006 post on 1:1 NAT with DD-WRT. DD-WRT v24 RC-6.2 has changed a few things, and I have also refined the approach after running this setup for over a year. The key improvement here is combining static 1:1 NAT for servers with dynamic NAPT for everything else, with proper firewall rules on both.
What changed in v24
DD-WRT v24 introduced a new firewall framework. The default rules are more restrictive, which is good, but it means your custom iptables rules need to play nicely with the existing chains. The WAN interface name has also changed on some builds - on my WRT54GL running v24 RC-6.2, it is vlan1 but I have seen eth0 and ppp0 on PPPoE connections.
Check yours first:
# nvram get wan_ifname
vlan1
The scenario
Same as before: ISP provides 82.x.x.0/29. The WRT54GL's WAN has 82.x.x.1. I want:
- 82.x.x.2 mapped 1:1 to 192.168.1.10 (web server)
- 82.x.x.3 mapped 1:1 to 192.168.1.20 (mail server)
- All other LAN hosts (192.168.1.0/24) use dynamic NAPT through 82.x.x.1
Startup script
In Administration - Commands, save this as the Startup script. It adds the extra public IPs to the WAN interface:
#!/bin/sh
WAN=$(nvram get wan_ifname)
ifconfig $WAN:1 82.x.x.2 netmask 255.255.255.248
ifconfig $WAN:2 82.x.x.3 netmask 255.255.255.248
logger "1:1 NAT aliases configured on $WAN"
Using nvram get wan_ifname instead of hardcoding the interface name means this survives firmware upgrades where the interface might change.
Firewall script
Save this as the Firewall script. This runs after DD-WRT's own firewall rules are loaded:
#!/bin/sh
WAN=$(nvram get wan_ifname)
# --- 1:1 NAT: Web server (82.x.x.2 <-> 192.168.1.10) ---
# Inbound DNAT
iptables -t nat -I PREROUTING -i $WAN -d 82.x.x.2 \
-j DNAT --to-destination 192.168.1.10
# Outbound SNAT
iptables -t nat -I POSTROUTING -o $WAN -s 192.168.1.10 \
-j SNAT --to-source 82.x.x.2
# Forward rules (restricted to specific ports)
iptables -I FORWARD -i $WAN -d 192.168.1.10 -p tcp \
-m multiport --dports 80,443 -j ACCEPT
iptables -I FORWARD -i $WAN -d 192.168.1.10 -p icmp -j ACCEPT
# --- 1:1 NAT: Mail server (82.x.x.3 <-> 192.168.1.20) ---
iptables -t nat -I PREROUTING -i $WAN -d 82.x.x.3 \
-j DNAT --to-destination 192.168.1.20
iptables -t nat -I POSTROUTING -o $WAN -s 192.168.1.20 \
-j SNAT --to-source 82.x.x.3
iptables -I FORWARD -i $WAN -d 192.168.1.20 -p tcp \
-m multiport --dports 25,143,993,587 -j ACCEPT
iptables -I FORWARD -i $WAN -d 192.168.1.20 -p icmp -j ACCEPT
# --- Allow established/related for 1:1 hosts ---
iptables -I FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
# --- Dynamic NAPT for everything else ---
# DD-WRT already has a MASQUERADE rule but it only covers the primary IP.
# This ensures it works for all LAN traffic not caught by SNAT above.
iptables -t nat -A POSTROUTING -o $WAN -s 192.168.1.0/24 \
-j MASQUERADE
logger "1:1 NAT firewall rules loaded"
Key difference from the 2006 version
I am using -I (insert) instead of -A (append) for the PREROUTING and FORWARD rules. This is important with v24 because DD-WRT's default rules include a catch-all DROP at the end of the FORWARD chain. If you append your rules, they end up after the DROP and never get hit. Inserting puts them at the top of the chain.
You can verify the rule order:
# iptables -L FORWARD -n --line-numbers | head -10
Chain FORWARD (policy ACCEPT)
num target prot opt source destination
1 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state ESTABLISHED,RELATED
2 ACCEPT icmp -- 0.0.0.0/0 192.168.1.20
3 ACCEPT tcp -- 0.0.0.0/0 192.168.1.20 multiport dports 25,143,993,587
4 ACCEPT icmp -- 0.0.0.0/0 192.168.1.10
5 ACCEPT tcp -- 0.0.0.0/0 192.168.1.10 multiport dports 80,443
Troubleshooting
Outbound traffic from 1:1 hosts uses the wrong IP. Check that your SNAT rules appear before the MASQUERADE rule in the POSTROUTING chain. Use iptables -t nat -L POSTROUTING -n --line-numbers to verify. The SNAT rules should be first.
Inbound traffic is not reaching the internal host. Make sure the FORWARD rules allow traffic to the host. Enable logging temporarily to see what is being dropped:
iptables -I FORWARD -d 192.168.1.10 -j LOG --log-prefix "FWD_WEB: "
Check logread on the router or /var/log/messages for the tagged entries.
Cannot reach the 1:1 IP from inside the LAN. This is a hairpin NAT problem. You need an additional rule:
iptables -t nat -I POSTROUTING -s 192.168.1.0/24 -d 192.168.1.10 \
-j SNAT --to-source 192.168.1.1
This rewrites the source address for LAN-to-LAN traffic so the reply comes back through the router instead of going direct (which would confuse the connection tracking).
Resource usage
This adds minimal overhead. The WRT54GL has 16MB RAM and the connection tracking table handles it easily for home use. Check your conntrack usage:
# cat /proc/sys/net/ipv4/netfilter/ip_conntrack_count
847
# cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max
4096
If you are running P2P software behind this, you may need to increase ip_conntrack_max but for normal server traffic 4096 is plenty.