Skip to content
wavemesh

Self-hosting

Install wave-mesh

A wave consists of a control server with relay and database, which you run in your own Kubernetes cluster, and the client on every device. This guide walks through both.

Not public yet

The wave-mesh source code, container images and client binaries are not public yet. Write to us if you want to run wave-mesh yourself, and we will give you access.

Request access
  1. Requirements

    A Kubernetes cluster; a single server with k3s is enough. The cluster needs an ingress controller with TLS and a public IP address that accepts UDP on port 3478 for STUN.

    Two names for the control server and the relay, for example control.example.com and relay.example.com.

    Optionally a DNS zone you own, for device names and certificates. Cloudflare, Hetzner, IONOS and INWX are supported; without credentials it still works, and you add TXT records yourself.

  2. Control server, relay and database

    Copy the prod overlay and adjust three places that belong together: the names in ingress.yaml, WAVE_BASE_URL and the STUN address in WAVE_RELAYS. Login links and redirects are built from WAVE_BASE_URL, so the name must match the ingress.

    secret.env holds the database password and connection address. If the container images are private, a dockerconfig.json with read access to GHCR goes next to it. Both files stay out of Git.

    $ cp -r deployment/server/overlays/prod deployment/server/overlays/mywave
    $ cd deployment/server/overlays/mywave
    $ cp secret.env.example secret.env # fill in, mode 600
    $ kubectl apply -k .
  3. Set the STUN address

    The STUN address in WAVE_RELAYS must be an IP address, not a name. It is known once the relay's service has a public address. Enter it and apply the overlay again.

    $ kubectl -n wave-mesh get svc wave-relay-stun
  4. Create the first account

    There is deliberately no sign-up page: the operator creates accounts. The command asks for the password twice, at least twelve characters.

    $ kubectl -n wave-mesh exec -it deploy/wave-control -- \
    bun apps/control/src/admin.ts set-password you@example.com
  5. Install the client

    The client is a single binary for Linux, macOS and Windows, each on amd64 and arm64. install copies it to /usr/local/bin, creates the group wave and starts the service and tray icon. Day-to-day use needs no sudo after that.

    On Windows, extract the ZIP archive and run wave.exe install in a console with administrator rights.

    $ tar xzf wave-linux-amd64.tar.gz
    $ sudo ./wave install
  6. Log in and connect

    wave login names your control server and prints a link to log in. Then wave up connects, and wave status shows live which path reaches each device. A device can join as many waves as you like.

    $ wave login https://control.example.com
    $ wave up
    $ wave status
  7. Names and certificatesoptional

    Give a wave a DNS suffix you own, and its devices get names under it and, if you like, Let's Encrypt certificates. The provider is set once per wave; after that wave cert fetches the certificate on the device, and the service renews it on its own. The private key never leaves the device.

    For a provider token the server needs WAVE_DNS_SECRET (32 bytes, base64) to store the token encrypted. The default is Let's Encrypt's staging directory; real certificates come with WAVE_ACME_DIRECTORY.

    With the manual provider this works with any host, but then every renewal also needs a person to add the TXT record.

    $ kubectl -n wave-mesh exec -it deploy/wave-control -- \
    bun apps/control/src/admin.ts set-dns-provider mywave cloudflare
    $ wave cert --hook 'systemctl reload caddy'
  8. Services from a Kubernetes clusteroptional

    A connector brings a cluster's internal services into the wave without an inbound port. It joins with a reusable key. After that a plain Ingress with ingressClassName: wave is enough, and every device in the wave reaches the service by its name.

    $ kubectl -n wave-mesh exec deploy/wave-control -- \
    bun apps/control/src/admin.ts auth-key mywave connector --reusable
    $ cd deployment/cluster/overlays/example
    $ cp secret.env.example secret.env # paste the key
    $ kubectl apply -k .
  9. Updates

    The service updates itself: the control server offers new releases, the client installs only what is signed with the release key, and rolls back on its own if the new build cannot reach a server. If you don't want to wait, install right away.

    $ wave version
    $ wave update

Rather have it set up?

We install wave-mesh in your company's cloud, connect clusters and devices and, if you like, take care of updates and operations.

See pricing