Apps · Porthole

Show what you are building, without deploying it

Run one command and someone else can use the app on your laptop, in their browser, from anywhere. No public URL, no inbound port, no VPN — and nothing left running afterwards, because there was never an address to leave running.

0 public addresses created nothing to scan, nothing to guess, nothing to forget about
0 inbound ports opened the agent on your machine only ever makes outbound connections
AES-256-GCM on every request and response the relay carries ciphertext; the key never travels in the link
How it works

A description of a request, carried as a message

Porthole does not forward packets. It takes the HTTP request the guest's browser wanted to make, seals it, and sends it as an ordinary message on a channel. The agent on your machine unseals it, makes that request against localhost, and sends the response back the same way.

  • You run porthole 3000. It connects outbound to a channel and waits.
  • You send a link and, separately, the session password. The password is never in the link — a link alone reaches nothing.
  • Their browser loads a session page holding the key. A service worker intercepts every fetch the app makes and tunnels it, so the app runs unmodified — it does not know it is not local.
  • The relay sees sealed blobs. It cannot read the traffic, and there is no TLS termination where it could.
The difference

Not another tunnel

ngrok, Cloudflare Tunnel and friends work by creating a public address for your local app. Porthole creates no address at all, and that is the entire point.

  A tunnel with a public URL Porthole
Public URLyes — scannable within minutesnone exists
Inbound portsnonenone
Who can reach itanyone holding the URLchannel and password holders
What the relay seesyour traffic — TLS terminates thereciphertext
Left behindlive until you stop itnothing to leave behind
One agent, three modes

Pick who gets in, deliberately

Porthole and Backstage are one app now: the same agent and the same viewer, and the difference is a mode you choose when you start it. backstage still works — it is this agent with the door shut by default.

Instant --mode instant

Whoever holds the link and the password reaches the app. Fast, and right when you are showing a colleague something for ten minutes. The default for porthole.

Approval --mode approval

Nobody gets in until you press a key, every knock and refusal is written to an audit file, and a named session (--session) gives back the same link tomorrow. Right when the person asking is a client, or the answer has to survive a security review. --mode review lets anyone with the link look, and nobody change anything.

What it does not do

It is not hosting. Your machine has to be awake and the agent running — close the laptop and the session ends, which is the honest consequence of there being no copy of your app anywhere else.

And in instant mode a link plus a password reaches everything the app serves, on every path — limit it with --allow and --deny, or start it in approval mode and let each viewer in yourself.

Pricing

What it costs

Free for an open link — approval and review, with an audit file, are licensed

An open link is free: your machine serves the app and the channel carries sealed blobs, so there is nothing to meter. The door and the paperwork — approval, read-only review and the audit file, formerly Backstage — are what a licence covers. Without one they still run, and the log records licensed: false.

How it's built

The part that matters, in the open

A service worker in the guest's browser answers the app's own requests, so a private site loads with no public URL.

web/js/app.js
await navigator.serviceWorker.register('sw.js', { scope: './' });
await navigator.serviceWorker.ready;
navigator.serviceWorker.addEventListener('message', onWorkerMessage);

Taken from this app's source, not written for the page. Built on the Messaging Platform SDK.