Discord Can't Ban
What Discord Doesn't Own.
rde_nostr_log is the first truly decentralized FiveM logging system. Every server event is cryptographically signed and published to the Nostr network — permanent, uncensorable, and free of Discord's rate limits, TOS bans and single point of failure.
Overview
Traditional FiveM logging depends on Discord webhooks — a single centralized company that can rate-limit, censor, or delete your logs at will. rde_nostr_log replaces that entirely with the Nostr protocol: every log event is a signed message broadcast to a network of independent relays you don't control and can't be taken down.
Why this over Discord webhooks
| Discord Webhooks | rde_nostr_log |
|---|---|
| Rate limited (30 req/min) | Unlimited posts |
| Censored by Discord TOS | Uncensorable — no central authority |
| Deleted when server banned | Permanent — distributed across relays |
| Single point of failure | Decentralized — 100+ global relays |
See your logs live at the RDE Log Browser, or any standard Nostr client such as Amethyst (Android) or Damus (iOS).
Quick Start
# 1. Clone the repository
cd resources
git clone https://github.com/RedDragonElite/rde_nostr_log.git
# 2. Install dependencies — yarn, not npm!
cd rde_nostr_log
yarn install
# 3. Add to server.cfg
ensure rde_nostr_log
node_modules/nostr-tools is version 2.x — v1.x has a completely different API and will crash on startup.
Nostr Identity Setup
Leave privateKey = '' empty in server.js to auto-generate a key on first boot — the nsec prints to console, copy it back in for a permanent identity. Or generate one offline for maximum security and paste it in yourself.
Choose your relays
relays: [
'wss://nos.lol', // Fast, stable
'wss://relay.damus.io', // Largest iOS client relay
'wss://relay.primal.net', // High uptime
]
3–5 relays is the sweet spot — more relays means slower posts with diminishing returns.
Configuration
Config.Nostr = {
privateKey: 'nsec1...',
relays: [...],
batchEnabled: false, // keep false for realtime logging
publishTimeout: 15000,
}
Config.AdminSystem = {
steamIds: ['steam:123...'],
acePermission: 'rde.nostr.admin',
}
Exports / API
| Export | Signature | Notes |
|---|---|---|
| postLog | exports.rde_nostr_log:postLog(msg, tags) | Post a custom log with tags from any resource. Rate-limited per resource (10/5s). |
| getBotNpub | exports.rde_nostr_log:getBotNpub() | Returns the bot's public Nostr identity |
Automatic logging covers: player connect/join/leave, disconnect reasons, admin actions, weather changes (via rde_weather), and AI Pilot events (via rde_aipilot).
Security
set NOSTR_PRIVATE_KEY "nsec1yourkeyhere" — and read it via GetConvar(). Never hardcode your nsec directly in server.js, and never commit it to GitHub.
Common Pitfalls
"hex string expected, got object" on startup
Version mismatch between nostr-tools v1.x and v2.x — v2 changed its entire API, and nip19.decode() now returns a Uint8Array instead of hex.
Fix: pin "nostr-tools": "^2.0.0" in package.json, delete node_modules, run yarn install again.
UnhandledPromiseRejection on player disconnect
getEventHash() and getSignature() no longer exist in nostr-tools v2.x.
Fix: replaced with finalizeEvent() in v1.2.3 — update if you're on an older version.
attempt to index a nil value (global 'lib')
@ox_lib/init.lua was missing from shared_scripts in fxmanifest.lua on v1.2.3 and earlier.
Fix: update to v1.2.4 — drop-in replacement, no config changes required.
FAQ
Is this really free?
Yes. 100% free forever — no premium version, no upsells.
Can Discord ban my bot?
No — this doesn't use Discord at all.
Can I delete old logs?
No. Nostr events are permanent — only post what you're okay being public forever.
Works with ESX/QBCore/ox_core?
Yes — the core bot is framework-agnostic, with native integrations for rde_weather and rde_aipilot.
Changelog
Critical fix — lib was nil on client, @ox_lib/init.lua added to shared_scripts.
Architecture cleanup — eliminated duplicate player event logging, DevMode forced off in production.
Stability — eliminated UnhandledPromiseRejection via nostr-tools v2.x migration to finalizeEvent(), fixed OFFLINE panel bug, added pre-init event queue.