Documentation

Self-hosting

Run your traffic over a relay you own. It takes about ten minutes, it works with Kino Cloud, and it costs nothing.

The relay is the only piece with a public address, so it is the piece people most often want to own. That is a supported, first-class setup — kino-relay is AGPL-3.0 and there is nothing to unlock.

You do not have to give up Kino Cloud to do it. Enroll your relay and you keep automatic discovery, self-installing machines, and expiring credentials — your bytes just take your route.

Should you?#

Kino Cloud relays Your own relay
Setup None A VM, a domain, and ten minutes
Upkeep None Yours — TLS renewal, restarts, updates
Your traffic crosses Shared infrastructure Hardware you control
Latency Nearest healthy relay Wherever you put it
Can read your session No — it is ciphertext either way No

The privacy argument is weaker than it looks: a relay cannot read your session whichever one you use. The real reasons to run your own are placement (a relay in the same region as your machines), policy (a compliance rule that says traffic stays on infrastructure you own), and not depending on anyone else’s uptime.

Path A — your relay, with Kino Cloud#

Recommended. Discovery, installs, and credential rotation keep working exactly as they do now.

1. Put it on a public host#

Anywhere always-on with a public address. The relay is tiny and stateless, but it holds long-lived WebSocket connections, so it needs somewhere that does not idle-sleep or cap connection duration — an always-on VM, not a serverless tier. Oracle Cloud’s Always Free ARM instances work well; the aarch64 build covers them.

git clone https://github.com/Samarthegde/kino-relay && cd kino-relay
cp .env.example .env

2. Get an enrollment code#

Relays → New enrollment code. One use, yours in a click.

3. Fill in .env#

KINO_CONTROL_URL=https://kino.dpdns.org
KINO_ENROLL_CODE=<the code>
RELAY_PUBLIC_URL=wss://relay.example.com
RELAY_NAME=my-relay

# Worth setting: a relay whose enrollment fails and has no other credential
# runs with NO authentication. Generate with: openssl rand -hex 32
RELAY_TOKEN=<a long random string>

4. Terminate TLS in front of it#

The relay speaks plain HTTP and expects a proxy. WebSocket upgrade headers are mandatory — without them every connection fails with 400 Bad Request:

map $http_upgrade $connection_upgrade { default upgrade; '' close; }

server {
    listen 443 ssl;
    server_name relay.example.com;
    # ssl_certificate / ssl_certificate_key …

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade    $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_read_timeout 1h;        # or idle terminals get cut at 60s
        proxy_buffering off;
    }
}

A complete, correct server block ships in the repository at deploy/nginx-kino-relay.conf.

Do not put it behind a CDN proxy

Cloudflare’s orange cloud adds a ~100-second idle WebSocket timeout and puts long-lived tunnelling in the way of the terms of service. Grey-cloud the record.

5. Start it#

docker compose up -d --build

RELAY_PUBLIC_URL must already resolve and answer /healthz over TLS — Kino Cloud probes it before accepting the enrollment. Check from somewhere else first:

curl -fsS https://relay.example.com/healthz     # -> ok

The relay serves first, enrolls, receives the public key it verifies credentials with, saves it to its volume, and starts enforcing auth immediately — no second restart. Later starts load the saved key and skip enrollment, so the code is needed exactly once.

Your relay now appears on Relays, health-checked every minute.

6. Nothing else changes#

Add machines the way you always did. Agents discover your relay along with the others and park on whichever answers fastest.

Fastest, not yours

Agents pick the fastest healthy relay, which may not be the one you just stood up. If your machines must use only your relay, see Path B.

Path B — standalone, no control plane#

The agent and the relay are complete programs and will work with no controller at all. You give up discovery, automatic installs, credential rotation, and the dashboard; you get a system with no dependency on anyone.

The trade you are making, plainly: one shared password, held by every client, that never expires. Rotating it means touching every machine by hand.

On the relay#

openssl rand -hex 32          # this is the shared secret

Put it in .env as RELAY_TOKEN, leave every KINO_CONTROL_* variable empty, and start it behind the same nginx config as above.

On each machine#

curl -fsSL https://raw.githubusercontent.com/Samarthegde/kino-agent/main/packaging/bootstrap.sh \
  | sudo sh -s -- --relay-url wss://relay.example.com --token <the same secret>

Note the agent id it prints. You will need it, and there is nowhere to look it up later.

In Kino SSH Manager#

Settings → Agent & Cloud → Enable agent connections, then add a host in Kino Agent mode and fill in the relay URL, the agent id, and the same token by hand — the self-hosted fields, not the Kino Cloud ones.

Repeat for every machine, and again for every device you use.

Operating a relay#

  • Watch /healthz. A relay that stops answering is dropped from discovery. Agents already parked stay until their connection drops.
  • Restarts drop every parked agent. They reconnect within ~5 seconds, and in discovery mode may land somewhere else entirely. Harmless, but it is why a relay restart briefly shows machines as moving.
  • There is nothing to back up. No sessions are persisted, no database. The only file that matters is the cached public key, and a fresh enrollment code replaces it.
  • Timeouts are the usual culprit. proxy_read_timeout defaults to 60 seconds in a location; proxy_timeout to 10 minutes in a stream block. Both cut idle SSH sessions. Set both to 1h.
  • sshd is still your gate. Kino changes how a machine is reached, not who may log in.

Full configuration reference: kino-relay.

What about the control plane?#

Both paths above still leave one thing outside your network: either you use Kino Cloud (Path A), or you do without a control plane entirely and hand-manage tokens (Path B).

There is a third option for organisations that can accept neither. kino-control can be licensed to run on your own infrastructure — your servers, your database, your signing key, your identity provider in front of it, and no outbound dependency on anything of ours. That is the Enterprise plan; see the plans page.

Next#