LPM CLI

lpm tunnel

Expose localhost to the internet, claim stable domains, capture and replay webhooks.

lpm tunnel <port-or-action> [domain]

Exposes a local port to the public internet through the LPM.dev Registry tunnel network. Used by lpm dev --tunnel under the hood, and directly when you need a public URL outside the dev server (running an MCP server locally, hosting a webhook receiver, sharing a preview).

Webhooks that arrive at the public URL are captured to disk. You can browse, filter, and replay them from the CLI or a browser inspector.

Examples

lpm tunnel                                # tunnel the only active lpm dev endpoint
lpm tunnel 4000                           # start on port 4000
lpm tunnel claim acme-api.lpm.llc         # claim a stable domain (Pro/Org)
lpm tunnel unclaim acme-api.lpm.llc       # release a claimed domain
lpm tunnel list                           # your claimed domains
lpm tunnel domains                        # available base domains
lpm tunnel inspect                        # captured webhook event log
lpm tunnel inspect -- --ui                # open browser inspector
lpm tunnel replay 3                       # replay event #3 to localhost
lpm tunnel log                            # browse event log

Starting a tunnel

lpm dev
lpm tunnel

# Or target an explicit server:
lpm tunnel 3000

Returns an https:// URL that proxies to http://127.0.0.1:3000/. Requires a refresh-backed LPM.dev Registry login session — lpm tunnel rejects --token, LPM_TOKEN, and CI-only tokens for relay-facing actions. Free users get an ephemeral random domain on every run; Pro and Org users can claim a stable one (see below).

With no numeric port, lpm tunnel discovers the verified endpoint published by a running lpm dev session. This preserves the child server's loopback address, port, and base path, so Vite on 5173 or a second Vite process on 5174 works without restating the port. No active session is a clear error. If multiple dev sessions are active, pass the intended port explicitly; LPM CLI never guesses between them.

Tunnel and replay forwarding require a plain HTTP child. LPM CLI never disables certificate verification for an arbitrary framework HTTPS server. If the child advertises HTTPS, disable framework-level HTTPS and use lpm dev --https: LPM CLI terminates trusted browser-facing TLS while the tunnel safely forwards to the verified HTTP child.

lpm tunnel 3000 acme-api.lpm.llc          # use a claimed domain
lpm tunnel 3000 --tunnel-auth             # require an auth token to access
lpm tunnel 3000 --auto-ack                # 200 OK while local server is down
lpm tunnel 3000 --session "stripe-test"   # name the session in the inspector

The domain must include a base — lpm.fyi (free + Pro/Org) or lpm.llc (Pro/Org). lpm tunnel 3000 acme (no dot) fails with Missing base domain and suggests the available bases; lpm tunnel domains lists every enabled base with the plan tier required.

--auto-ack is useful when you're not running a server but need webhook providers to keep their endpoint active — providers typically deactivate endpoints after repeated 5xx responses.

Once connected, the startup block prints the public URL, inspector URL, plan, expiry when the relay advertises one, active limits, current accepted/included request usage, overage state, session, complete local URL, and domain. --json keeps local_port for compatibility and adds local_url so scripts retain the scheme, IPv4/IPv6 authority, and base path; it also includes the additive limits and usage objects. Current CLI versions print live usage warnings when the relay sends allowance or overage threshold notices. Press o to open the inspector when it is running, or q to quit the tunnel. Incoming requests stream as compact rows such as → POST /hooks/stripe 201 42ms.

Request allowance

PlanIncluded requestsAccount-wide rateConcurrent tunnelsAfter allowance
Free20,000/UTC month4,000/min1hard stop
Pro100,000/billing period20,000/min3$1/100,000 proportional overage
Org100,000/billed seat/billing period20,000/min/billed seat10$1/100,000 proportional overage

Every plan also applies 600 requests/minute to each visitor IP within the account. Limits and usage are shared across the account's domains; three Pro tunnels do not receive three separate allowances. Pro and Org overage is enabled by default and can be turned off from the tunnel dashboard for a hard stop.

An admitted HTTP request counts once even if localhost later fails or times out. A successful public WebSocket upgrade counts once; its frames do not count. Public WebSockets require a current protocol-v2 CLI connection; tunnels connected by an older protocol-v1 client return 426 Upgrade Required before quota admission. See Request usage and overage for exclusions and billing-period behavior.

Claiming a stable domain

lpm tunnel claim acme-api.lpm.llc
lpm tunnel claim acme-api.lpm.llc --org acme    # claim under an org
lpm tunnel list                                  # show claimed
lpm tunnel unclaim acme-api.lpm.llc              # release

Claimed domains persist across runs — the same URL keeps working as long as you hold the claim. Discover available base domains with lpm tunnel domains.

Inspecting and replaying webhooks

lpm tunnel inspect                # show captured events (terminal table)
lpm tunnel inspect -- --ui        # open the inspector in a browser
lpm tunnel inspect -- --last 10
lpm tunnel inspect -- --status 4xx
lpm tunnel inspect -- --filter stripe
lpm tunnel log                    # event log browse view

lpm tunnel replay 3               # re-deliver event #3 to the local server
lpm tunnel replay 3 -- --port 4000

Captured webhook bodies, headers, and statuses live under the project's tunnel log directory. Local inspect, log, and replay flags are forwarded after --. Replays use an explicit --port, or the single active lpm dev endpoint when no replay port is given. Ports must be in 1..=65535; zero, negative, and overflowing values fail instead of wrapping.

Inspector port

The inspector (web UI) starts automatically alongside the tunnel and binds to a free ephemeral port — the URL is printed on startup. Pass an explicit port if you want a stable bookmark, or --no-inspect to skip the inspector:

lpm tunnel 3000                       # inspector at http://127.0.0.1:<auto-picked>
lpm tunnel 3000 --inspect-port 4500   # inspector at http://127.0.0.1:4500
lpm tunnel 3000 --no-inspect          # skip the inspector entirely

The auto-pick keeps the inspector race-free against the dev server's own port and any other local service. An explicit non-zero --inspect-port N is strict — if N is already in use, the command fails with a clear diagnostic instead of silently rolling to another port.

lpm dev --tunnel accepts the same --inspect-port and --no-inspect flags and surfaces the inspector URL in the startup banner. During multi-service startup the inspector reports that it is waiting for the dev server instead of showing a guessed port; after ownership verification its status includes the resolved local_url. The tunnel footer's o key opens the inspector in a browser.

Flags

FlagEffect
--org <SLUG>Operate against an organization (claim/unclaim/list)
--tunnel-authRequire an auth token to access the tunnel URL (Pro/Org only)
--auto-ackReturn 200 OK to webhooks when the local server is down
--session <NAME>Name this tunnel session in the inspector
--no-inspectDisable the auto-started inspector UI
--inspect-port <N>Bind the inspector to exactly this port (default: auto-pick a free ephemeral port)

Trailing arguments are forwarded to inspect / replay / log subcommands after -- (for example: lpm tunnel inspect -- --last 10, lpm tunnel replay 3 -- --port 4000).

Plus the global flags.

See also

  • lpm dev --tunnel — start a tunnel as part of the dev pipeline
  • Tunneling — how the tunnel network and capture system work
  • lpm cert — local HTTPS for non-tunnel localhost