{
  "slug": "How-to-Port-Forward-Traffic-to-a-Remote-IP-Using-Iptables-c3a8c10a6228",
  "title": "How to Port Forward Traffic to a Remote IP Using Iptables",
  "subtitle": "In the world of networking, you often find yourself in a situation where a vital service — like a Swagger API dashboard — is hosted on a…",
  "excerpt": "In the world of networking, you often find yourself in a situation where a vital service — like a Swagger API dashboard — is hosted on a…",
  "date": "2026-02-02",
  "tags": [
    "API"
  ],
  "readingTime": "3 min",
  "url": "https://medium.com/@mobinshaterian/how-to-port-forward-traffic-to-a-remote-ip-using-iptables-c3a8c10a6228",
  "hero": "https://cdn-images-1.medium.com/max/800/1*O1YF6Ylsgt2Fv9W3x-AOWg.png",
  "content": [
    {
      "type": "heading",
      "level": 2,
      "text": "How to Port Forward Traffic to a Remote IP Using Iptables"
    },
    {
      "type": "paragraph",
      "html": "In the world of networking, you often find yourself in a situation where a vital service — like a Swagger API dashboard — is hosted on a server that isn’t directly reachable by everyone on your team. Whether due to subnet isolation, VPN restrictions, or firewall policies, these “network silos” can stall development and testing."
    },
    {
      "type": "paragraph",
      "html": "This article provides a step-by-step technical walkthrough on how to use <strong>iptables</strong> to turn a standard Linux machine into a transparent bridge. By leveraging Destination NAT (DNAT) and Source NAT (SNAT), you can map a local port on your gateway machine to a remote service, effectively “proxying” the connection at the kernel level for maximum performance and reliability."
    },
    {
      "type": "image",
      "src": "https://cdn-images-1.medium.com/max/800/1*O1YF6Ylsgt2Fv9W3x-AOWg.png",
      "alt": "How to Port Forward Traffic to a Remote IP Using Iptables",
      "caption": "",
      "width": 1024,
      "height": 1024
    },
    {
      "type": "heading",
      "level": 2,
      "text": "The Scenario"
    },
    {
      "type": "list",
      "ordered": false,
      "items": [
        "<strong>Target Service:</strong> <code>ip_target:4000</code> (The \"hidden\" service you can access) like 10.100.100.10:400",
        "<strong>Gateway IP:</strong> <code>ip_gateway</code> (Your machine's IP on the network).",
        "<strong>Shared Port:</strong> <code>9099</code> (The port users will use to reach the service)."
      ]
    },
    {
      "type": "heading",
      "level": 2,
      "text": "Step 1: Enable Kernel-Level Forwarding"
    },
    {
      "type": "paragraph",
      "html": "By default, most Linux distributions disable the ability to pass traffic between different network interfaces for security reasons. You must tell the kernel to behave like a router."
    },
    {
      "type": "paragraph",
      "html": "<strong>Check status:</strong> <code>cat /proc/sys/net/ipv4/ip_forward</code>"
    },
    {
      "type": "paragraph",
      "html": "<strong>Enable it:</strong>"
    },
    {
      "type": "code",
      "lang": "bash",
      "code": "sudo sysctl -w net.ipv4.ip_forward=1"
    },
    {
      "type": "quote",
      "html": "Note: To make this permanent after a reboot, edit <code>/etc/sysctl.conf</code> and uncomment the line <code>net.ipv4.ip_forward=1</code>."
    },
    {
      "type": "heading",
      "level": 2,
      "text": "Step 2: Destination NAT (PREROUTING)"
    },
    {
      "type": "paragraph",
      "html": "The <code>PREROUTING</code> chain in the <strong>NAT table</strong> handles packets as they first hit your network card. Here, we change the \"envelope\" of the packet: we swap your IP address for the target service's IP address."
    },
    {
      "type": "code",
      "lang": "bash",
      "code": "sudo iptables -t nat -A PREROUTING -p tcp --dport 9099 -j DNAT --to-destination ip_target:4000"
    },
    {
      "type": "paragraph",
      "html": "<strong>What this does:</strong> Any TCP traffic hitting your machine on port <code>9099</code> is immediately redirected to ip_target on port <code>4000</code>."
    },
    {
      "type": "heading",
      "level": 2,
      "text": "Step 3: Open the Firewall (FORWARD)"
    },
    {
      "type": "paragraph",
      "html": "Even if the packet is redirected, the Linux firewall (Filter table) will drop it by default if your policy is set to <code>DROP</code>. You must explicitly grant permission for these packets to cross through your system."
    },
    {
      "type": "code",
      "lang": "bash",
      "code": "# 1. Allow established connections back in\nsudo iptables -I FORWARD 1 -m state --state\nRELATED,ESTABLISHED -j ACCEPT"
    },
    {
      "type": "code",
      "lang": "bash",
      "code": "# 2. Allow new requests to the target destination\nsudo iptables -I FORWARD 2 -p tcp -d ip_gateway\n--dport 4000 -j ACCEPT"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "Step 4: Source NAT (POSTROUTING)"
    },
    {
      "type": "paragraph",
      "html": "This is the most critical and often forgotten step. When the target service (ip_target) receives a packet, it needs to know where to send the reply."
    },
    {
      "type": "paragraph",
      "html": "If we don’t use <strong>MASQUERADE</strong>, the service will try to reply directly to the original user’s IP. Since the user never asked ip_target for anything (they asked <em>you</em>), their computer will reject the reply."
    },
    {
      "type": "code",
      "lang": "bash",
      "code": "sudo iptables -t nat -A POSTROUTING -p tcp -d ip_target --dport 4000 -j MASQUERADE"
    },
    {
      "type": "paragraph",
      "html": "<strong>What this does:</strong> It “masks” the original user’s IP with your own gateway IP. The target service replies to you, and you safely pass that reply back to the user."
    },
    {
      "type": "heading",
      "level": 2,
      "text": "Step 5: Verification and Testing"
    },
    {
      "type": "paragraph",
      "html": "To verify the rules are active, list the NAT table with line numbers and packet counters:"
    },
    {
      "type": "code",
      "lang": "bash",
      "code": "sudo iptables -t nat -L -n -v --line-numbers"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "How to Test"
    },
    {
      "type": "list",
      "ordered": false,
      "items": [
        "<strong>Remote Test:</strong> From another machine on the network, try to reach the URL: <a href=\"http://ip_gateway:9099/swagger/index.html\" target=\"_blank\" rel=\"noreferrer noopener\">http://ip_gateway:9099/swagger/index.html</a>",
        "<strong>Monitor Counters:</strong> While testing, run <code>sudo iptables -t nat -L -n -v</code>. If the <code>pkts</code> (packets) column increases, your traffic is successfully hitting the rule."
      ]
    },
    {
      "type": "heading",
      "level": 2,
      "text": "Conclusion"
    },
    {
      "type": "paragraph",
      "html": "Mastering <strong>iptables</strong> for port forwarding is more than just running a single command; it is about understanding how packets flow through the Linux networking stack. By correctly configuring the <strong>PREROUTING</strong>, <strong>FORWARD</strong>, and <strong>POSTROUTING</strong> chains, you have successfully built a transparent bridge that bypasses network isolation without the overhead of a traditional proxy server."
    },
    {
      "type": "heading",
      "level": 2,
      "text": "Key Takeaways"
    },
    {
      "type": "list",
      "ordered": false,
      "items": [
        "<strong>The Trinity of NAT:</strong> Forwarding requires three distinct actions: translating the destination (DNAT), permitting the pass-through (FORWARD), and masking the source for the return trip (MASQUERADE).",
        "<strong>Kernel Awareness:</strong> No amount of iptables rules will work if the kernel’s <code>ip_forward</code> setting is disabled.",
        "<strong>Visibility is Power:</strong> Using the <code>-v</code> (verbose) flag to monitor packet counters is the most effective way to debug where a connection is being dropped."
      ]
    },
    {
      "type": "paragraph",
      "html": "With this setup, your gateway machine now provides a seamless entry point for your team, making the “hidden” Swagger UI at ip_target as accessible as any local resource. Just remember to save your rules using <code>iptables-persistent</code> to ensure your bridge survives the next system reboot."
    }
  ]
}
