Skip to content

Monitor Service

The Monitor service continuously evaluates relay health by testing NIP-11 information documents and NIP-66 capabilities. It measures round-trip times and tracks relay status over time.

PropertyValue
Service Namemonitor
LifecycleContinuous (run_forever)
Default Interval3600 seconds (1 hour)
DependenciesPostgreSQL, Tor (optional)
Configurationyaml/services/monitor.yaml

Each cycle, the Monitor:

  1. Select Relays: Query relays needing health check (based on min_age_since_check)
  2. Connect: Establish WebSocket connections (via Tor for .onion)
  3. Fetch NIP-11: Request relay information document
  4. Test NIP-66: Test capabilities (open, read, write)
  5. Measure RTT: Record round-trip times for each operation
  6. Deduplicate: Hash NIP-11/NIP-66 content for storage efficiency
  7. Store Results: Insert metadata snapshots into database
yaml/services/monitor.yaml
# Cycle interval
interval: 3600.0 # 1 hour (minimum: 60.0)
# Tor proxy for .onion relays
tor:
enabled: true
host: "tor" # Docker service name
port: 9050
# Nostr keys for NIP-66 write tests
keys:
public_key: "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"
# private_key loaded from MONITOR_PRIVATE_KEY environment variable
# Timeouts for relay checks
timeouts:
clearnet: 30.0 # seconds (5.0-120.0)
tor: 60.0 # seconds (10.0-180.0)
# Concurrency settings
concurrency:
max_parallel: 50 # concurrent checks (1-500)
batch_size: 50 # relays per DB batch (1-500)
# Relay selection criteria
selection:
min_age_since_check: 3600 # seconds since last check (≥0)
FieldTypeDefaultRangeDescription
intervalfloat3600.0≥60.0Seconds between cycles
tor.enabledbooltrue-Enable Tor proxy
tor.hoststring127.0.0.1-Tor SOCKS5 host
tor.portint90501-65535Tor SOCKS5 port
timeouts.clearnetfloat30.05.0-120.0Clearnet timeout
timeouts.torfloat60.010.0-180.0Tor timeout
concurrency.max_parallelint501-500Concurrent checks
concurrency.batch_sizeint501-500DB batch size

The Monitor fetches the NIP-11 relay information document:

GET / HTTP/1.1
Host: relay.example.com
Accept: application/nostr+json

Captured fields:

FieldDescription
nameRelay name
descriptionRelay description
pubkeyOperator’s public key
contactContact information
supported_nipsArray of supported NIPs
softwareSoftware name/URL
versionSoftware version
limitationRelay limitations
privacy_policyPrivacy policy URL
terms_of_serviceTerms of service URL

The Monitor tests NIP-66 relay capabilities:

Can we establish a WebSocket connection?

→ WebSocket CONNECT wss://relay.example.com
← Connection established
✓ openable = true, rtt_open = 142ms

Does the relay respond to REQ messages?

→ ["REQ", "test", {"limit": 1}]
← ["EOSE", "test"]
✓ readable = true, rtt_read = 89ms

Does the relay accept EVENT messages?

→ ["EVENT", {...signed_event...}]
← ["OK", "event_id", true, ""]
✓ writable = true, rtt_write = 234ms

Monitor automatically routes .onion URLs through Tor:

if ".onion" in relay_url:
connector = ProxyConnector.from_url(f"socks5://{tor_host}:{tor_port}")
timeout = config.timeouts.tor
else:
connector = None
timeout = config.timeouts.clearnet

Benefits:

  • Full support for Tor-only relays
  • Separate, longer timeouts for Tor
  • Configurable Tor proxy settings

NIP-11 and NIP-66 documents are stored using content-addressed deduplication:

  1. Compute Hash: SHA-256 of the document content
  2. Check Existence: Does this hash already exist?
  3. Store or Reuse: Insert new record or reference existing
-- nip11 table
CREATE TABLE nip11 (
id BYTEA PRIMARY KEY, -- SHA-256 hash
name TEXT,
description TEXT,
...
);
-- relay_metadata references by hash
CREATE TABLE relay_metadata (
relay_url TEXT,
generated_at BIGINT,
nip11_id BYTEA REFERENCES nip11(id),
nip66_id BYTEA REFERENCES nip66(id),
...
);

This means:

  • Identical NIP-11 documents share one record
  • Storage efficiency for relays with static metadata
  • Historical tracking via relay_metadata timestamps
monitor:
command: ["python", "-m", "services", "monitor"]
environment:
- MONITOR_PRIVATE_KEY=${MONITOR_PRIVATE_KEY} # Optional
restart: unless-stopped
Terminal window
cd implementations/bigbrotr
python -m services monitor
Terminal window
MONITOR_PRIVATE_KEY=<hex_private_key> python -m services monitor
Terminal window
python -m services monitor --log-level DEBUG

Typical Monitor output:

INFO monitor: cycle_started
INFO monitor: relays_selected count=1250
INFO monitor: checking_relays batch=1 total=25
INFO monitor: relay_checked url=wss://relay.damus.io openable=true readable=true writable=true
INFO monitor: relay_checked url=wss://nos.lol openable=true readable=true writable=false
INFO monitor: batch_completed batch=1 checked=50 success=48 failed=2
...
INFO monitor: cycle_completed duration=245.6 checked=1250 success=1180 failed=70
INFO monitor: waiting seconds=3600
SELECT
relay_url,
nip66_openable,
nip66_readable,
nip66_writable,
nip66_rtt_open,
nip66_rtt_read,
nip11_name,
nip11_software
FROM relay_metadata_latest
WHERE nip66_openable = true
ORDER BY nip66_rtt_open ASC
LIMIT 20;
SELECT
DATE(TO_TIMESTAMP(generated_at)) as date,
COUNT(*) FILTER (WHERE n66.openable) as openable,
COUNT(*) FILTER (WHERE n66.readable) as readable,
COUNT(*) FILTER (WHERE n66.writable) as writable
FROM relay_metadata rm
JOIN nip66 n66 ON rm.nip66_id = n66.id
GROUP BY DATE(TO_TIMESTAMP(generated_at))
ORDER BY date DESC;
SELECT
n11.software,
COUNT(DISTINCT rm.relay_url) as relay_count
FROM relay_metadata_latest rml
JOIN nip11 n11 ON rml.nip11_id = n11.id
WHERE n11.software IS NOT NULL
GROUP BY n11.software
ORDER BY relay_count DESC;
WARNING monitor: relay_timeout url=wss://slow-relay.example.com timeout=30.0

Relay is marked as not openable; continues with other relays.

WARNING monitor: nip11_invalid url=wss://relay.example.com error=Invalid JSON

NIP-11 fields are set to NULL; NIP-66 tests still attempted.

ERROR monitor: tor_unavailable url=wss://xyz.onion error=Connection refused

Tor relays fail if Tor proxy is not running.

For large deployments with many relays:

concurrency:
max_parallel: 100 # Increase parallelism
batch_size: 100 # Larger DB batches

For high-latency networks:

timeouts:
clearnet: 60.0
tor: 120.0

For limited resources:

concurrency:
max_parallel: 10
batch_size: 25