Files
nosterm-client/README.md
T
Robert Goodall cd2b900639
ci / build (push) Successful in 1m3s
ci / image (push) Successful in 41s
Initial commit: Nosterm client (terminal-style Nostr chat SPA)
2026-07-24 13:47:53 -04:00

4.7 KiB

Nosterm

Nosterm — a terminal-style Nostr chat application

A terminal-style Nostr chat client.

The Nosterm web client: a terminal-style Nostr chat SPA built with SvelteKit and served as static files by Caddy. Nostr is a client-side protocol, so there is no application backend here — the browser talks directly to relays over WebSocket. Run a relay from the companion nosterm-relay repository if you want your own home relay.

This is the public, contribution-focused repository for the Nosterm client. Open a pull request against main — see CONTRIBUTING.md. Each merge to main builds the container image and publishes it to ECR Public for anonymous pulls (see Deploy).

Layout

nosterm-client/
  src/                  # SvelteKit source (components, stores, nostr, commands…)
  static/               # static assets
  Dockerfile            # build the SPA → serve with Caddy
  Caddyfile             # static file server + security headers + optional /relay proxy
  docker-compose.yml    # one-command deploy on port 8080
  .env.example          # copy to .env and configure
  package.json          # dev/build/test scripts

Develop

npm install
npm run dev            # vite dev server
npm run check          # svelte-check (type-check)
npm run lint           # prettier --check + eslint
npm test               # vitest
npm run test:e2e       # playwright
npm run build          # static build → ./build

Deploy

cp .env.example .env          # then set NOSTERM_DEFAULT_RELAYS at minimum
docker compose up -d --build

The client is then served at http://localhost:8080.

To run the prebuilt public image with your own relays — no rebuild, no AWS account (anonymous pull from ECR Public):

docker run -p 8080:80 \
  -e NOSTERM_DEFAULT_RELAYS=wss://relay.example.com \
  public.ecr.aws/k3k1z1x5/nosterm:latest

NOSTERM_DEFAULT_RELAYS accepts a comma-separated list. On startup the container's entrypoint writes it to /config.json, which the SPA fetches on load — so one shared image serves every deployment with different relays.

Configuration

Relays are configured at runtime (NOSTERM_DEFAULT_RELAYS), so a single prebuilt image works for any deployment. The remaining PUBLIC_* tunables are build-time args baked into the browser bundle (client-visible, never secrets) — change one → rebuild the image.

Runtime (set on the running container, no rebuild):

Variable Default Purpose
NOSTERM_DEFAULT_RELAYS empty Comma-separated relay WebSocket URLs to preload
RELAY_UPSTREAM relay:3334 Upstream for Caddy's optional /relay reverse-proxy (below)

Build-time (baked into the bundle; rebuild to change):

Variable Default Purpose
PUBLIC_DEFAULT_RELAYS empty Fallback relays when no runtime config is set
PUBLIC_DEFAULT_THEME nord Theme applied before the user picks one
PUBLIC_MAX_TERMINAL_ENTRIES 1000 Terminal entries kept in memory / rendered
PUBLIC_MAX_MESSAGE_LENGTH 2000 Max outbound message length (characters)
PUBLIC_MAX_CACHED_MESSAGES_PER_ROOM 500 Messages retained per room in IndexedDB

Talking to a relay

The client connects directly to whatever relays are configured in NOSTERM_DEFAULT_RELAYS (and any the user adds at runtime). Two common setups:

  • External relay — set NOSTERM_DEFAULT_RELAYS=wss://relay.example.com. You can delete the handle /relay* block from the Caddyfile.
  • Same-origin home relay — run nosterm-relay, set NOSTERM_DEFAULT_RELAYS=ws://localhost:8080/relay (or wss://… behind TLS), and set RELAY_UPSTREAM to the relay's address so Caddy proxies /relay to it. Put both services on a shared Docker network for name resolution.

Production TLS

For a real domain, edit the Caddyfile: replace :80 with your hostname (e.g. nosterm.example.com { … }) and Caddy will obtain and renew a certificate automatically. Expose ports 80 and 443 in docker-compose.yml.