Documentation

Everything you need to expose localhost to the internet — install, authenticate, and tunnel in under a minute.

Introduction

poriq is an open-source tunneling tool that gives any local service a public HTTPS URL. Point it at a port and you get a shareable https://yourapp.poriq.run address with automatic TLS — no firewall changes, no deploy. It speaks HTTP, TCP, and UDP, and it is MIT-licensed and self-hostable.

A tunnel runs over a single persistent WebSocket between the CLI and the server, so connections survive flaky networks and reconnect on their own. Large uploads stream rather than buffer, and inner WebSockets (like a dev server's HMR socket) are proxied transparently.

Installation

Install with Go (1.22+):

go install github.com/poriq/poriq@latest

This drops a poriq binary in your $GOPATH/bin. Confirm it is on your PATH:

poriq version

Authentication

Sign in once with your GitHub account. This opens a browser device flow and stores an API token locally (~/.config/poriq/config.json).

poriq login
# → opens GitHub, enter the shown code
# → "logged in as <you>"

Check status or sign out at any time:

poriq status
poriq logout

Quick Start

Expose a local server running on port 3000:

poriq http 3000

  Tunnel established!
  Public URL:  https://bold-wren-204.poriq.run
  Forwarding:  https://bold-wren-204.poriq.run → http://localhost:3000
  Inspector:   http://localhost:4040

Share the public URL. Every request is forwarded to your local server and shown live in the terminal and the inspector.

HTTP Tunnels

poriq http is the workhorse. Pass one or more ports — multiple ports open multiple tunnels at once.

poriq http 3000                 # single tunnel
poriq http 3000 8080            # two tunnels
poriq http https://localhost:8443   # HTTPS local target (cert ignored)

Options

<port[:subdomain]>Local port to expose. Optionally pin a subdomain, e.g. 3000:myapp.
--newRequest a fresh random subdomain instead of reusing a saved one.
--inspect <port>Web inspector UI port (default 4040, 0 to disable).
--log <file>Append every request to a JSONL file for later replay.
--auth <user:pass>Protect the tunnel with HTTP Basic auth.
--allow-ip <list>Allow only these IPs/CIDRs (comma-separated).
--rate-limit <rps>Cap requests per second to your local server.
--rate-limit-path <path:rps>Per-path rate limit override (repeatable).
--mock <path:status:body>Return a canned response for a path (repeatable).
--rewrite <from:to>Rewrite a request path prefix before forwarding (repeatable).
--header-add / --header-removeAdd or strip request headers before forwarding.
--response-header-add / -removeAdd or strip headers on the response.
--wol <name=MAC|IPv4>Register a Wake-on-LAN target (repeatable).
--notify-on-errorDesktop notification on 5xx responses.
--timeout <dur>Local response timeout, e.g. 30s, 1m.
--drain-timeout <dur>Grace period for in-flight requests on shutdown (default 5s).
--quietSuppress the per-request log output.

TCP & UDP Tunnels

Forward raw TCP or UDP — SSH, databases, game servers, anything. These are available on paid plans and expose a host:port instead of an HTTPS URL.

poriq tcp 22      # → tunnel.poriq.run:10000 → localhost:22
poriq udp 51820   # WireGuard, DNS, game servers, …

Connect using the host and allocated port poriq prints on start.

WebSockets & HMR

WebSocket upgrades are proxied bidirectionally over the same tunnel, so realtime apps and dev-server hot reload work out of the box.

One caveat for framework dev servers (Next.js, Vite, …): they reject cross-origin dev requests by default. Add your tunnel host to the dev-origin allowlist, e.g. in next.config.js:

// next.config.js
module.exports = {
  allowedDevOrigins: ["*.poriq.run"],
};

Custom Subdomains

Free tunnels get a random subdomain each session. Paid plans can reserve subdomains and reuse them. Pin one inline:

poriq http 3000:myapp     # → https://myapp.poriq.run

poriq remembers the subdomain per local URL, so the next run reuses it automatically. Pass --new to force a fresh one. Reserve and manage subdomains from the dashboard.

Request Inspector

Every HTTP tunnel ships a local web inspector (default http://localhost:4040) showing each request and response — headers, body, status, and timing.

poriq http 3000 --inspect 4040   # change the port
poriq http 3000 --inspect 0      # disable it

Log requests to a file and replay them later in the same UI:

poriq http 3000 --log requests.jsonl
poriq inspect requests.jsonl     # open the saved log

Config File

Drop a poriq.json in your project to avoid retyping flags. Generate a starter with poriq init.

{
  "port": 3000,
  "subdomain": "myapp",
  "tunnels": [{ "port": 3000 }, { "port": 8080 }],
  "inspect": 4040,
  "log": "requests.jsonl",
  "auth": "user:pass",
  "allow_ips": ["10.0.0.0/8"],
  "rate_limit": 50,
  "rate_limits": { "/api/webhook": 10 },
  "mocks": { "/health": { "status": 200, "body": "ok" } },
  "path_rewrites": { "/api/v1": "/v1" },
  "header_add": ["X-From: poriq"],
  "notify_on_error": true,
  "timeout": "30s"
}

Running poriq http with no arguments picks up this file.

Security & Access Control

Gate a tunnel without touching your app:

poriq http 3000 --auth admin:s3cret           # HTTP Basic auth
poriq http 3000 --allow-ip 1.2.3.4,10.0.0.0/8 # IP allowlist
poriq http 3000 --rate-limit 50               # 50 req/s cap
poriq http 3000 --rate-limit-path /api/webhook:10

These run at the edge of your tunnel, so blocked requests never reach your local server.

Traffic Shaping

Mock endpoints, rewrite paths, and rewrite headers on the fly:

# Canned response (path:status:body)
poriq http 3000 --mock /health:200:ok

# Rewrite a path prefix before forwarding
poriq http 3000 --rewrite /api/v1:/v1

# Add / strip headers
poriq http 3000 --header-add "X-Env: tunnel" \
                --response-header-remove "X-Powered-By"

Wake-on-LAN

Register Wake-on-LAN targets so you can boot machines on your LAN remotely through the tunnel (and the dashboard).

poriq http 3000 --wol "desktop=192.168.1.20"
poriq http 3000 --wol "desktop=AA:BB:CC:DD:EE:FF"

IPv4 lookup uses your local ARP/neighbor cache at startup. poriq only sends magic packets for MACs explicitly registered or resolved on the tunnel client machine.

Plans & Limits

Free

$0
  • 2 HTTP tunnels
  • Random subdomains
  • Short sessions, manual reconnect
  • 50 MB / day
  • 5K requests / day

Pro

$5/mo
  • 5 HTTP + 2 TCP
  • 3 custom subdomains
  • Configurable TTL, default off
  • 2 GB / day
  • 100K requests / day

Team

$15/mo
  • 10 HTTP + 5 TCP
  • 10 custom subdomains
  • Configurable TTL, default off
  • 10 GB / day
  • 1M requests / day

Paid plans can still be limited by server policy. The normal paid default is TTL off, while trial, promo, and PoC deployments can use explicit TTLs such as 1h or 8h. TCP/UDP inherit the same duration policy when a plan sets one.

HTTP request bodies stream up to 100 MB. Self-hosting removes all limits. See pricing for details.

Self-Hosting

poriq is MIT-licensed and runs as a single binary. Host your own server with zero limits on tunnels, bandwidth, and sessions — your infra, your rules.

# build the server
go build -o poriq-server ./cmd/poriq-server

# run it (HTTP + tunnel API on one process)
./poriq-server --domain example.com --port 9090

Point clients at it with --server wss://example.com. Full guide on GitHub.

CLI Reference

poriq login              authenticate with GitHub
poriq logout             remove saved credentials
poriq status             show auth status
poriq http <port...>     create HTTP tunnel(s)
poriq tcp  <port>        create a TCP tunnel
poriq udp  <port>        create a UDP tunnel
poriq inspect <file>     view a saved request log
poriq init               create a poriq.json config
poriq version            show version info

Run any command with --help to see its full flag set.

Ready to tunnel? Sign in with GitHub and run poriq http 3000.

Get Started — Free