C Nostr Relay - Event-Based Configuration System
A high-performance Nostr relay implemented in C with SQLite backend, featuring a revolutionary zero-configuration approach using event-based configuration 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
🔧 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. Admin commands use ephemeral kinds 23455 and 23456 with optional NIP-44 encryption for enhanced security.
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.
Security Options
Standard Mode (Plaintext): Commands sent in tags as normal Encrypted Mode (NIP-44): Commands encrypted in content field, no tags used
Kind 23455: Configuration Management (Ephemeral)
Update relay configuration parameters or query available settings.
Configuration Update:
{
"kind": 23455,
"content": "<optional nip-44 encrypted tags>",
"tags": [
["config_key1", "config_value1"],
["config_key2", "config_value2"]
]
}
Query Available Config Keys:
{
"kind": 23455,
"content": "<optional nip-44 encrypted tags>",
"tags": [
["config_query", "list_all_keys"]
]
}
Get Current Configuration:
{
"kind": 23455,
"content": "<optional nip-44 encrypted tags>",
"tags": [
["config_query", "get_current_config"]
]
}
Available Configuration Keys:
Basic Relay Settings:
relay_description: Relay description textrelay_contact: Contact informationmax_connections: Maximum concurrent connectionsmax_subscriptions_per_client: Max subscriptions per clientmax_event_tags: Maximum tags per eventmax_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 difficultynip40_expiration_enabled: Enable event expiration (true/false)
Kind 23456: Auth Rules & System Management (Ephemeral)
Manage whitelist/blacklist rules and system administration commands.
Add Blacklist Rule:
{
"kind": 23456,
"content": "<optional nip-44 encrypted tags>",
"tags": [
["blacklist", "pubkey", "deadbeef1234abcd..."]
]
}
Add Whitelist Rule:
{
"kind": 23456,
"content": "<optional nip-44 encrypted tags>",
"tags": [
["whitelist", "pubkey", "cafebabe5678efgh..."]
]
}
Remove Rule:
{
"kind": 23456,
"content": "<optional nip-44 encrypted tags>",
"tags": [
["blacklist", "pubkey", "deadbeef1234abcd..."]
]
}
Query Auth Rules:
{
"kind": 23456,
"content": "<optional nip-44 encrypted tags>",
"tags": [
["auth_query", "all"]
]
}
Query Specific Rule Type:
{
"kind": 23456,
"content": "<optional nip-44 encrypted tags>",
"tags": [
["auth_query", "whitelist"]
]
}
Query Specific Pattern:
{
"kind": 23456,
"content": "<optional nip-44 encrypted tags>",
"tags": [
["auth_query", "pattern", "deadbeef1234abcd..."]
]
}
Clear All Auth Rules:
{
"kind": 23456,
"content": "<optional nip-44 encrypted tags>",
"tags": [
["system_command", "clear_all_auth_rules"]
]
}
Response Format
All admin commands return JSON responses via WebSocket:
Success Response:
["OK", "event_id", true, "Operation completed successfully"]
Error Response:
["OK", "event_id", false, "Error: invalid configuration value"]
Command Examples
Using nak CLI tool:
# Set environment variables
ADMIN_PRIVKEY="your_admin_private_key_here"
RELAY_PUBKEY="your_relay_public_key_here"
RELAY_URL="ws://localhost:8888"
# List all available configuration keys
nak event -k 23455 --content "Discovery query" \
-t "config_query=list_all_keys" \
--sec $ADMIN_PRIVKEY | nak event $RELAY_URL
# Enable whitelist/blacklist auth rules
nak event -k 23455 --content "Enable auth rules" \
-t "auth_enabled=true" \
--sec $ADMIN_PRIVKEY | nak event $RELAY_URL
# Add user to blacklist
nak event -k 23456 --content "Block spam user" \
-t "blacklist=pubkey;$SPAM_USER_PUBKEY" \
--sec $ADMIN_PRIVKEY | nak event $RELAY_URL
# Add user to whitelist
nak event -k 23456 --content "Allow trusted user" \
-t "whitelist=pubkey;$TRUSTED_USER_PUBKEY" \
--sec $ADMIN_PRIVKEY | nak event $RELAY_URL
# Query all current auth rules
nak event -k 23456 --content "Get all auth rules" \
-t "auth_query=all" \
--sec $ADMIN_PRIVKEY | nak event $RELAY_URL
# Query only whitelist rules
nak event -k 23456 --content "Get whitelist rules" \
-t "auth_query=whitelist" \
--sec $ADMIN_PRIVKEY | nak event $RELAY_URL
# Query only blacklist rules
nak event -k 23456 --content "Get blacklist rules" \
-t "auth_query=blacklist" \
--sec $ADMIN_PRIVKEY | nak event $RELAY_URL
# Check if specific pattern exists
nak event -k 23456 --content "Check user status" \
-t "auth_query=pattern;$CHECK_USER_PUBKEY" \
--sec $ADMIN_PRIVKEY | nak event $RELAY_URL
# Clear all auth rules (for testing)
nak event -k 23456 --content "Clear all rules" \
-t "system_command=clear_all_auth_rules" \
--sec $ADMIN_PRIVKEY | nak event $RELAY_URL
# Update relay description
nak event -k 23455 --content "Update description" \
-t "relay_description=My awesome relay" \
--sec $ADMIN_PRIVKEY | nak event $RELAY_URL
# Set connection limits
nak event -k 23455 --content "Update limits" \
-t "max_connections=500" \
-t "max_subscriptions_per_client=10" \
--sec $ADMIN_PRIVKEY | nak event $RELAY_URL
For encrypted commands (NIP-44), use empty tags and encrypted content:
# Enable auth rules (encrypted)
ENCRYPTED_TAGS=$(echo '[["auth_enabled","true"]]' | nip44_encrypt_with_relay_pubkey)
nak event -k 23455 --content "{\"encrypted_tags\":\"$ENCRYPTED_TAGS\"}" \
--sec $ADMIN_PRIVKEY | nak event $RELAY_URL
# Add user to blacklist (encrypted)
ENCRYPTED_TAGS=$(echo '[["blacklist","pubkey","'$SPAM_USER_PUBKEY'"]]' | nip44_encrypt_with_relay_pubkey)
nak event -k 23456 --content "{\"encrypted_tags\":\"$ENCRYPTED_TAGS\"}" \
--sec $ADMIN_PRIVKEY | nak event $RELAY_URL
Authentication Systems
C-Relay supports two independent authentication systems:
1. Auth Rules (Whitelist/Blacklist)
- Config Key:
auth_enabled=true - Purpose: Block or allow specific pubkeys from publishing events
- Method: Database-driven rules enforcement
- Use Case: Spam prevention, content moderation
2. NIP-42 Cryptographic Authentication
- Config Key:
nip42_auth_required=true - Purpose: Require cryptographic proof of pubkey ownership
- Method: Challenge-response authentication protocol
- Use Case: Verified identity, premium features
Important: These systems can be used independently or together:
auth_enabled=true+nip42_auth_required=false: Only whitelist/blacklist rulesauth_enabled=false+nip42_auth_required=true: Only NIP-42 auth challenges- Both
true: Users must pass NIP-42 auth AND not be blacklisted
Security Considerations
- Private Key Protection: Admin private key grants full relay control
- Network Access: Admin commands should only be sent over secure connections
- Backup: Keep secure backups of admin private key
- Rotation: Consider implementing admin key rotation for production deployments
Troubleshooting
Common Issues:
auth-required: not authorized admin: Verify you're using the correct admin private keyinvalid: missing or invalid kind: Ensure event kind is 23455 or 23456error: failed to process configuration event: Check configuration key/value validityno valid auth rules found: Verify tag format uses semicolon syntax for multi-element tags
Debug Commands:
# Check if relay is accepting connections
echo '["REQ","test",{}]' | websocat ws://localhost:8888
# Test admin authentication
nak event -k 23455 --content "Test auth" \
-t "test_config=true" \
--sec $ADMIN_PRIVKEY | nak event ws://localhost:8888
# Discover available configuration keys
nak event -k 23455 --content "Discovery query" \
-t "config_query=list_all_keys" \
--sec $ADMIN_PRIVKEY | nak event ws://localhost:8888
# Query current auth rules
nak event -k 23456 --content "Get auth rules" \
-t "auth_query=all" \
--sec $ADMIN_PRIVKEY | nak event ws://localhost:8888
Configuration Discovery
Before making changes, admins can query the relay to discover all available configuration options:
# Get list of all editable configuration keys with descriptions
nak event -k 23455 --content '{"query":"list_config_keys","description":"Discovery"}' \
-t "config_query=list_all_keys" \
--sec $ADMIN_PRIVKEY | nak event $RELAY_URL
# Get current values of all configuration parameters
nak event -k 23455 --content '{"query":"get_config","description":"Current state"}' \
-t "config_query=get_current_config" \
--sec $ADMIN_PRIVKEY | nak event $RELAY_URL
Expected Response Format:
["EVENT", "subscription_id", {
"kind": 23455,
"content": "{\"config_keys\": [\"auth_enabled\", \"max_connections\", ...], \"descriptions\": {...}}",
"tags": [["response_type", "config_keys_list"]]
}]