Early alpha: This is an experiment and is not intended for production use.
cinder-link is a Go tunnel service and CLI for exposing local HTTP and WebSocket services over a secure WebSocket session.
This repository currently contains the initial MVP scaffolding:
cmd/tunneldfor the hosted control-plane, gateway, and edge processcmd/tunnelfor the local CLI client- shared config, logging, ID generation, shutdown helpers, and tunnel protocol types
- in-memory session and route registries to support early bring-up before Postgres wiring lands
- starter SQL schema for the account, token, session, route, and audit models
The local client is now moving toward the intended agent-based model:
tunneldowns the hosted gateway, edge proxy, and control-plane wiringtunnel agentowns one long-lived local tunnel sessiontunnel statusqueries the local agent for session and route statetunnel route add,tunnel route list, andtunnel route deletemanage routes through the local agent- one agent session can forward HTTP, WebSocket, and local HTTPS upstreams
The current quota implementation is account-based and count-based:
max_sessions: maximum active tunnel sessions per accountmax_routes: maximum active public routes per account
This means quotas currently limit how many connected client sessions and route mappings an account may hold at once.
The current MVP does not yet enforce bandwidth quotas or billing-period traffic usage. Those are planned as later quota layers.
Start Postgres 18 with Docker Compose:
docker compose up -d postgresThen export the database URL or copy .env.example values into your shell:
export CINDER_DATABASE_URL='postgres://postgres:postgres@127.0.0.1:5432/cinder_link?sslmode=disable'tunneld automatically runs SQL migrations on startup when CINDER_DATABASE_URL is set.
- Use a TLS-terminating reverse proxy in front of
tunneldfor productionwsstraffic. - Keep
CINDER_TLS_INSECURE=falsein production; it exists only for local development against self-signed endpoints. - Set
CINDER_ALLOWED_ORIGINSwhen browser clients need to reach the gateway from a different origin than the request host. CINDER_MAX_BODY_BYTESdefaults to10485760(10 MiB) and caps request/response bodies until chunked streaming lands.- Gateway and edge rate limits are configurable with
CINDER_GATEWAY_CONNECT_RATE,CINDER_ROUTE_REGISTER_RATE, andCINDER_EDGE_REQUEST_RATEplus matching*_BURSTenv vars.
Run the hosted service:
go run ./cmd/tunneldRun the client help:
go run ./cmd/tunnel --helpStart the local agent:
go run ./cmd/tunnel agentAdd a route through the local agent:
go run ./cmd/tunnel route add --subdomain api-demo --target-port 8080Show current session and routes:
go run ./cmd/tunnel statusList or delete routes:
go run ./cmd/tunnel route list
go run ./cmd/tunnel route delete --route-id rte_xxxOpen a one-shot foreground route for quick local testing:
go run ./cmd/tunnel open --subdomain api-demo --target-port 8080Common local verification commands:
make test
make sqlc
make nilawaysqlc and nilaway are tracked in go.mod as Go tools, so no separate install step is needed.
Or run the combined check locally:
make ciThe project now supports agent-owned sessions, route add/list/delete, HTTP forwarding, WebSocket forwarding, and HTTPS localhost upstreams with explicit insecure skip-verify support. Reconnect polish, richer CLI/TUI flows, and production hardening are still in progress.