- CONTRIBUTING: use holepunchto/bare repo URL - NATIVE-HOST: getState servers use url (not hsUrl), no state field - BACKUP/NATIVE-HOST: backup filenames use holesail-backup- prefix and _ timestamp - NATIVE-HOST: document createBackup/listBackups path and createdAt - SSH: clarify that saved password is stored as passwordB64 in state.json - ARCHITECTURE: note extra state.json settings in SETTINGS_DEFAULTS
Holesail Browser
Browse P2P Holesail tunnels directly in your browser. Holesail Browser is a Chrome/Firefox extension paired with a native host that routes virtual host domains (e.g. *.hole.sail or any private TLD you choose) through Holesail tunnels — with automatic TLS, no port-forwarding, and no central servers.
How it works
- You add a virtual host in the dashboard:
myapp.hole.sail→hs://abc123... - The extension sets a PAC script that routes
*.hole.sail(and any other custom TLDs) → local CONNECT proxy (port 8442) - The CONNECT proxy pipes the raw TLS stream to the HTTPS proxy (port 8443)
- The HTTPS proxy reads the TLS ClientHello, extracts the SNI hostname, and presents a per-TLD wildcard cert (signed by the local CA)
- The Holesail tunnel connects P2P to the remote peer over the DHT
All traffic is end-to-end encrypted via the Noise protocol. The local CA is only used for the browser↔proxy TLS leg.
Features
- Virtual Hosts — browse any
hs://URL ashttps://name.hole.sail/or any custom private TLD (e.g.https://api.my.internal/) - Custom TLDs — use any private two-tier TLD, not just
.hole.sail; PAC script and certificates are updated automatically - Server Tunnels — expose a local port as an
hs://key (TCP or UDP); supports an optional label for easy identification - Service Tunnels — forward a remote
hs://peer to a local TCP port - SSH — in-browser SSH terminal via xterm.js, over a Holesail tunnel; supports public key, saved password, and interactive auth
- Remote Desktop — VNC (noVNC) and RDP viewer in the browser, over a Holesail tunnel; passwords saved securely
- Backups —
tar.gzsnapshots of all state and certificates, with configurable retention - Auto CA — generates and installs a local root CA; issues per-TLD wildcard certs on demand via JS-layer SNI
- Persistent state — all tunnels, connections, and settings survive restarts
Installation
macOS / Linux (recommended)
curl -fsSL https://git.ssh.surf/snxraven/holesail-browser/raw/branch/main/scripts/web-installer.sh | bash
Windows (Windows 11 latest)
Download and run the PowerShell installer:
irm https://git.ssh.surf/snxraven/holesail-browser/raw/branch/main/scripts/install.ps1 | iex
Or download install.ps1 from the latest release and run it manually.
What the installer does
- Downloads the pre-built native host binary for your platform from the latest release
- Installs it to
~/.holesail-browser/(macOS/Linux) or%LOCALAPPDATA%\holesail-browser\(Windows) - Writes the native messaging manifest so Chrome/Firefox can find it
- Downloads the extension
.zip(Chrome) and.xpi(Firefox) to~/Downloads - On macOS: removes Gatekeeper quarantine and ad-hoc signs the binary and native addons
Loading the extension
Chrome / Edge
- Open
chrome://extensions - Enable Developer mode (top right)
- Drag
~/Downloads/Holesail-Browser-1.0.0.ziponto the page
(or click Load unpacked after extracting the zip)
Firefox (regular)
Firefox requires extensions to be signed by Mozilla for permanent installation. Use the temporary add-on loader instead:
- Open
about:debugging - Click This Firefox
- Click Load Temporary Add-on...
- Select
~/Downloads/Holesail-Browser-1.0.0.zip(or any file inside the extracted folder)
Note: Temporary add-ons are removed when Firefox restarts. You will need to reload it each time.
Firefox Developer Edition / Nightly (permanent, unsigned)
Developer Edition and Nightly allow disabling signature enforcement:
- Open
about:config→ search forxpinstall.signatures.required→ set it tofalse - Open
about:addons→ gear icon → Install Add-on From File - Select
~/Downloads/Holesail-Browser-1.0.0.xpi
Firefox (permanent, signed)
For a permanent install in regular Firefox, the extension must be signed by Mozilla via addons.mozilla.org. Self-hosted distribution (no public listing required) is available — see docs/INSTALLATION.md for details.
First run
- Click the Holesail Browser icon in your toolbar to open the Overview dashboard
- Go to Proxy & CA → click Install Root CA
- Fully quit and reopen Chrome (Cmd+Q on macOS) for the CA trust to take effect
- Go to Virtual Hosts → add a hostname (e.g.
myapp.hole.sail) and itshs://key - Navigate to
https://myapp.hole.sail/
Note: The CA must be installed and Chrome must be restarted before virtual host sites will load without a certificate warning. You can use any private two-tier TLD — not just
.hole.sail.
Dashboard pages
The dashboard uses a single topbar title per page. The Overview page is the landing page and features a sticky Quick Actions bar at the bottom with equal-height scrollable list cards for all data types.
| Page | Description |
|---|---|
| Overview | Status summary, stat cards, scrollable lists for all data types, Quick Actions |
| Virtual Hosts | Map hs:// keys to hostnames on any private TLD |
| Server Tunnels | Expose local ports as hs:// keys (TCP/UDP), with optional label |
| Service Tunnels | Forward remote hs:// peers to local TCP ports |
| Proxy & CA | Proxy port settings, CA install/status |
| SSH | In-browser SSH terminal over Holesail |
| Remote Desktop | VNC/RDP viewer over Holesail |
| Backups | Create, restore, and manage backups |
| Logs | Live log stream from the native host |
| Settings | Proxy ports, timeouts, notifications, debug mode |
File locations
| Path | Description |
|---|---|
~/.holesail-browser/holesail-browser-host |
Native host binary |
~/.holesail-browser/holesail-browser-storage/state.json |
All persistent state |
~/.holesail-browser/holesail-browser-certs/ |
CA and domain certificates |
~/.holesail-browser/holesail-browser.log |
Native host log file |
~/.holesail-browser/holesail-browser-storage/backups/ |
Backup archives |
Troubleshooting
Virtual host sites show a certificate error
The root CA is not trusted, or Chrome was not restarted after installing it. Open the dashboard → Proxy & CA and check the CA status. If it shows "Not Installed", click Install Root CA, then fully quit and reopen Chrome (Cmd+Q).
If the CA shows "Installed" but you still see errors, the keychain may have a stale entry from a previous installation. Click Install Root CA again — it will detect the mismatch, remove the old entry, and install the correct one.
No tunnel for this hostname
The native host has no active tunnel for that hostname. Possible causes:
- The tunnel is still connecting — wait a few seconds and refresh
- The native host was restarted and is reconnecting — open the dashboard to check
- The hostname in the dashboard doesn't exactly match what you're browsing
Native host not connecting / hostConnected: false
- Make sure you haven't started
holesail-browser-hostmanually from a terminal — only Chrome should spawn it via native messaging - Check
~/.holesail-browser/holesail-browser.logfor errors - Try reloading the extension at
chrome://extensions
macOS: "Apple cannot verify..." / Gatekeeper warning (e.g. bare-pipe.bare)
On macOS 15+ and 26+ (Tahoe), the main binary must have the com.apple.security.cs.disable-library-validation entitlement to load ad-hoc signed native addons. The installer creates a launcher (so TMPDIR is set before the binary runs), extracts and signs addons, then re-signs the main binary with that entitlement. Rebuild the host and run the installer again so you get the launcher + entitlement. If you still see the warning or installed manually, run:
REAL_BIN=$(find ~/.holesail-browser -name holesail-browser-host -type f | head -1)
HOST_DIR=$(dirname "$REAL_BIN")
ADDON_TMP="${HOST_DIR}/tmp"
/usr/bin/xattr -rd com.apple.quarantine ~/.holesail-browser 2>/dev/null || true
# Sign main binary FIRST so --extract-addons is not killed (SIGKILL 9)
printf '%s\n' '<?xml version="1.0" encoding="UTF-8"?>' '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">' '<plist version="1.0"><dict><key>com.apple.security.cs.disable-library-validation</key><true/></dict></plist>' > "${HOST_DIR}/entitlements.plist"
codesign --force --sign - --entitlements "${HOST_DIR}/entitlements.plist" "$REAL_BIN"
mkdir -p "$ADDON_TMP"
export TMPDIR="$ADDON_TMP"
"$REAL_BIN" --extract-addons 2>/dev/null
sleep 2
find "$ADDON_TMP" -type f \( -name "*.bare" -o -name "*.dylib" \) -exec codesign --force --sign - {} \; 2>/dev/null
Access to the specified native messaging host is forbidden
The extension ID in the native messaging manifest doesn't match the installed extension. Re-run the installer, or manually update the allowed_origins field in the manifest JSON to match the extension ID shown in chrome://extensions.
Building from source
git clone https://git.ssh.surf/snxraven/holesail-browser
cd holesail-browser
npm install
cd native-host && npm install && cd ..
# Build extension
npm run pack
# Build native host binary for current platform
npm run build:dist
# Build for all platforms
npm run build:dist:all
The built extension will be in releases/Holesail-Browser-*.zip and .xpi. Platform binaries will be in releases/<platform>-<arch>/.
Platform support
| Platform | Architecture | Binary |
|---|---|---|
| macOS | Apple Silicon (arm64) | darwin-arm64 |
| macOS | Intel (x64) | darwin-x64 |
| Linux | x64 | linux-x64 |
| Linux | ARM64 | linux-arm64 |
| Windows 11 (latest) | x64 | win32-x64 (.exe) |
Documentation
- Architecture — system design, component overview, message flow
- Installation — detailed install guide for all platforms
- Tunneling — virtual hosts, server tunnels, service tunnels
- Virtual Hosts — custom TLDs, certificate generation, deep hostnames
- SSH — in-browser SSH terminal
- Remote Desktop — VNC and RDP over Holesail
- Backups — backup and restore
- Security — CA model, encryption, threat model
- Native Host Protocol — message types and API reference
License
GNU Affero General Public License v3.0 (AGPL-3.0). See LICENSE for the full text.