Skip to main content

/docs/port-forwarding

Port forwarding for IICP nodes & adapters

For your node to receive tasks from the mesh, port 9484 must be reachable. For SDK clients to send tasks to your adapter, port 8080 must be reachable. This guide covers both.

The easy way:you don't need to touch your router. Current clients can try a paced Cloudflare Quick Tunnel automatically when direct reachability cannot be verified, while still preferring a real public endpoint when you have one. The full guide covers that plus manual port-forwarding (ports 9484 / 8080).

Why port forwarding is needed

Your home or office router assigns your computer a private IP address (like 192.168.1.42) that is only reachable inside your local network. The rest of the internet only sees your router's public IP.

When another IICP node wants to send your node a task, it connects to your public_endpoint URL. Without port forwarding, that connection hits your router and stops — the router doesn't know which device behind it should receive it.

Port forwarding tells the router: "connections on port 9484 go to this machine." The IICP node listens on that port and handles the task.

Port to forward: 9484 TCP. This is the default IICP node port. If you changed it via IICP_PORT (or --port), forward that port instead.

Find your router's admin page

The router admin page is usually at one of these addresses — try them in your browser:

Or find it from the terminal:

# macOS
route -n get default | grep gateway

# Linux
ip route | grep default

The "default gateway" address is your router. The brand is usually on a sticker on the bottom of the device.

Find your machine's local IP address

You need this to tell the router which device to forward to:

# macOS
ipconfig getifaddr en0      # Wi-Fi
ipconfig getifaddr en1      # Ethernet (try en0, en1, en2)

# Linux
hostname -I | awk '{print $1}'

It will be something like 192.168.1.42. Note this down — you'll enter it in the router.

Tip: Set a static local IP (DHCP reservation) in your router so the forwarding rule doesn't break when your IP changes after a reboot.

Router-specific instructions

AVM FRITZ!Box

  1. Open fritz.box in your browser and log in.
  2. Go to Internet → Permit Access → Port Sharing.
  3. Click Add Device for Sharing, select your machine.
  4. Click Add Sharing, set Protocol: TCP, Port: 9484 (external and internal).
  5. Save. The rule is active immediately.

TP-Link (Archer series)

  1. Log in at 192.168.1.1 (or tplinkrouter.net).
  2. Go to Advanced → NAT Forwarding → Virtual Servers.
  3. Click Add. Service Type: Custom. External Port: 9484. Internal IP: your machine's IP. Internal Port: 9484. Protocol: TCP.
  4. Save and reboot the router if prompted.

ASUS (RT series)

  1. Log in at 192.168.1.1 or router.asus.com.
  2. Go to WAN → Virtual Server / Port Forwarding.
  3. Click Add profile. Service Name: iicp-node. Protocol: TCP. External Port: 9484. Internal IP: your machine. Internal Port: 9484.
  4. Apply. Changes take effect immediately.

Other routers

The feature is called "Port Forwarding", "Virtual Server", or "NAT Forwarding" depending on the brand. portforward.com has step-by-step guides for hundreds of router models.

Verify the port is open

With iicp-node running, check from an external machine or use an online port checker:

# From another machine outside your network:
curl -v --connect-timeout 5 http://YOUR_PUBLIC_IP:9484/iicp/health

# Or use a port-check tool such as:
# https://portchecker.co   (enter port 9484)

You should see a JSON response (the node health endpoint). A "Connection refused" or timeout means the port is still blocked.

CGNAT — when port forwarding won't work

Some ISPs use Carrier-Grade NAT (CGNAT): instead of giving you a real public IP, they put thousands of customers behind one shared IP. In that case, even a correct port-forwarding rule won't work — the connection never reaches your router.

Detect CGNAT

# Check your public IP
curl -s https://api.ipify.org

# Then check if that IP is in a CGNAT range
# CGNAT uses 100.64.0.0/10 (RFC 6598)
python3 -c "
import ipaddress, subprocess
pub = subprocess.check_output(['curl','-s','https://api.ipify.org']).decode().strip()
ip = ipaddress.ip_address(pub)
print('Public IP:', ip)
print('CGNAT?', ip in ipaddress.ip_network('100.64.0.0/10'))
"

Or visit am.i.mullvad.net/json and check the is_vpn and mullvad_exit_ipfields — a shared exit IP is a strong CGNAT indicator.

What to do if you have CGNAT

Option 1 — Request a public IP from your ISP

Many ISPs will assign a static public IP on request, sometimes for free or a small monthly fee. Call support and ask for "a dedicated public IP address" or "removal from CGNAT".

Option 2 — Use the proxy without a node

If you just want to route tasks throughthe mesh without accepting inbound work, you don't need a public endpoint at all. Install the client SDK and route tasks with it — the client discovers nodes from the directory and forwards your requests without registering a local endpoint. See the client quickstart:

pip install iicp-client      # or: npm i -g @iicp/client  ·  cargo install iicp-client

Option 3 — Automatic tunnel / relay fallback (experimental)

Available, but still experimental.Current clients keep direct IPv4/IPv6/pinhole reachability first. If that route is unavailable or unverified, they can use a zero-account Cloudflare Quick Tunnel for the node's own public endpoint, then fall back to a configured or auto-elected relay path. Directly reachable nodes are not forced through this path.

Affected CGNAT or firewall-gated operators can force a Quick Tunnel for testing, disable it when direct routing is preferred, or point at a specific relay worker endpoint:

# Force a temporary public HTTPS endpoint for this node
iicp-node serve --tunnel

# Opt out of automatic Quick Tunnel fallback
IICP_TUNNEL=0 iicp-node serve

# Use a specific relay worker endpoint when one is provided
IICP_RELAY_WORKER_ENDPOINT=relay.example.com:9485 iicp-node serve

Treat relay/tunnel paths as bootstrap and resilience tools until broader NAT, abuse, confidentiality and rotation testing is complete.

Quick test with a tunnel (no router config needed)

If you just want to verify that your node can receive tasks before committing to router changes, a temporary tunnel gives you a public URL in seconds. This is not a permanent solution — the URL changes every time the tunnel restarts, so you'll need to re-register with the new public_endpoint.

Security note: Use only tunnels whose operator and data-residency posture fit your use case. IICP task payloads (prompts and model outputs) flow over the selected route to the provider node. IICP-CX protects request payloads to key-ready nodes, but the executing node still reads the task it runs. Treat accountless Quick Tunnels as bootstrap/resilience tooling; prefer a named tunnel or operator-managed endpoint for persistent service.

Accountless Cloudflare Quick Tunnel (free, temporary)

# Install cloudflared: https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/
cloudflared tunnel --url http://localhost:9484

The IICP node speaks HTTP, so use http:// as the tunnel target. Cloudflare prints an HTTPS hostname (e.g. https://some-name.trycloudflare.com). Set that as your public_endpoint via the env var (or --public-endpoint) — no port needed:

# use the cloudflared URL — env var or --public-endpoint flag
IICP_PUBLIC_ENDPOINT=https://some-name.trycloudflare.com iicp-node serve

Free quick tunnels don't require a Cloudflare account. The URL persists as long as the cloudflared process is running. The URL changes on every restart — you'll need to update IICP_PUBLIC_ENDPOINT and re-register each time. Because accountless Quick Tunnels can be rate-limited, current clients pause tunnel creation after Cloudflare 429 / 1015 responses instead of retry-storming.

Current client guardrails: accountless tunnel creation is paced across local IICP services (default 120s), serialized with a short local lease (default 45s), and cooled down after provider rate limits (default 900s). If your machine sleeps or a tunnel dies, a supervised current node retries after the cooldown instead of hammering Cloudflare or advertising an unsafe direct route. The directory exposes this as a short recovery window on /stats and /nodes. Override only when you know why: IICP_TUNNEL_CREATE_MIN_INTERVAL_S, IICP_TUNNEL_CREATE_LEASE_S, IICP_TUNNEL_RATE_LIMIT_COOLDOWN_S, and IICP_TUNNEL_DEAD_POLICY.
For a persistent relay or always-on provider (same URL across restarts): use a named Cloudflare Tunnel with your own domain — free with any Cloudflare account — or set an operator-managed IICP_PUBLIC_ENDPOINT. Run cloudflared tunnel login once, then cloudflared tunnel create my-iicp-node to get a stable *.cfargotunnel.com hostname that never changes. See the Cloudflare Tunnel quickstart ↗.

Exposing the standalone Python adapter (port 8080) — advanced

Most operators don't need this. The supported path is the single-binary node — iicp-node serve (HTTP on port 9484, covered above). This section covers the separate execution-plane adapter running from source, an advanced setup.

The standalone IICP Adapter exposes an HTTP API on port 8080. SDK clients discover your adapter's address from the directory and POST tasks directly to it — so the adapter endpoint must be reachable from the internet, just like the node. Run it from your chosen adapter checkout or package; the forwarding mechanics below are identical to 9484.

Port to forward: 8080 TCP (HTTP). The adapter speaks HTTP — use an HTTP tunnel or router forwarding.

Accountless Cloudflare Quick Tunnel (free, temporary)

# Install cloudflared: https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/
cloudflared tunnel --url http://localhost:8080

# cloudflared prints: https://some-name.trycloudflare.com
export IICP_PUBLIC_ENDPOINT=https://some-name.trycloudflare.com
# then start the adapter with this public endpoint

Cloudflare's free quick tunnels work without an account and provide HTTPS automatically. The adapter registers its public_endpoint with the directory at startup. SDK clients will discover this URL and POST tasks to it.

Router port forwarding for the adapter

If you have a public IP (no CGNAT), forward port 8080 the same way as 9484 above, pointing to your machine's local IP. Then set:

export IICP_PUBLIC_ENDPOINT=http://YOUR_PUBLIC_IP:8080
# then start the adapter with this public endpoint

For production use, put the adapter behind a reverse proxy (nginx, Caddy) with TLS so clients reach it over HTTPS.