Problem
When the app is in background or closed, users miss incoming messages because Nostr relay WebSocket connections are dropped by iOS.
Solution
Run a lightweight Sigil Push Service (open source, self-hostable):
Architecture
┌─────────────────┐ ┌──────────────────────┐ ┌─────────┐
│ Nostr Relay │────▶│ Sigil Push Service │────▶│ APNs │
│ (relay.damus.io) │ │ (sigil-push) │ │ / FCM │
│ │ │ │ │ │
│ kind:4 / kind:17 │ │ • Listens for DMs │ │ Push to │
│ events for npub │ │ • Matches device tokens │ │ device │
└─────────────────┘ │ • Sends push via APNs │ └─────────┘
└──────────────────────┘
Open source, self-hostable
Components
-
sigil-push server (Rust or Node.js)
- Connects to configured relays
- Subscribes to NIP-04/NIP-17 events for registered npubs
- On new event → send push notification via APNs (iOS) / FCM (Android)
- REST API:
POST /register { npub, device_token, platform }
- REST API:
DELETE /unregister { device_token }
-
iOS client changes
- Register for remote notifications on launch
- Send device token + npub to sigil-push service
- Handle incoming push → show notification with sender name + preview (or "Encrypted message" if can't decrypt)
-
Default instance
- Sigil project runs a default push service (e.g., push.sigil.chat)
- Users can point to their own self-hosted instance in settings
Privacy
- Push service sees which npubs receive messages but NOT message content (NIP-04/NIP-17 encrypted)
- Self-hosting eliminates this metadata exposure
- Device tokens are stored server-side, deleted on unregister
Implementation Order
- iOS: register for push notifications, obtain device token
- Server: relay listener + APNs integration
- iOS: send device token to server on connect
- iOS: handle push notification display
- Settings: custom push server URL
Prior Art
- Signal runs their own push service (closed source)
- SimpleX has optional push relay
- ntfy.sh — open source push notification service (different protocol)
Problem
When the app is in background or closed, users miss incoming messages because Nostr relay WebSocket connections are dropped by iOS.
Solution
Run a lightweight Sigil Push Service (open source, self-hostable):
Architecture
Components
sigil-push server (Rust or Node.js)
POST /register { npub, device_token, platform }DELETE /unregister { device_token }iOS client changes
Default instance
Privacy
Implementation Order
Prior Art