Skip to content

Self-hosting Armada

Armada communities already run without a host. This is how to own the rest — the app, the relays, and the calls.

No server owns your community. It travels as ordinary Nostr events, sealed, over relays that cannot read them — so self-hosting Armada means the app and, if you want them, the pipes. Never the community itself.

The client is a static site, and the repo ships a Dockerfile that builds it and serves it with nginx.

Terminal window
git clone nostr://soapbox.pub/relay.ngit.dev/armada
cd armada
docker build -t armada .
docker run -p 8080:80 armada

That address is a Nostr remote, so git clone needs ngit installed once. Put your own TLS in front of the container — microphones only work in a secure context, so voice needs a real certificate anywhere but localhost.

Settings bake in at build time, as Docker build args.

Build arg What it does
VITE_APP_NAME What the app calls itself.
VITE_APP_RELAYS The relays a fresh user starts with. Editable in Settings.
VITE_SEARCH_RELAYS Where search queries go.
VITE_APP_BLOSSOM_SERVERS Default media upload servers.
VITE_CONCORD_AV_SERVERS Voice token brokers.
Terminal window
docker build \
--build-arg VITE_APP_NAME="Example Chat" \
--build-arg VITE_APP_RELAYS="wss://relay.example.com" \
-t example-chat .
  • Logopublic/logo.svg
  • Social cardpublic/og.png
  • ColorsbuiltinThemes in src/themes.ts

A background, a text color and a primary. Every other token — surfaces, borders, muted text — is derived from those, so retinting is three values, not a stylesheet.

You probably do not need your own. Any Nostr relay carries an Armada community, and nostr.watch lists hundreds run by people who have never heard of yours — spread across a few, one going down doesn’t take the community with it.

If you want one anyway, Soapbox runs ditto-relay: AGPL-3.0, written for Bun, storing events in OpenSearch.

The one piece that has to be a real server, because audio cannot travel the way messages do. It is stock LiveKit plus a small token broker that checks you hold the key to a channel and issues a ticket for one room — it never learns which community that is, and the audio is encrypted end to end anyway.

Terminal window
git clone nostr://chad@chadwick.site/relay.ngit.dev/armada-av
cd armada-av/deploy/single
cp .env.example .env
docker compose up -d

Set AV_DOMAIN to the name people actually reach, and a LiveKit key pair from docker run --rm livekit/livekit-server generate-keys. Open 80, 443, UDP 7882 and TCP 7881. Then, in Armada: Settings → Voice → https://av.example.com.

Nothing about a backend is compiled into the Android or desktop builds. Your users install the normal app, add your relay in Settings, and they are on your stack.

One catch: an invite link on your domain opens a browser rather than jumping into the app, because the installed app only claims links on armada.buzz. It costs your members one extra tap.

A client on your domain, relays you administer, calls through your own box — or just the client, pointed at relays that already exist, for an afternoon of work and no database to babysit.

$ own the whole road