Go to file
2026-05-15 15:37:10 -07:00
.cursor/rules sneaker 2025-09-23 19:11:39 -07:00
src Add chunked response support for large bodies 2026-05-15 15:37:10 -07:00
.gitignore sneaker 2025-09-23 19:11:39 -07:00
.npmrc npm registry 2026-02-11 16:32:23 -08:00
bun.lock Update dependencies and package config 2026-03-25 20:52:05 -07:00
CLAUDE.md sneaker 2025-09-23 19:11:39 -07:00
package.json 0.0.5 2026-03-25 20:52:42 -07:00
README.md readme 2026-03-02 21:28:12 -08:00
tsconfig.json sneaker 2025-09-23 19:11:39 -07:00

sneaker

Sneakers sneaks your home server onto the internet by tunneling traffic between a public URL and your private server using WebSockets.

Install

bun add @because/sneaker

Server

Run the tunnel server:

bun run src/server.tsx

The server exposes:

  • GET /health — returns the current git SHA
  • GET /tunnels — lists active tunnel connections
  • GET /tunnel/:app — redirects to the app's subdomain
  • GET /tunnel?app=NAME — WebSocket endpoint for clients to establish a tunnel (optional subdomain query param to request a specific subdomain)

Incoming HTTP requests to SUBDOMAIN.your-server.com are forwarded through the WebSocket to the connected client and proxied to the local target.

The server adds an x-sneaker header with the server's hostname to all proxied requests.

Client

import { connect } from "@because/sneaker"

const tunnel = connect({
  server: "ws://your-server.com",
  app: "my-app",
  target: "http://localhost:3000",
  subdomain: "my-app",       // optional: request a specific subdomain
  reconnect: true,            // optional: auto-reconnect (default: true)
  onOpen(subdomain) {
    console.log(`Tunnel open: ${subdomain}.your-server.com`)
  },
  onClose() {
    console.log("Tunnel closed")
  },
  onRequest(req) {
    console.log(`${req.method} ${req.path}`)
  },
  onError(err) {
    console.error(err)
  },
})

// Later:
tunnel.close()

Client options

Option Type Description
server string WebSocket URL of the tunnel server
app string App name identifier
target string Local URL to proxy requests to
subdomain string? Request a specific subdomain
reconnect boolean? Auto-reconnect on disconnect (default: true)
onOpen (subdomain: string) => void Called when tunnel is established
onClose () => void Called when tunnel disconnects
onRequest (req) => void Called for each proxied request
onError (error: Error) => void Called on errors

Binary responses (images, fonts, etc.) are automatically base64-encoded over the tunnel and decoded by the server.