Port forwarding is what lets a device inside your home or office network accept connections from the outside world. Your router gets one public IP; behind it sit dozens of private devices. A forwarded port is a rule that says "when traffic arrives on TCP port 25565, send it to 192.168.1.42 on the same port."
Why you might need it
- Hosting a Minecraft / game server.
- Running a self-hosted Nextcloud, Home Assistant, or media server reachable away from home.
- Self-hosted VPN (WireGuard, OpenVPN) so you can VPN back into your home network.
- Receiving incoming SIP calls or Tailscale-relay-free Mesh links.
- Hosting any service that needs inbound connections rather than just outbound.
How the rule works
Your router maintains a NAT table. For each outbound flow it remembers "192.168.1.42:54321 ↔ <public IP>:31234"; when the response comes back, it knows where to send it. Port forwarding adds a static entry: any new inbound connection to a specific public port lands on a specific private IP+port.
Most consumer routers expose this as "Port Forwarding," "Virtual Server," "Application Filter," or (badly) "DMZ." The standardised auto-config protocol is UPnP IGD, which an app can call to request a forward without you touching the router UI. Apple's PCP (Port Control Protocol, RFC 6887) is the successor — better security model, less broken.
Why your port forward silently fails
Three things commonly break a forward:
- You're behind CGNAT. The ISP is doing a second layer of NAT above your router. The forward stops at your router; the ISP's NAT layer has no idea anybody wanted to reach you. This is the #1 cause on mobile carriers and cheap FTTH plans.
- Your router doesn't actually have a public IP. Compare what your router shows on its WAN page to what IPFerret shows. If they're different, something is NAT'ing you upstream.
- The target device's local firewall. A correctly-forwarded port lands at the device but is rejected by Windows Defender / ufw / Little Snitch. Easy to miss because the router shows "rule active" and the failure is one layer deeper.
Quick checks:
- From outside your network (use cellular or a remote machine), try the port.
- Tools like canyouseeme.org probe a specific port on your public IP from outside.
- From inside, run
curl -v telnet://<your-public-ip>:<port>— but be aware "NAT hairpinning" affects whether this works.
Modern alternatives
Port forwarding belongs to a 1990s mental model where every device wanted its own public IP. The modern moves are mostly about not needing inbound:
- Reverse tunnels. Your device dials out to a public-facing relay (Cloudflare Tunnel, Tailscale Funnel, ngrok, your own VPS with SSH-R). The relay holds the connection open and forwards inbound traffic back down it. Works behind any NAT, including CGNAT. This is how most modern "make my home thing reachable" workflows ship.
- IPv6 end-to-end. If both endpoints have native IPv6, every device on your home network has a globally-routable address — no NAT, no port forwarding, just firewall rules. Test your IPv6 here.
- Hole punching. WebRTC, Tailscale, BitTorrent, and modern game engines use STUN servers to discover each side's NAT mapping, then synchronise outbound packets so the NAT mappings line up. Works for peer-to-peer, doesn't help "I want random-internet-strangers to reach my web server."
When you genuinely need a forward
If reverse tunnels feel like cheating and you actually want a real open port:
- Confirm you have a real public IP (not CGNAT). Your router's WAN status page is the source of truth, not what some web tool says.
- Decide whether the target device should have a static private IP or a DHCP reservation. DHCP reservation is usually less hassle.
- Open the router's "Port Forwarding" / "Virtual Server" panel and add: external port, internal IP, internal port, protocol (TCP, UDP, or both).
- Open the matching port in the device's local firewall (
ufw allow 25565/tcp, Windows Defender Firewall, etc). - Test from outside the LAN.
If at any point a check fails, the troubleshooting order is: ISP CGNAT? → router rule present? → device firewall open? → service actually listening? Once you've ruled out CGNAT the rest is local debugging.
