/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.
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.
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:
192.168.1.1— most common default192.168.0.1fritz.box— FRITZ!Box routers
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.
Router-specific instructions
AVM FRITZ!Box
- Open
fritz.boxin your browser and log in. - Go to Internet → Permit Access → Port Sharing.
- Click Add Device for Sharing, select your machine.
- Click Add Sharing, set Protocol: TCP, Port: 9484 (external and internal).
- Save. The rule is active immediately.
TP-Link (Archer series)
- Log in at
192.168.1.1(ortplinkrouter.net). - Go to Advanced → NAT Forwarding → Virtual Servers.
- Click Add. Service Type: Custom. External Port: 9484. Internal IP: your machine's IP. Internal Port: 9484. Protocol: TCP.
- Save and reboot the router if prompted.
ASUS (RT series)
- Log in at
192.168.1.1orrouter.asus.com. - Go to WAN → Virtual Server / Port Forwarding.
- Click Add profile. Service Name: iicp-node. Protocol: TCP. External Port: 9484. Internal IP: your machine. Internal Port: 9484.
- 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)
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.
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.
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.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
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.
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.