# Configuration Management Guide Comprehensive guide for managing the C Nostr Relay's event-based configuration system. ## Table of Contents - [Overview](#overview) - [Configuration Events](#configuration-events) - [Parameter Reference](#parameter-reference) - [Configuration Examples](#configuration-examples) - [Security Considerations](#security-considerations) - [Troubleshooting](#troubleshooting) ## Overview The C Nostr Relay uses a revolutionary **event-based configuration system** where all settings are stored as kind 33334 Nostr events in the database. This provides several advantages: ### Benefits - **Real-time updates**: Configuration changes applied instantly without restart - **Cryptographic security**: All changes must be cryptographically signed by admin - **Audit trail**: Complete history of all configuration changes - **Version control**: Each configuration change is timestamped and signed - **Zero files**: No configuration files to manage, backup, or version control ### How It Works 1. **Admin keypair**: Generated on first startup, used to sign configuration events 2. **Configuration events**: Kind 33334 Nostr events with relay settings in tags 3. **Real-time processing**: New configuration events processed via WebSocket 4. **Immediate application**: Changes applied to running system without restart ## Configuration Events ### Event Structure Configuration events follow the standard Nostr event format with kind 33334: ```json { "id": "event_id_computed_from_content", "kind": 33334, "pubkey": "admin_public_key_hex", "created_at": 1699123456, "content": "C Nostr Relay Configuration", "tags": [ ["d", "relay_public_key_hex"], ["relay_description", "My Nostr Relay"], ["max_subscriptions_per_client", "25"], ["pow_min_difficulty", "16"] ], "sig": "signature_computed_with_admin_private_key" } ``` ### Required Tags - **`d` tag**: Must contain the relay's public key (identifies which relay this config is for) ### Event Properties - **Kind**: Must be exactly `33334` - **Content**: Should be descriptive (e.g., "C Nostr Relay Configuration") - **Pubkey**: Must be the admin public key generated at first startup - **Signature**: Must be valid signature from admin private key ## Parameter Reference ### Basic Relay Information #### `relay_description` - **Description**: Human-readable relay description (shown in NIP-11) - **Default**: `"C Nostr Relay"` - **Format**: String, max 512 characters - **Example**: `"My awesome Nostr relay for the community"` #### `relay_contact` - **Description**: Admin contact information (email, npub, etc.) - **Default**: `""` (empty) - **Format**: String, max 256 characters - **Example**: `"admin@example.com"` or `"npub1..."` #### `relay_software` - **Description**: Software identifier for NIP-11 - **Default**: `"c-relay"` - **Format**: String, max 64 characters - **Example**: `"c-relay v1.0.0"` #### `relay_version` - **Description**: Software version string - **Default**: Auto-detected from build - **Format**: Semantic version string - **Example**: `"1.0.0"` ### Client Connection Limits #### `max_subscriptions_per_client` - **Description**: Maximum subscriptions allowed per WebSocket connection - **Default**: `"25"` - **Range**: `1` to `100` - **Impact**: Prevents individual clients from overwhelming the relay - **Example**: `"50"` (allows up to 50 subscriptions per client) #### `max_total_subscriptions` - **Description**: Maximum total subscriptions across all clients - **Default**: `"5000"` - **Range**: `100` to `50000` - **Impact**: Global limit to protect server resources - **Example**: `"10000"` (allows up to 10,000 total subscriptions) ### Message and Event Limits #### `max_message_length` - **Description**: Maximum WebSocket message size in bytes - **Default**: `"65536"` (64KB) - **Range**: `1024` to `1048576` (1MB) - **Impact**: Prevents large messages from consuming resources - **Example**: `"131072"` (128KB) #### `max_event_tags` - **Description**: Maximum number of tags allowed per event - **Default**: `"2000"` - **Range**: `10` to `10000` - **Impact**: Prevents events with excessive tags - **Example**: `"5000"` #### `max_content_length` - **Description**: Maximum event content length in bytes - **Default**: `"65536"` (64KB) - **Range**: `1` to `1048576` (1MB) - **Impact**: Limits event content size - **Example**: `"131072"` (128KB for longer content) ### Proof of Work (NIP-13) #### `pow_min_difficulty` - **Description**: Minimum proof-of-work difficulty required for events - **Default**: `"0"` (no PoW required) - **Range**: `0` to `40` - **Impact**: Higher values require more computational work from clients - **Example**: `"20"` (requires significant PoW) #### `pow_mode` - **Description**: How proof-of-work is handled - **Default**: `"optional"` - **Values**: - `"disabled"`: PoW completely ignored - `"optional"`: PoW verified if present but not required - `"required"`: All events must meet minimum difficulty - **Example**: `"required"` (enforce PoW for all events) ### Event Expiration (NIP-40) #### `nip40_expiration_enabled` - **Description**: Enable NIP-40 expiration timestamp support - **Default**: `"true"` - **Values**: `"true"` or `"false"` - **Impact**: When enabled, processes expiration tags and removes expired events - **Example**: `"false"` (disable expiration processing) #### `nip40_expiration_strict` - **Description**: Strict mode for expiration handling - **Default**: `"false"` - **Values**: `"true"` or `"false"` - **Impact**: In strict mode, expired events are immediately rejected - **Example**: `"true"` (reject expired events immediately) #### `nip40_expiration_filter` - **Description**: Filter expired events from query results - **Default**: `"true"` - **Values**: `"true"` or `"false"` - **Impact**: When enabled, expired events are filtered from responses - **Example**: `"false"` (include expired events in results) #### `nip40_expiration_grace_period` - **Description**: Grace period in seconds before expiration takes effect - **Default**: `"300"` (5 minutes) - **Range**: `0` to `86400` (24 hours) - **Impact**: Allows some flexibility in expiration timing - **Example**: `"600"` (10 minute grace period) ## Configuration Examples ### Basic Relay Setup ```json { "kind": 33334, "content": "Basic Relay Configuration", "tags": [ ["d", "relay_pubkey_here"], ["relay_description", "Community Nostr Relay"], ["relay_contact", "admin@community-relay.com"], ["max_subscriptions_per_client", "30"], ["max_total_subscriptions", "8000"] ] } ``` ### High-Security Relay ```json { "kind": 33334, "content": "High Security Configuration", "tags": [ ["d", "relay_pubkey_here"], ["relay_description", "High-Security Nostr Relay"], ["pow_min_difficulty", "24"], ["pow_mode", "required"], ["max_subscriptions_per_client", "10"], ["max_total_subscriptions", "1000"], ["max_message_length", "32768"], ["nip40_expiration_strict", "true"] ] } ``` ### Public Community Relay ```json { "kind": 33334, "content": "Public Community Relay Configuration", "tags": [ ["d", "relay_pubkey_here"], ["relay_description", "Open Community Relay - Welcome Everyone!"], ["relay_contact", "community@relay.example"], ["max_subscriptions_per_client", "50"], ["max_total_subscriptions", "25000"], ["max_content_length", "131072"], ["pow_mode", "optional"], ["pow_min_difficulty", "8"], ["nip40_expiration_enabled", "true"], ["nip40_expiration_grace_period", "900"] ] } ``` ### Private/Corporate Relay ```json { "kind": 33334, "content": "Corporate Internal Relay", "tags": [ ["d", "relay_pubkey_here"], ["relay_description", "Corporate Internal Communications"], ["relay_contact", "it-admin@company.com"], ["max_subscriptions_per_client", "20"], ["max_total_subscriptions", "2000"], ["max_message_length", "262144"], ["nip40_expiration_enabled", "false"], ["pow_mode", "disabled"] ] } ``` ## Security Considerations ### Admin Key Management #### Secure Storage ```bash # Store admin private key securely echo "ADMIN_PRIVKEY=your_admin_private_key_here" > .env chmod 600 .env # Or use a password manager # Never store in version control echo ".env" >> .gitignore ``` #### Key Rotation Currently, admin key rotation requires: 1. Stopping the relay 2. Removing the database (loses all events) 3. Restarting (generates new keys) Future versions will support admin key rotation while preserving events. ### Event Validation The relay performs comprehensive validation on configuration events: #### Cryptographic Validation - **Signature verification**: Uses `nostr_verify_event_signature()` - **Event structure**: Validates JSON structure with `nostr_validate_event_structure()` - **Admin authorization**: Ensures events are signed by the authorized admin pubkey #### Content Validation - **Parameter bounds checking**: Validates numeric ranges - **String length limits**: Enforces maximum lengths - **Enum validation**: Validates allowed values for mode parameters ### Network Security #### Access Control ```bash # Limit access with firewall sudo ufw allow from 192.168.1.0/24 to any port 8888 # Or use specific IPs sudo ufw allow from 203.0.113.10 to any port 8888 ``` #### TLS/SSL Termination ```nginx # nginx configuration for HTTPS termination server { listen 443 ssl; server_name relay.example.com; ssl_certificate /path/to/cert.pem; ssl_certificate_key /path/to/key.pem; location / { proxy_pass http://127.0.0.1:8888; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; proxy_set_header Host $host; } } ``` ## Troubleshooting ### Configuration Not Applied #### Check Event Signature ```javascript // Verify event signature with nostrtool or similar const event = { /* your configuration event */ }; const isValid = nostrTools.verifySignature(event); ``` #### Verify Admin Pubkey ```bash # Check current admin pubkey in database sqlite3 relay.nrdb "SELECT DISTINCT pubkey FROM events WHERE kind = 33334 ORDER BY created_at DESC LIMIT 1;" # Compare with expected admin pubkey from first startup grep "Admin Public Key" relay.log ``` #### Check Event Structure ```bash # View the exact event stored in database sqlite3 relay.nrdb "SELECT json_pretty(json_object( 'kind', kind, 'pubkey', pubkey, 'created_at', created_at, 'content', content, 'tags', json(tags), 'sig', sig )) FROM events WHERE kind = 33334 ORDER BY created_at DESC LIMIT 1;" ``` ### Configuration Validation Errors #### Invalid Parameter Values ```bash # Check relay logs for validation errors journalctl -u c-relay | grep "Configuration.*invalid\|Invalid.*configuration" # Common issues: # - Numeric values outside valid ranges # - Invalid enum values (e.g., pow_mode) # - String values exceeding length limits ``` #### Missing Required Tags ```bash # Ensure 'd' tag is present with relay pubkey sqlite3 relay.nrdb "SELECT tags FROM events WHERE kind = 33334 ORDER BY created_at DESC LIMIT 1;" | grep '"d"' ``` ### Performance Impact #### Monitor Configuration Changes ```bash # Track configuration update frequency sqlite3 relay.nrdb "SELECT datetime(created_at, 'unixepoch') as date, COUNT(*) as config_updates FROM events WHERE kind = 33334 GROUP BY date(created_at, 'unixepoch') ORDER BY date DESC;" ``` #### Resource Usage After Changes ```bash # Monitor system resources after configuration updates top -p $(pgrep c_relay) # Check for memory leaks ps aux | grep c_relay | awk '{print $6}' # RSS memory ``` ### Emergency Recovery #### Reset to Default Configuration If configuration becomes corrupted or causes issues: ```bash # Create emergency configuration event nostrtool event \ --kind 33334 \ --content "Emergency Reset Configuration" \ --tag d YOUR_RELAY_PUBKEY \ --tag max_subscriptions_per_client 25 \ --tag max_total_subscriptions 5000 \ --tag pow_mode optional \ --tag pow_min_difficulty 0 \ --private-key YOUR_ADMIN_PRIVKEY \ | nostrtool send ws://localhost:8888 ``` #### Database Recovery ```bash # If database is corrupted, backup and recreate cp relay.nrdb relay.nrdb.backup rm relay.nrdb* ./build/c_relay_x86 # Creates fresh database with new keys ``` --- This configuration guide covers all aspects of managing the C Nostr Relay's event-based configuration system. The system provides unprecedented flexibility and security for Nostr relay administration while maintaining simplicity and real-time responsiveness.