Files
holesail-browser/docs/TUNNELING.md
T
Raven Scott f5c349a4a3
CI / Build & Test (push) Successful in 2m56s
docs
2026-02-28 22:29:56 -05:00

7.4 KiB

Tunneling

Holesail Browser supports three tunnel types: virtual hosts (for browsing), server tunnels (for sharing), and service tunnels (for raw TCP forwarding). All tunnels use the Holesail P2P network and are persisted across restarts.

How *.hole.sail browsing works

When you navigate to https://myapp.hole.sail/:

  1. The PAC script (set by the extension) matches *.hole.sail and routes the request to PROXY 127.0.0.1:8442
  2. Chrome sends CONNECT myapp.hole.sail:443 HTTP/1.1 to the CONNECT proxy
  3. The CONNECT proxy replies 200 Connection established and pipes the stream to 127.0.0.1:8443
  4. The HTTPS proxy reads the TLS ClientHello, extracts the SNI hostname (myapp.hole.sail), derives the wildcard parent (hole.sail), and presents the *.hole.sail wildcard cert signed by the local CA
  5. The HTTPS proxy reads the Host header, looks up the Holesail tunnel for myapp.hole.sail, and proxies the HTTP request to the tunnel's local port
  6. The Holesail client tunnel forwards the request to the remote peer over the DHT

All traffic between the browser and proxy is TLS-encrypted using a locally-trusted certificate. Traffic between the native host and the remote peer is encrypted via the Noise protocol.

Virtual hosts

Virtual hosts map an hs:// key to a *.hole.sail hostname. The browser navigates to the hostname; the proxy looks up the tunnel and forwards the request.

Adding a virtual host

  1. Open the dashboard → Virtual Hosts
  2. Enter a hostname (e.g. myapp.hole.sail) and the hs:// key for the remote peer
  3. Click Add — the tunnel connects immediately and the entry is saved to state.json

Hostname rules

  • Must have at least 3 labels (e.g. myapp.hole.sail, not hole.sail)
  • The TLD portion must be two-tier (e.g. .hole.sail, .my.internal) — single-label TLDs like .holesail are not allowed
  • Must not use a real public TLD (.com, .net, .co.uk, etc.)
  • Each label may contain only lowercase letters, digits, and hyphens; no leading or trailing hyphens
  • Any depth is supported: myapp.hole.sail, i.love.hole.sail, api.v2.my.internal
  • You are not limited to .hole.sail — any valid private two-tier TLD works (see VIRTUAL-HOSTS.md)

Port allocation

Each virtual host gets a local port allocated from 19000 upward. The HTTPS proxy forwards requests for that hostname to 127.0.0.1:<allocated-port>. Ports are released when the virtual host is removed.

Lifecycle events

The native host emits events that the extension relays to subscribed tabs:

Event Description
tunnelReady Tunnel connected and ready to serve requests
tunnelClosed Tunnel disconnected (peer went offline or was removed)
tunnelError Tunnel failed to connect

Persistence

Virtual hosts are saved to state.json and restored on every native host startup. The tunnel reconnects automatically — if the remote peer is temporarily offline, the tunnel will reconnect when it comes back.

Removing a virtual host

Open the dashboard → Virtual Hosts → click the remove button. The tunnel is closed and the entry is deleted from state.json.


Server tunnels

Server tunnels expose a local TCP (or UDP) port as an hs:// key. Other peers can connect to your service using that key.

Creating a server tunnel

  1. Open the dashboard → Server Tunnels
  2. Optionally enter a Label (e.g. My Web App) to identify the tunnel
  3. Enter the local port to expose (e.g. 3000)
  4. Select TCP or UDP
  5. Optionally enable Secure mode (requires the connecting peer to have the key)
  6. Click Start — an hs:// key is generated and displayed

Share the hs:// key with anyone who should be able to connect to your service.

Parameters

Parameter Description
label Optional human-readable name shown in the dashboard
port Local port to expose
host Local host to bind (default: 127.0.0.1)
udp Use UDP instead of TCP (default: false)
secure Require key authentication (default: true)

Persistence

Server tunnels are saved to state.json and restarted on every native host startup. The hs:// key is stable — it is derived from the server's keypair, which is preserved in state.

Stopping a server tunnel

Open the dashboard → Server Tunnels → click Stop. The tunnel is closed and the entry is deleted from state.json.


Service tunnels

Service tunnels forward a remote hs:// peer to a local TCP port. Any local application can connect to 127.0.0.1:<port> and communicate with the remote peer directly — without going through the browser proxy.

Use cases:

  • Connect a local database client to a remote database over Holesail
  • Forward a remote TCP service to a local port for use by any application
  • Expose a Minecraft server, game server, or other TCP service locally

Creating a service tunnel

  1. Open the dashboard → Service Tunnels
  2. Enter a label (e.g. Postgres), the hs:// key, and the local port to bind
  3. Click Start — the tunnel connects and begins listening on the specified port

Parameters

Parameter Description
label Human-readable name
hsUrl hs:// key for the remote peer
localPort Local TCP port to bind

Persistence

Service tunnels are saved to state.json and restored on startup.

Reconnecting a service tunnel

If a service tunnel enters an error or closed state, click Reconnect in the dashboard. This sends an updateServiceTunnel command to the native host, which stops the old tunnel (if any) and starts a fresh one with the same parameters.

Stopping a service tunnel

Open the dashboard → Service Tunnels → click Stop.


Tunnel lookup

You can check whether an hs:// key is reachable on the DHT without creating a full tunnel. This is useful for verifying a key before adding it as a virtual host or service tunnel.

From the dashboard → Virtual Hosts or Service Tunnels, use the lookup/test button next to the hs:// field.


Tunnel type comparison

Feature Virtual Host Server Tunnel Service Tunnel
Direction Inbound (you browse to remote) Outbound (remote connects to you) Inbound (you connect to remote)
Access method Browser via *.hole.sail URL hs:// key shared with peers Local TCP port
Protocol HTTPS (TLS terminated locally) TCP or UDP TCP
Use case Browse remote web apps Share local services Connect local apps to remote services
Persisted Yes Yes Yes

Troubleshooting

No tunnel for this hostname

The HTTPS proxy received a request for a hostname it has no tunnel for. Causes:

  • The tunnel is still connecting — wait a few seconds and refresh
  • The native host restarted and is still restoring tunnels — open the dashboard to check
  • The hostname doesn't exactly match what was configured (check for typos)

Tunnel shows connecting but never becomes ready

  • The remote peer may be offline
  • The hs:// key may be incorrect
  • Check ~/.holesail-browser/holesail-browser.log for error details
  • Try setting readyTimeoutMs to 30000 in Settings to surface timeout errors

Service tunnel port is already in use

Another process is using the requested local port. Choose a different port, or stop the conflicting process.