Run a MeshChat relay node.

A relay is the volunteer infrastructure behind the MeshChat peer-to-peer messenger: it stores messages for offline users, routes them across the DHT, relays calls through NAT (TURN), keeps encrypted media, and forwards group calls. Everything stays end-to-end encrypted — a relay only ever sees opaque blobs.

install on a blank VM — needs only a public IPv4

$ curl -fsSL https://relay-dist.dev.4qube.ru/bootstrap.sh \
    | PUBLIC_HOST=<your-numeric-ip> bash

Installs Docker, unpacks into a persistent ~/meshchat-relay, loads prebuilt images, and starts the stack. Re-run anytime to update — your data/ and .env are preserved.

01

Before you start

Open / forward to the VM

PortService
8767/udpTURN controlrequired for calls
49160–49200/udpTURN media relayrequired for calls
8766/tcplibp2p / DHTonly when federating
8765/tcpWS APIbehind your TLS proxy
02

What lands on the server

Everything lives in one persistent directory:

~/meshchat-relay/
  docker-compose.yml          # image-only
  .env                        # PUBLIC_HOST, ADMIN_TOKEN, FCM_PROJECT_ID
  pushproxy-allowlist.json    # authorised relay node pubkey(s)
  data/                       # ALL state — bbolt DBs + node keys
!

Back up data/. It holds the bbolt databases plus node_ed25519.key (push-signing identity) and libp2p_ed25519.key (DHT peer id).

If those keys are lost the node gets a new identity — never delete this directory.

03

Reach the admin UI

The operator dashboard binds to 127.0.0.1:8768 — loopback only, never published. Set ADMIN_TOKEN in .env to enable it, then tunnel in over SSH:

$ ssh -L 8768:localhost:8768 <vm>
# then open http://localhost:8768
04

Enable Android push

The bundle ships the pushproxy bridge but leaves it off until you supply an FCM service account — a per-host secret that is never baked into the distribution. The relay runs fine without it; only background wake-ups for the Android app are skipped. To turn push on:

  1. Get the FCM service account

    In the Firebase console for your project: ⚙ Project settings → Service accounts → Generate new private key. This downloads a JSON file.

  2. Install it on the VM as a root-only secret
    $ sudo install -m600 -o root -g root <downloaded>.json /etc/meshchat/fcm-sa.json
  3. Set your Firebase project id in .env
    FCM_PROJECT_ID=<your-firebase-project-id>
  4. Authorise this relay in the allowlist

    Read the node's signer pubkey from the log and add it. An empty allowlist blocks every wake.

    $ docker compose logs relay | grep 'node signer pubkey'
    $ echo '["<that-pubkey>"]' > ~/meshchat-relay/pushproxy-allowlist.json
  5. Re-run the installer

    It detects the SA file + project id and starts pushproxy automatically.

    $ cd ~/meshchat-relay && ./install.sh
    # or, directly:
    $ docker compose --profile push up -d
i

pushproxy and the admin UI both bind to loopback only and are reached via the relay / an SSH tunnel — they are never exposed to the internet.

05

Update or re-provision

Re-running bootstrap pulls the latest bundle and recreates the containers while keeping data/ and .env — safe to run on a live node:

$ curl -fsSL https://relay-dist.dev.4qube.ru/bootstrap.sh | bash

Bundle: relay-deploy.zip · script: bootstrap.sh