Port Forwarding in macOS: Equivalent to Linux iptables DNAT Rule for 192.168.99.100:80 to 127.0.0.1:8000


3 views

When working with local development servers, we often need to forward traffic from one IP/port combination to another. On Linux systems, this is commonly achieved using iptables NAT rules. The equivalent functionality in macOS requires a different approach due to differences in the underlying networking stack.

Apple has transitioned from ipfw to pf (Packet Filter) as the primary firewall and NAT solution. Here's how to achieve the desired port forwarding:

# Create or edit /etc/pf.conf
echo '
rdr pass on lo0 inet proto tcp from any to 192.168.99.100 port 80 -> 127.0.0.1 port 8000
' | sudo tee -a /etc/pf.conf

# Enable and load the rules
sudo pfctl -e
sudo pfctl -f /etc/pf.conf

To verify the rules are active:

sudo pfctl -s nat

Common issues to check:

  • Ensure the lo0 interface exists (ifconfig lo0)
  • Check for syntax errors (sudo pfctl -vnf /etc/pf.conf)
  • Verify the target service is running (netstat -an | grep 8000)

For developers who prefer user-space solutions:

Using socat

brew install socat
socat TCP4-LISTEN:80,fork,reuseaddr,bind=192.168.99.100 TCP4:127.0.0.1:8000

Using nginx as reverse proxy

brew install nginx
# Add to /usr/local/etc/nginx/nginx.conf
server {
    listen 192.168.99.100:80;
    server_name _;
    location / {
        proxy_pass http://127.0.0.1:8000;
    }
}

To make the pf solution persistent across reboots:

sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.pfctl.plist

When working with local development environments, we often need to forward traffic from one IP/port to another. On Linux, this is straightforward with iptables, but macOS requires different tools.

macOS provides two main firewall/forwarding mechanisms:


1. PF (Packet Filter) - The newer, recommended system (since macOS 10.10)
2. IPFW - The legacy system (deprecated but still available)

Create or edit /etc/pf.conf:


# Enable packet forwarding
sysctl -w net.inet.ip.forwarding=1

# Add these rules to pf.conf
rdr pass on lo0 inet proto tcp from any to 192.168.99.100 port 80 -> 127.0.0.1 port 8000
pass in quick proto tcp from any to 127.0.0.1 port 8000

Then load the rules:


sudo pfctl -ef /etc/pf.conf

For older macOS versions, IPFW can work but has limitations:


sudo ipfw add fwd 127.0.0.1,8000 tcp from any to 192.168.99.100 80

Check if the rules are active:


# For PF
sudo pfctl -s nat

# For IPFW
sudo ipfw show

Test with curl:


curl -I http://192.168.99.100
  • Ensure your dev server is running on 127.0.0.1:8000
  • Check macOS firewall isn't blocking the traffic
  • Verify the interface name (lo0 vs en0 etc.)

For persistent rules across reboots, add the PF configuration to /etc/pf.conf and create a launch daemon or use anchors for more complex setups.