2025-10-31 11:10:53 -04:00
2025-10-31 10:39:06 -04:00
2025-10-31 10:39:06 -04:00
2025-09-03 20:39:06 -04:00
2025-10-05 14:35:09 -04:00
2025-10-30 06:52:05 -04:00
2025-10-31 11:08:18 -04:00
2025-10-30 07:06:48 -04:00
2025-10-05 14:35:09 -04:00
2025-10-18 14:48:16 -04:00
2025-10-31 11:06:27 -04:00
2025-10-31 11:08:18 -04:00
2025-10-03 04:52:40 -04:00
2025-10-30 06:52:05 -04:00
2025-10-30 06:52:05 -04:00
2025-10-05 14:35:09 -04:00
2025-10-05 14:35:09 -04:00
2025-10-31 10:39:06 -04:00

C-Nostr Relay

A high-performance Nostr relay implemented in C with SQLite backend, featuring nostr event-based management.

Supported NIPs

  • NIP-01: Basic protocol flow implementation
  • NIP-09: Event deletion
  • NIP-11: Relay information document
  • NIP-13: Proof of Work
  • NIP-15: End of Stored Events Notice
  • NIP-20: Command Results
  • NIP-33: Parameterized Replaceable Events
  • NIP-40: Expiration Timestamp
  • NIP-42: Authentication of clients to relays
  • NIP-45: Counting results
  • NIP-50: Keywords filter
  • NIP-70: Protected Events

Quick Start

Get your C-Relay up and running in minutes with a static binary (no dependencies required):

1. Download Static Binary

Download the latest static release from the releases page:

# Static binary - works on all Linux distributions (no dependencies)
wget https://git.laantungir.net/laantungir/c-relay/releases/download/v0.6.0/c-relay-v0.6.0-linux-x86_64-static
chmod +x c-relay-v0.6.0-linux-x86_64-static
mv c-relay-v0.6.0-linux-x86_64-static c-relay

2. Start the Relay

Simply run the binary - no configuration files needed:

./c-relay

On first startup, you'll see:

  • Admin Private Key: Save this securely! You'll need it for administration
  • Relay Public Key: Your relay's identity on the Nostr network
  • Port Information: Default is 8888, or the next available port

3. Access the Web Interface

Open your browser and navigate to:

http://localhost:8888/api/

The web interface provides:

  • Real-time configuration management
  • Database statistics dashboard
  • Auth rules management
  • Secure admin authentication with your Nostr identity

4. Test Your Relay

Test basic connectivity:

# Test WebSocket connection
curl -H "Accept: application/nostr+json" http://localhost:8888

# Test with a Nostr client
# Add ws://localhost:8888 to your client's relay list

5. Configure Your Relay (Optional)

Use the web interface or send admin commands to customize:

  • Relay name and description
  • Authentication rules (whitelist/blacklist)
  • Connection limits
  • Proof-of-work requirements

That's it! Your relay is now running with zero configuration required. The event-based configuration system means you can adjust all settings through the web interface or admin API without editing config files.

Web Admin Interface

C-Relay includes a built-in web-based administration interface accessible at http://localhost:8888/api/. The interface provides:

  • Real-time Configuration Management: View and edit all relay settings through a web UI
  • Database Statistics Dashboard: Monitor event counts, storage usage, and performance metrics
  • Auth Rules Management: Configure whitelist/blacklist rules for pubkeys
  • NIP-42 Authentication: Secure access using your Nostr identity
  • Event-Based Updates: All changes are applied as cryptographically signed Nostr events

The web interface serves embedded static files with no external dependencies and includes proper CORS headers for browser compatibility.

Administrator API

C-Relay uses an innovative event-based administration system where all configuration and management commands are sent as signed Nostr events using the admin private key generated during first startup. All admin commands use NIP-44 encrypted command arrays for security and compatibility.

Authentication

All admin commands require signing with the admin private key displayed during first-time startup. Save this key securely - it cannot be recovered and is needed for all administrative operations.

Event Structure

All admin commands use the same unified event structure with NIP-44 encrypted content:

Admin Command Event:

{
  "id": "event_id",
  "pubkey": "admin_public_key",
  "created_at": 1234567890,
  "kind": 23456,
  "content": "AqHBUgcM7dXFYLQuDVzGwMST1G8jtWYyVvYxXhVGEu4nAb4LVw...",
  "tags": [
    ["p", "relay_public_key"]
  ],
  "sig": "event_signature"
}

The content field contains a NIP-44 encrypted JSON array representing the command.

Admin Response Event:

["EVENT", "temp_sub_id", {
  "id": "response_event_id",
  "pubkey": "relay_public_key",
  "created_at": 1234567890,
  "kind": 23457,
  "content": "BpKCVhfN8eYtRmPqSvWxZnMkL2gHjUiOp3rTyEwQaS5dFg...",
  "tags": [
    ["p", "admin_public_key"]
  ],
  "sig": "response_event_signature"
}]

The content field contains a NIP-44 encrypted JSON response object.

Admin Commands

All commands are sent as NIP-44 encrypted JSON arrays in the event content. The following table lists all available commands:

Command Type Command Format Description
Configuration Management
config_update ["config_update", [{"key": "auth_enabled", "value": "true", "data_type": "boolean", "category": "auth"}, {"key": "relay_description", "value": "My Relay", "data_type": "string", "category": "relay"}, ...]] Update relay configuration parameters (supports multiple updates)
config_query ["config_query", "all"] Query all configuration parameters
Auth Rules Management
auth_add_blacklist ["blacklist", "pubkey", "abc123..."] Add pubkey to blacklist
auth_add_whitelist ["whitelist", "pubkey", "def456..."] Add pubkey to whitelist
auth_delete_rule ["delete_auth_rule", "blacklist", "pubkey", "abc123..."] Delete specific auth rule
auth_query_all ["auth_query", "all"] Query all auth rules
auth_query_type ["auth_query", "whitelist"] Query specific rule type
auth_query_pattern ["auth_query", "pattern", "abc123..."] Query specific pattern
System Commands
system_clear_auth ["system_command", "clear_all_auth_rules"] Clear all auth rules
system_status ["system_command", "system_status"] Get system status
stats_query ["stats_query"] Get comprehensive database statistics
Database Queries
sql_query ["sql_query", "SELECT * FROM events LIMIT 10"] Execute read-only SQL query against relay database

Available Configuration Keys

Basic Relay Settings:

  • relay_name: Relay name (displayed in NIP-11)
  • relay_description: Relay description text
  • relay_contact: Contact information
  • relay_software: Software URL
  • relay_version: Software version
  • supported_nips: Comma-separated list of supported NIP numbers (e.g., "1,2,4,9,11,12,13,15,16,20,22,33,40,42")
  • language_tags: Comma-separated list of supported language tags (e.g., "en,es,fr" or "*" for all)
  • relay_countries: Comma-separated list of supported country codes (e.g., "US,CA,MX" or "*" for all)
  • posting_policy: Posting policy URL or text
  • payments_url: Payment URL for premium features
  • max_connections: Maximum concurrent connections
  • max_subscriptions_per_client: Max subscriptions per client
  • max_event_tags: Maximum tags per event
  • max_content_length: Maximum event content length

Authentication & Access Control:

  • auth_enabled: Enable whitelist/blacklist auth rules (true/false)
  • nip42_auth_required: Enable NIP-42 cryptographic authentication (true/false)
  • nip42_auth_required_kinds: Event kinds requiring NIP-42 auth (comma-separated)
  • nip42_challenge_timeout: NIP-42 challenge expiration seconds

Proof of Work & Validation:

  • pow_min_difficulty: Minimum proof-of-work difficulty
  • nip40_expiration_enabled: Enable event expiration (true/false)

Monitoring Settings:

  • kind_24567_reporting_throttle_sec: Minimum seconds between monitoring events (default: 5)

Dynamic Configuration Updates

C-Relay supports dynamic configuration updates without requiring a restart for most settings. Configuration parameters are categorized as either dynamic (can be updated immediately) or restart-required (require relay restart to take effect).

Dynamic Configuration Parameters (No Restart Required):

  • All relay information (NIP-11) settings: relay_name, relay_description, relay_contact, relay_software, relay_version, supported_nips, language_tags, relay_countries, posting_policy, payments_url
  • Authentication settings: auth_enabled, nip42_auth_required, nip42_auth_required_kinds, nip42_challenge_timeout
  • Subscription limits: max_subscriptions_per_client, max_total_subscriptions
  • Event validation limits: max_event_tags, max_content_length, max_message_length
  • Proof of Work settings: pow_min_difficulty, pow_mode
  • Event expiration settings: nip40_expiration_enabled, nip40_expiration_strict, nip40_expiration_filter, nip40_expiration_grace_period

Restart-Required Configuration Parameters:

  • Connection settings: max_connections, relay_port
  • Database and core system settings

When updating configuration, the admin API response will indicate whether a restart is required for each parameter. Dynamic updates take effect immediately and are reflected in NIP-11 relay information documents without restart.

Response Format

All admin commands return signed EVENT responses via WebSocket following standard Nostr protocol. Responses use JSON content with structured data.

Response Examples

Success Response:

["EVENT", "temp_sub_id", {
  "id": "response_event_id",
  "pubkey": "relay_public_key",
  "created_at": 1234567890,
  "kind": 23457,
  "content": "nip44 encrypted:{\"query_type\": \"config_update\", \"status\": \"success\", \"message\": \"Operation completed successfully\", \"timestamp\": 1234567890}",
  "tags": [
    ["p", "admin_public_key"]
  ],
  "sig": "response_event_signature"
}]

Error Response:

["EVENT", "temp_sub_id", {
  "id": "response_event_id",
  "pubkey": "relay_public_key",
  "created_at": 1234567890,
  "kind": 23457,
  "content": "nip44 encrypted:{\"query_type\": \"config_update\", \"status\": \"error\", \"error\": \"invalid configuration value\", \"timestamp\": 1234567890}",
  "tags": [
    ["p", "admin_public_key"]
  ],
  "sig": "response_event_signature"
}]

Auth Rules Query Response:

["EVENT", "temp_sub_id", {
  "id": "response_event_id",
  "pubkey": "relay_public_key",
  "created_at": 1234567890,
  "kind": 23457,
  "content": "nip44 encrypted:{\"query_type\": \"auth_rules_all\", \"total_results\": 2, \"timestamp\": 1234567890, \"data\": [{\"rule_type\": \"blacklist\", \"pattern_type\": \"pubkey\", \"pattern_value\": \"abc123...\", \"action\": \"allow\"}]}",
  "tags": [
    ["p", "admin_public_key"]
  ],
  "sig": "response_event_signature"
}]

Configuration Query Response:

["EVENT", "temp_sub_id", {
  "id": "response_event_id",
  "pubkey": "relay_public_key",
  "created_at": 1234567890,
  "kind": 23457,
  "content": "nip44 encrypted:{\"query_type\": \"config_all\", \"total_results\": 27, \"timestamp\": 1234567890, \"data\": [{\"key\": \"auth_enabled\", \"value\": \"false\", \"data_type\": \"boolean\", \"category\": \"auth\", \"description\": \"Enable NIP-42 authentication\"}, {\"key\": \"relay_description\", \"value\": \"My Relay\", \"data_type\": \"string\", \"category\": \"relay\", \"description\": \"Relay description text\"}]}",
  "tags": [
    ["p", "admin_public_key"]
  ],
  "sig": "response_event_signature"
}]

Configuration Update Success Response:

["EVENT", "temp_sub_id", {
  "id": "response_event_id",
  "pubkey": "relay_public_key",
  "created_at": 1234567890,
  "kind": 23457,
  "content": "nip44 encrypted:{\"query_type\": \"config_update\", \"total_results\": 2, \"timestamp\": 1234567890, \"status\": \"success\", \"data\": [{\"key\": \"auth_enabled\", \"value\": \"true\", \"status\": \"updated\"}, {\"key\": \"relay_description\", \"value\": \"My Updated Relay\", \"status\": \"updated\"}]}",
  "tags": [
    ["p", "admin_public_key"]
  ],
  "sig": "response_event_signature"
}]

Configuration Update Error Response:

["EVENT", "temp_sub_id", {
  "id": "response_event_id",
  "pubkey": "relay_public_key",
  "created_at": 1234567890,
  "kind": 23457,
  "content": "nip44 encrypted:{\"query_type\": \"config_update\", \"status\": \"error\", \"error\": \"field validation failed: invalid port number '99999' (must be 1-65535)\", \"timestamp\": 1234567890}",
  "tags": [
    ["p", "admin_public_key"]
  ],
  "sig": "response_event_signature"
}]

Database Statistics Query Response:

["EVENT", "temp_sub_id", {
  "id": "response_event_id",
  "pubkey": "relay_public_key",
  "created_at": 1234567890,
  "kind": 23457,
  "content": "nip44 encrypted:{\"query_type\": \"stats_query\", \"timestamp\": 1234567890, \"database_size_bytes\": 1048576, \"total_events\": 15432, \"database_created_at\": 1234567800, \"latest_event_at\": 1234567890, \"event_kinds\": [{\"kind\": 1, \"count\": 12000, \"percentage\": 77.8}, {\"kind\": 0, \"count\": 2500, \"percentage\": 16.2}], \"time_stats\": {\"total\": 15432, \"last_24h\": 234, \"last_7d\": 1456, \"last_30d\": 5432}, \"top_pubkeys\": [{\"pubkey\": \"abc123...\", \"event_count\": 1234, \"percentage\": 8.0}, {\"pubkey\": \"def456...\", \"event_count\": 987, \"percentage\": 6.4}]}",
  "tags": [
    ["p", "admin_public_key"]
  ],
  "sig": "response_event_signature"
}]

SQL Query Response:

["EVENT", "temp_sub_id", {
  "id": "response_event_id",
  "pubkey": "relay_public_key",
  "created_at": 1234567890,
  "kind": 23457,
  "content": "nip44 encrypted:{\"query_type\": \"sql_query\", \"request_id\": \"request_event_id\", \"timestamp\": 1234567890, \"query\": \"SELECT * FROM events LIMIT 10\", \"execution_time_ms\": 45, \"row_count\": 10, \"columns\": [\"id\", \"pubkey\", \"created_at\", \"kind\", \"content\"], \"rows\": [[\"abc123...\", \"def456...\", 1234567890, 1, \"Hello world\"], ...]}",
  "tags": [
    ["p", "admin_public_key"],
    ["e", "request_event_id"]
  ],
  "sig": "response_event_signature"
}]

SQL Query Command

The sql_query command allows administrators to execute read-only SQL queries against the relay database. This provides powerful analytics and debugging capabilities through the admin API.

Request/Response Correlation:

  • Each response includes the request event ID in both the tags array (["e", "request_event_id"]) and the decrypted content ("request_id": "request_event_id")
  • This allows proper correlation when multiple queries are submitted concurrently
  • Frontend can track pending queries and match responses to requests

Security Features:

  • Only SELECT statements allowed (INSERT, UPDATE, DELETE, DROP, etc. are blocked)
  • Query timeout: 5 seconds (configurable)
  • Result row limit: 1000 rows (configurable)
  • All queries logged with execution time

Available Tables and Views:

  • events - All Nostr events
  • config - Configuration parameters
  • auth_rules - Authentication rules
  • subscription_events - Subscription lifecycle log
  • event_broadcasts - Event broadcast log
  • recent_events - Last 1000 events (view)
  • event_stats - Event statistics by type (view)
  • subscription_analytics - Subscription metrics (view)
  • active_subscriptions_log - Currently active subscriptions (view)
  • event_kinds_view - Event distribution by kind (view)
  • top_pubkeys_view - Top 10 pubkeys by event count (view)
  • time_stats_view - Time-based statistics (view)

Example Queries:

-- Recent events
SELECT id, pubkey, created_at, kind FROM events ORDER BY created_at DESC LIMIT 20

-- Event distribution by kind
SELECT * FROM event_kinds_view ORDER BY count DESC

-- Active subscriptions
SELECT * FROM active_subscriptions_log ORDER BY created_at DESC

-- Database statistics
SELECT
  (SELECT COUNT(*) FROM events) as total_events,
  (SELECT COUNT(*) FROM subscription_events) as total_subscriptions

Real-time Monitoring System

C-Relay includes a subscription-based monitoring system that broadcasts real-time relay statistics using ephemeral events (kind 24567).

Activation

The monitoring system activates automatically when clients subscribe to kind 24567 events:

["REQ", "monitoring-sub", {"kinds": [24567]}]

For specific monitoring types, use d-tag filters:

["REQ", "event-kinds-sub", {"kinds": [24567], "#d": ["event_kinds"]}]
["REQ", "time-stats-sub", {"kinds": [24567], "#d": ["time_stats"]}]
["REQ", "top-pubkeys-sub", {"kinds": [24567], "#d": ["top_pubkeys"]}]

When no subscriptions exist, monitoring is dormant to conserve resources.

Monitoring Event Types

Type d Tag Description
Event Distribution event_kinds Event count by kind with percentages
Time Statistics time_stats Events in last 24h, 7d, 30d
Top Publishers top_pubkeys Top 10 pubkeys by event count
Active Subscriptions active_subscriptions Current subscription details (admin only)
Subscription Details subscription_details Detailed subscription info (admin only)
CPU Metrics cpu_metrics Process CPU and memory usage

Event Structure

{
  "kind": 24567,
  "pubkey": "<relay_pubkey>",
  "created_at": <timestamp>,
  "content": "{\"data_type\":\"event_kinds\",\"timestamp\":1234567890,...}",
  "tags": [
    ["d", "event_kinds"]
  ]
}

Configuration

  • kind_24567_reporting_throttle_sec: Minimum seconds between monitoring events (default: 5)

Web Dashboard Integration

The built-in web dashboard (/api/) automatically subscribes to monitoring events and displays real-time statistics.

Performance Considerations

  • Monitoring events are ephemeral (not stored in database)
  • Throttling prevents excessive event generation
  • Automatic activation/deactivation based on subscriptions
  • Minimal overhead when no clients are monitoring

Direct Messaging Admin System

In addition to the above admin API, c-relay allows the administrator to direct message the relay to get information or control some settings. As long as the administrator is signed in with any nostr client that allows sending nip-17 direct messages (DMs), they can control the relay.

The is possible because the relay is a full nostr citizen with it's own private and public key, and it knows the administrator's public key.

Available DM commands

The intent is not to be strict in the formatting of the DM. So for example if the relay receives any DM from the administrator with the words "stats" or "statistics" in it, it will respond to the administrator with a reply DM with the current relay statistics.

  • stats|statistics: Relay statistics
  • config|configuration: Relay configuration
Description
No description provided
Readme 255 MiB
v1.0.0 Latest
2025-11-01 11:03:39 +00:00
Languages
C 79.6%
JavaScript 13.4%
Shell 6%
CSS 0.5%
HTML 0.3%
Other 0.2%