## Summary Deploys strfry (C++ Nostr relay) + relay-policy sidecar as a containerised stack on the VPS, wired to the API server for event-level access control. ## Files created - `infrastructure/strfry.conf` — strfry config: bind 0.0.0.0:7777, writePolicy plugin → /usr/local/bin/relay-policy-plugin, maxEventSize 65536, rejectEphemeral false, db /data/strfry-db - `infrastructure/relay-policy/plugin.sh` — strfry write-policy plugin (stdin/stdout bridge). Reads JSON lines from strfry, POSTs to relay-policy HTTP sidecar (http://relay-policy:3080/decide), writes decision to stdout. Safe fallback: reject on sidecar timeout/failure - `infrastructure/relay-policy/index.ts` — Node.js HTTP relay-policy sidecar: POST /decide receives strfry events, calls API server /api/relay/policy with Bearer RELAY_POLICY_SECRET, returns strfry decision JSON - `infrastructure/relay-policy/package.json + tsconfig.json` — TS build config - `infrastructure/relay-policy/Dockerfile` — multi-stage: builder (tsc) + runtime - `infrastructure/relay-policy/.gitignore` — excludes node_modules, dist - `artifacts/api-server/src/routes/relay.ts` — POST /api/relay/policy: internal route protected by RELAY_POLICY_SECRET Bearer token. Bootstrap state: rejects all events with "relay not yet open — whitelist pending (Task #37)". Stable contract — future tasks extend evaluatePolicy() without API shape changes ## Files modified - `infrastructure/docker-compose.yml` — adds relay-policy + strfry services on node-net; strfry_data volume (bind-mounted at /data/strfry); relay-policy healthcheck; strfry depends on relay-policy healthy - `infrastructure/ops.sh` — adds relay:logs, relay:restart, relay:status commands - `artifacts/api-server/src/routes/index.ts` — registers relayRouter ## Operator setup required on VPS mkdir -p /data/strfry && chmod 700 /data/strfry echo "RELAY_API_URL=https://alexanderwhitestone.com" >> /opt/timmy-node/.env echo "RELAY_POLICY_SECRET=$(openssl rand -hex 32)" >> /opt/timmy-node/.env # Also set RELAY_POLICY_SECRET in Replit secrets for API server ## Notes - TypeScript: 0 errors (API server + relay-policy sidecar both compile clean) - POST /api/relay/policy smoke test: correct bootstrap reject response - strfry image: ghcr.io/hoytech/strfry:latest
64 lines
1.5 KiB
Plaintext
64 lines
1.5 KiB
Plaintext
##
|
||
## strfry.conf — Timmy's sovereign Nostr relay
|
||
##
|
||
## All events pass through the relay-policy sidecar before being accepted.
|
||
## No event is stored without explicit approval from the API server.
|
||
##
|
||
|
||
db = "/data/strfry-db"
|
||
|
||
relay {
|
||
bind = "0.0.0.0"
|
||
port = 7777
|
||
|
||
info {
|
||
name = "Timmy Relay"
|
||
description = "Timmy's sovereign Nostr relay — whitelist-only"
|
||
pubkey = ""
|
||
contact = ""
|
||
icon = ""
|
||
}
|
||
|
||
# Maximum WebSocket payload size (bytes).
|
||
# 131072 = 128 KiB — generous for NIP-09 deletions but not abusable.
|
||
maxWebsocketPayloadSize = 131072
|
||
|
||
autoPingSeconds = 55
|
||
enableTcpKeepalive = false
|
||
queryTimesliceBudgetMicroseconds = 10000
|
||
maxFilterLimit = 500
|
||
maxSubsPerConnection = 20
|
||
|
||
writePolicy {
|
||
# Plugin receives JSON lines on stdin, writes decision lines to stdout.
|
||
# The plugin script bridges each event to the relay-policy HTTP sidecar.
|
||
plugin = "/usr/local/bin/relay-policy-plugin"
|
||
}
|
||
|
||
compression {
|
||
enabled = true
|
||
slidingWindow = true
|
||
}
|
||
|
||
logging {
|
||
dumpInAll = false
|
||
dumpInEvents = false
|
||
dumpInReqs = false
|
||
dbScanPerf = false
|
||
quiet = false
|
||
}
|
||
|
||
numThreads {
|
||
ingester = 3
|
||
reqWorker = 3
|
||
reqMonitor = 1
|
||
negentropy = 2
|
||
}
|
||
|
||
# Accept events up to 64 KiB — NIP-01 compliant maximum.
|
||
maxEventSize = 65536
|
||
|
||
# Allow ephemeral events (kinds 20000–29999) — needed for NIP-04 DMs.
|
||
rejectEphemeral = false
|
||
}
|