aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-10-25 16:00:12 -0700
committerAdam Soltys <[email protected]>2026-10-25 16:00:12 -0700
commit5f3985bfd2b7b96eea30a3253a755ab409276f00 (patch)
tree64adba99338cd92927c09d24f2ae6834e21b3d03
parent8ea5ae33f14ade28a0809a6dc267b44570c8e74f (diff)
downloadcoinosv3-server-5f3985bfd2b7b96eea30a3253a755ab409276f00.tar.gz
coinosv3-server-5f3985bfd2b7b96eea30a3253a755ab409276f00.zip
messages: messages.coinos.io, a Magnitude Relay for the app's private messages, inbox lists, calls and group chats; copies down from relay.coinos.io over NIP-77 (the strfry tunnel), never writes into it
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01QjVvE4YAcK3AGwV7kZXeN4
-rw-r--r--README.md1
-rw-r--r--compose.yml18
-rwxr-xr-xdeploy/post-receive2
-rw-r--r--messages/README.md35
-rw-r--r--messages/relay.toml41
5 files changed, 96 insertions, 1 deletions
diff --git a/README.md b/README.md
index ddbcbe2..6399e12 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,7 @@ and store its encrypted sync data.
| `names/` | **Payment-name registrar.** Gives each wallet a `[email protected]` address: BIP-353 DNS records (written through Cloudflare's API), LNURL-pay, and a BOLT 12 offer per name on the Ark server's Lightning node. Settled payments are forwarded to the name's Ark address from a small float wallet. Also serves zap receipts, point-of-sale invoices, CLINK, payment webhooks, link previews and translation. Writes are authorized with NIP-98. | `names.coinos.io` |
| `nwcpush/` | **NWC push notifier.** Watches relays for Nostr Wallet Connect requests addressed to registered wallet-service keys and wakes the device with a Web Push, so a closed wallet can answer. | (internal, behind the app) |
| `blossom/` | **Blossom server for sync envelopes.** Stores only the wallet's encrypted cross-device state blobs, which can outgrow a relay's event size. Refuses anything else. | `blossom.coinos.io` |
+| `messages/` | **Messaging relay** ([Magnitude Relay](https://github.com/VectorPrivacy/magnitude-relay)): private messages (NIP-17 gift wraps), inbox lists, calls and group chats; copies down what other clients deliver to relay.coinos.io. See `messages/README.md`. | `messages.coinos.io` |
| `feed/` | **Public feed snapshot** (`/api/feed`) and server-rendered note and profile pages. | `v3.coinos.io` |
| `live/` | **Live streams** sent from the app: the browser's recording over a WebSocket, out as HLS (a live window and the recording), for NIP-53 streams. Senders own a coinos name. | `v3.coinos.io/live/` |
| `vmedia/` | **Media helper** for the feed: video posters, H.264 fallbacks and resized pictures. | `v3.coinos.io/vmedia/` |
diff --git a/compose.yml b/compose.yml
index 123a02b..7626977 100644
--- a/compose.yml
+++ b/compose.yml
@@ -6,6 +6,7 @@
# $STATE/nwcpush/config.json $STATE/nwcpush/data/
# $STATE/blossom/data/
# $STATE/live/config.json $STATE/live/data/ (TURN key; streams and their recordings)
+# $STATE/messages/bin/magnitude-relay $STATE/messages/data/ (see messages/README.md)
services:
names:
image: ghcr.io/coinos/bun:1.4.3
@@ -80,6 +81,23 @@ services:
networks: [net]
restart: unless-stopped
+ # messages.coinos.io: Magnitude Relay (Rust) for private messages and group
+ # chats. Its binary is built on the host (messages/README.md), not in the
+ # hook; host networking so it can sync from the strfry tunnel on 127.0.0.1.
+ messages:
+ image: debian:bookworm-slim
+ container_name: messages
+ command: /usr/local/bin/magnitude-relay --config /etc/magnitude-relay/relay.toml
+ volumes:
+ - ${STATE}/messages/bin/magnitude-relay:/usr/local/bin/magnitude-relay:ro
+ - ./messages/relay.toml:/etc/magnitude-relay/relay.toml:ro
+ - ${STATE}/messages/data:/data
+ network_mode: host
+ cpus: 2
+ mem_limit: 2g
+ stop_grace_period: 20s
+ restart: unless-stopped
+
networks:
net:
external: true
diff --git a/deploy/post-receive b/deploy/post-receive
index 4bd4f7e..a0ec2b7 100755
--- a/deploy/post-receive
+++ b/deploy/post-receive
@@ -11,7 +11,7 @@ LOG=/home/adam/coinosv3-server-deploy.log
MIRROR=/home/adam/git/coinosv3-server.git
[email protected]:npub1w27mc4aa6m0ufe3xs5z3m6qyr52gc0rglept7vqlwx4xeaf72tasnqz70r/coinosv3-server.git
BARE=$(pwd)
-SERVICES="names nwcpush blossom live"
+SERVICES="names nwcpush blossom live messages"
while read -r oldrev newrev ref; do
[ "$ref" = refs/heads/prod ] || continue
diff --git a/messages/README.md b/messages/README.md
new file mode 100644
index 0000000..aa0d4da
--- /dev/null
+++ b/messages/README.md
@@ -0,0 +1,35 @@
+# messages.coinos.io
+
+The messaging relay: [Magnitude Relay](https://github.com/VectorPrivacy/magnitude-relay)
+(AGPL-3.0, Rust), run as the `messages` service in `compose.yml` with the
+settings in `relay.toml`. relay.coinos.io (strfry on desk) stays the general
+relay; this one takes the app's private messages, inbox lists, calls and
+group chats, and copies down what other clients deliver to relay.coinos.io.
+
+## Build (on cs)
+
+The binary is built from a pinned commit, outside the deploy hook (a release
+build takes minutes), and mounted into the container:
+
+```sh
+git -C ~/magnitude-relay-src fetch && git -C ~/magnitude-relay-src checkout <rev>
+docker run --rm --cpus 4 -v ~/magnitude-relay-src:/src -v ~/magnitude-build:/target \
+ -v magnitude-cargo:/usr/local/cargo/registry -w /src -e CARGO_TARGET_DIR=/target \
+ -e RELAY_BUILD_REV=<rev> rust:1-bookworm cargo build --release -p relay-server
+install -m 755 ~/magnitude-build/release/magnitude-relay $STATE/messages/bin/
+docker compose -f ~/coinosv3-server/compose.yml --env-file ~/coinosv3-state/.env up -d --force-recreate messages
+```
+
+Running now: 92f2440.
+
+## Ingress
+
+`messages.coinos.io` → `http://localhost:8794` in `~/.cloudflared/bitcoin.yml`
+(`sudo systemctl restart cloudflared-bitcoin`), DNS CNAME to the tunnel.
+
+## Operating
+
+Dashboard `https://messages.coinos.io/dashboard`, `/stats`, `/metrics`. Operator
+commands (`query`, `count`, `delete`, `backup`, `sync`) reach the running relay
+through `/data/admin.sock`:
+`docker exec messages magnitude-relay --config /etc/magnitude-relay/relay.toml count '{"kinds":[1059]}'`
diff --git a/messages/relay.toml b/messages/relay.toml
new file mode 100644
index 0000000..5d17967
--- /dev/null
+++ b/messages/relay.toml
@@ -0,0 +1,41 @@
+# messages.coinos.io: the messaging relay behind coinos v3 (Magnitude Relay,
+# github.com/VectorPrivacy/magnitude-relay). Private messages (NIP-17 gift
+# wraps), DM inbox lists, calls, Concord and White Noise (Marmot) group chats.
+# Posts, profiles' feeds, wallet sync and NWC stay on relay.coinos.io (strfry).
+# Every key is documented by `magnitude-relay init`.
+
+[relay]
+bind = "127.0.0.1:8794"
+urls = ["wss://messages.coinos.io"]
+# behind the Cloudflare tunnel every connection comes from cloudflared
+real_ip_header = "CF-Connecting-IP"
+
+[info]
+name = "coinos messages"
+description = "The messaging relay for coinos: private messages, group chats and calls."
+contact = "https://coinos.io"
+
+[policy]
+# Vector's set (gift wraps, 10050 inbox lists, Concord, calls' ephemeral
+# wraps 21059, NIP-46) plus Marmot: key packages (443 legacy, 30443), their
+# relay list (10051), welcomes (444) and group messages (445)
+kinds = "vector"
+allow_kinds = [443, 444, 445, 10051, 30443]
+# a Marmot welcome for a big group runs past 200 KB (relay.coinos.io went to 1 MB for it)
+max_event_bytes = 1048576
+
+[limits]
+max_message_bytes = 1150000
+
+[store]
+data = "/data"
+
+# Down from relay.coinos.io (strfry on desk, through cs's standing ssh tunnel
+# to it, relay-standby-tunnel.service): what other clients deliver there per
+# the old inbox lists lands here too. Down only: this relay never writes into
+# strfry (its write policy rate-limits by IP).
+[[sync]]
+url = "ws://127.0.0.1:17777"
+direction = "down"
+filter = '{"kinds":[1059,10050,443,444,445,10051,30443,13302,13303,33301,33302]}'
+reconcile_seconds = 300