NEGENTROPY_SYNC_GUIDE.md raw

Negentropy Sync Configuration Guide

ORLY implements NIP-77 negentropy-based set reconciliation for efficient relay synchronization. This guide covers configuration for all deployment modes.

How It Works

NIP-77 allows clients and relays to efficiently determine which events they have in common and which they're missing, without transferring full event lists. A client sends a NEG-OPEN message with a filter and a compact fingerprint of its local event set. The relay compares this against its own events and responds with NEG-MSG containing the diff. After one or more round-trips the reconciliation completes and the relay sends the missing EVENT messages.

ORLY supports two negentropy modes:

The mode is determined by ORLY_SYNC_TYPE:

Quick Start: Standalone Relay

The simplest setup. One env var, one process:

ORLY_NEGENTROPY_ENABLED=true ./orly

This starts the relay with an embedded negentropy handler. Clients can immediately use NEG-OPEN/NEG-MSG/NEG-CLOSE messages.

Verify it works — you should see this in the logs:

initializing embedded negentropy handler
embedded negentropy handler initialized (NIP-77 enabled)

If you don't see these lines, negentropy is not active. Check that ORLY_NEGENTROPY_ENABLED=true is actually set (not ORLY_LAUNCHER_SYNC_NEGENTROPY_ENABLED — that's a different variable for the launcher).

Verify via NIP-11 — the relay info document should list NIP-77 support:

curl -s -H "Accept: application/nostr+json" https://your-relay.example.com | jq '.supported_nips'

Quick Start: Launcher Mode (Split IPC)

When running via orly launcher, negentropy runs as a separate subprocess. The launcher automatically sets all the env vars the relay needs (ORLY_SYNC_TYPE=grpc, ORLY_NEGENTROPY_ENABLED=true, ORLY_GRPC_SYNC_NEGENTROPY=...).

You only need to tell the launcher to enable it:

ORLY_LAUNCHER_SYNC_NEGENTROPY_ENABLED=true ./orly launcher

Verify it works — you should see these log lines in order:

starting negentropy service on 127.0.0.1:50064
negentropy service is ready
connecting to gRPC negentropy server at 127.0.0.1:50064
gRPC negentropy client connected

If you see negentropy client is nil when a client sends NEG-OPEN, the gRPC connection failed. See Troubleshooting below.

Relay-to-Relay Peer Sync

To sync events with other relays in the background:

# Standalone
ORLY_NEGENTROPY_ENABLED=true \
ORLY_SYNC_NEGENTROPY_PEERS=wss://relay1.example.com,wss://relay2.example.com \
./orly

# Launcher mode
ORLY_LAUNCHER_SYNC_NEGENTROPY_ENABLED=true \
ORLY_SYNC_NEGENTROPY_PEERS=wss://relay1.example.com,wss://relay2.example.com \
./orly launcher

The relay periodically reconciles with each peer using negentropy, pulling and pushing events as needed.

Configuration Reference

Relay Variables

These control the relay's NIP-77 behavior. In launcher mode, most are set automatically by the launcher.

VariableDefaultDescription
ORLY_NEGENTROPY_ENABLEDfalseEnable NIP-77 negentropy support. Required.
ORLY_SYNC_TYPElocallocal = embedded handler, grpc = connect to gRPC service. The launcher sets this automatically.
ORLY_GRPC_SYNC_NEGENTROPY127.0.0.1:50056gRPC address of negentropy service. Only used when ORLY_SYNC_TYPE=grpc.
ORLY_GRPC_SYNC_TIMEOUT10sTimeout for gRPC connection to negentropy service.

Launcher Variables

These control whether and how the launcher spawns the negentropy subprocess.

VariableDefaultDescription
ORLY_LAUNCHER_SYNC_NEGENTROPY_ENABLEDfalseEnable negentropy subprocess in launcher mode.
ORLY_LAUNCHER_SYNC_NEGENTROPY_LISTEN127.0.0.1:50064gRPC listen address for the negentropy service.

Negentropy Service Variables

These configure the negentropy service itself (the subprocess, not the relay).

VariableDefaultDescription
ORLY_SYNC_NEGENTROPY_PEERSComma-separated WebSocket URLs of peer relays to sync with.
ORLY_SYNC_NEGENTROPY_INTERVAL60sHow often to sync with peers.
ORLY_SYNC_NEGENTROPY_FRAME_SIZE4096Negentropy protocol frame size in bytes.
ORLY_SYNC_NEGENTROPY_ID_SIZE16Event ID truncation size (bytes). 16 = first 16 bytes of 32-byte ID.
ORLY_SYNC_NEGENTROPY_SESSION_TIMEOUT5mHow long a client reconciliation session stays open before timeout.

Filter Variables

Limit which events are included in negentropy reconciliation:

VariableDefaultDescription
ORLY_SYNC_NEGENTROPY_FILTER_KINDSComma-separated kind numbers (e.g., 0,1,3,6,7).
ORLY_SYNC_NEGENTROPY_FILTER_AUTHORSComma-separated hex pubkeys.
ORLY_SYNC_NEGENTROPY_FILTER_SINCEUnix timestamp: only events after this time.
ORLY_SYNC_NEGENTROPY_FILTER_UNTILUnix timestamp: only events before this time.

Deployment Examples

systemd (Standalone)

[Unit]
Description=ORLY Nostr Relay
After=network.target

[Service]
ExecStart=/usr/local/bin/orly
Environment=ORLY_NEGENTROPY_ENABLED=true
Environment=ORLY_PORT=3334

[Install]
WantedBy=multi-user.target

systemd (Launcher with Negentropy)

[Unit]
Description=ORLY Nostr Relay (Launcher)
After=network.target

[Service]
ExecStart=/usr/local/bin/orly launcher
Environment=ORLY_LAUNCHER_SYNC_NEGENTROPY_ENABLED=true
Environment=ORLY_LAUNCHER_SYNC_NEGENTROPY_LISTEN=127.0.0.1:50064
Environment=ORLY_PORT=3334

[Install]
WantedBy=multi-user.target

Docker/Cloudron (supervisord)

[program:orly-db]
command=/app/code/orly db --driver=badger
environment=ORLY_DATA_DIR="/app/data/ORLY"
priority=15

[program:orly-negentropy]
command=/app/code/orly sync --driver=negentropy
environment=ORLY_SYNC_NEGENTROPY_LISTEN="127.0.0.1:50064",ORLY_SYNC_NEGENTROPY_DB_TYPE="grpc",ORLY_SYNC_NEGENTROPY_DB_SERVER="127.0.0.1:50051"
priority=20

[program:orly]
command=/app/code/orly
environment=ORLY_DB_TYPE="grpc",ORLY_GRPC_SERVER="127.0.0.1:50051",ORLY_NEGENTROPY_ENABLED="true",ORLY_SYNC_TYPE="grpc",ORLY_GRPC_SYNC_NEGENTROPY="127.0.0.1:50064"
priority=25

Note: when running the relay process directly (not via launcher), you must set BOTH ORLY_NEGENTROPY_ENABLED=true AND ORLY_SYNC_TYPE=grpc to use the gRPC negentropy service. Missing ORLY_SYNC_TYPE=grpc causes the relay to silently use the embedded handler instead.

strfry Interoperability

ORLY's NIP-77 implementation is compatible with strfry's sync command:

# Pull events from ORLY into strfry
strfry sync wss://your-orly-relay.com --filter '{"kinds": [0, 1, 3]}' --dir down

# Push events from strfry to ORLY
strfry sync wss://your-orly-relay.com --filter '{"kinds": [0, 1, 3]}' --dir up

# Bidirectional
strfry sync wss://your-orly-relay.com --dir both

Troubleshooting

"negentropy client is nil" in logs

The relay received a NEG-OPEN from a client but no negentropy handler was registered. The only cause is:

`ORLY_NEGENTROPY_ENABLED` is not `true`. The relay skips negentropy init entirely. In launcher mode, this means ORLY_LAUNCHER_SYNC_NEGENTROPY_ENABLED was not set — the launcher only passes ORLY_NEGENTROPY_ENABLED=true to the relay subprocess when this is enabled.

Note: gRPC connection failures and timeouts no longer cause this. If the gRPC negentropy service is unreachable, the relay automatically falls back to the embedded handler and logs a warning. NIP-77 stays enabled either way.

No log output about negentropy at startup

ORLY_NEGENTROPY_ENABLED is not true. The init function logs "negentropy NIP-77 disabled" and returns. Set it and restart.

"falling back to embedded handler" in logs

The relay tried to connect to the gRPC negentropy service but failed (connection refused or 30s timeout). It fell back to the embedded handler, so NIP-77 still works. However, you're not getting the benefits of the separate negentropy service (process isolation, independent restarts). Check that:

"embedded negentropy handler initialized" but expected gRPC mode

ORLY_SYNC_TYPE is local (the default). The relay went straight to the embedded handler without attempting gRPC. Set ORLY_SYNC_TYPE=grpc or use orly launcher which sets it automatically.

Peer sync not working

High memory during sync

Architecture

Standalone Mode

Client ──NEG-OPEN──► ┌────────────────────────────┐
Client ◄──NEG-MSG─── │       orly (relay)          │
Client ──NEG-MSG───► │                              │
Client ◄──EVENT───── │  embedded negentropy handler │
                      │           ↕                  │
                      │     badger/neo4j DB          │
                      └────────────────────────────────┘

Launcher / Split IPC Mode

Client ──NEG-OPEN──► ┌──────────┐  gRPC   ┌───────────────────┐
Client ◄──NEG-MSG─── │  orly    │ ──────► │ orly sync          │
Client ──NEG-MSG───► │ (relay)  │ ◄────── │ --driver=negentropy│
Client ◄──EVENT───── └──────────┘         └─────────┬──────────┘
                           │                          │
                           │ gRPC                     │ gRPC
                           ▼                          ▼
                      ┌──────────────────────────────────┐
                      │       orly db --driver=badger     │
                      └──────────────────────────────────┘

See Also