A simple API service that connects to Nostr relays and provides Lightning address lookups for npubs. This service is designed to be used with WordPress plugins and other applications that need to retrieve Lightning addresses for Nostr users.
- Connects to multiple configurable Nostr relays using WebSockets
- REST API endpoint for looking up Lightning addresses by npub
- Extracts Lightning addresses from kind:0 metadata events (lud06/lud16 fields)
- Implements robust caching to minimize relay connections
- Handles connection failures gracefully
- Supports configurable relay list
- API key authentication for authorized access
- Rate limiting and request throttling
- Detailed request logging with privacy protection
Fetches Lightning address for the specified npub.
Request:
GET /api/v1/profile/npub1... HTTP/1.1
Host: your-api-domain.com
X-API-Key: your-api-key
You can provide the API key in any of these ways:
- Header:
X-API-Key: your-api-key
- Header:
Authorization: your-api-key
- Query parameter:
?api_key=your-api-key
Response:
{
"npub": "npub1...",
"lightning_address": "[email protected]",
"relay_source": "wss://relay.example.com",
"cached": true,
"cache_age": 3600
}
Returns status information about connected relays.
Request:
GET /api/v1/relays HTTP/1.1
Host: your-api-domain.com
X-API-Key: your-api-key
Response:
[
{
"url": "wss://relay.damus.io",
"status": "connected",
"lastConnected": 1677123456789
},
{
"url": "wss://relay.nostr.info",
"status": "disconnected",
"lastConnected": 1677123456789,
"lastError": 1677123459999
}
]
Returns the health status of the API. This endpoint does not require authentication.
Response:
{
"status": "ok"
}
- API key authentication for all endpoints except health check
- Time-constant comparison for API key validation to prevent timing attacks
- Request rate limiting to prevent abuse
- Progressive request throttling for fair access
- CORS configuration for controlled access
- Advanced security headers via Helmet
- Request logging with PII protection
- Payload size limiting
- Secure error handling that doesn't expose internals
- Node.js with Express
- nostr-tools for Nostr protocol implementation
- node-cache for in-memory caching
- WebSockets for relay connections
- Node.js 14+ (18+ recommended)
- npm or yarn
- A server with port 3000 available (or configurable)
-
Clone the repository:
git clone https://github.com/yourusername/Nostr-Profile-API.git cd Nostr-Profile-API
-
Install dependencies:
npm install
-
Create environment file:
cp .env.example .env
-
Generate an API key:
npm run generate-key
-
Edit the
.env
file to add your API key and configure other settings:nano .env
Add the generated API key to the
API_KEYS
variable. -
Add global WebSocket support for Node.js:
# Edit the relay manager file nano src/services/relayManager.js # Add this line at the very top of the file: global.WebSocket = require('ws');
-
Start the service:
npm start
-
Test the API:
curl http://localhost:3000/api/v1/health curl -H "X-API-Key: your-api-key" http://localhost:3000/api/v1/relays
-
Install Node.js 18+:
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash - sudo apt install -y nodejs
-
Install Caddy:
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list sudo apt update sudo apt install caddy
-
Clone and set up the application:
git clone https://github.com/yourusername/Nostr-Profile-API.git cd Nostr-Profile-API npm install cp .env.example .env npm run generate-key nano .env # Add your API key and other settings # Add WebSocket support nano src/services/relayManager.js # Add "global.WebSocket = require('ws');" at the top
-
Create a systemd service file:
sudo nano /etc/systemd/system/nostr-profile-api.service
Add the following content (replace with your actual username and paths):
[Unit] Description=Nostr Profile API After=network.target [Service] Type=simple User=your-username WorkingDirectory=/path/to/Nostr-Profile-API ExecStart=/usr/bin/node /path/to/Nostr-Profile-API/src/index.js Restart=on-failure RestartSec=10 Environment=NODE_ENV=production [Install] WantedBy=multi-user.target
-
Enable and start the service:
sudo systemctl enable nostr-profile-api sudo systemctl start nostr-profile-api
-
Configure Caddy as a reverse proxy:
sudo nano /etc/caddy/Caddyfile
Add your configuration:
api.yourdomain.com { reverse_proxy localhost:3000 tls [email protected] }
-
Reload Caddy:
sudo systemctl reload caddy
-
Test the API through your domain:
curl https://api.yourdomain.com/api/v1/health
-
Build and start the Docker container:
docker-compose up -d
-
The service will be available on port 3000.
Key environment variables:
API_KEYS
: Comma-separated list of API keys for authenticationDEFAULT_RELAYS
: Comma-separated list of Nostr relay WebSocket URLsCACHE_TTL
: TTL for cached profile data in seconds (default: 3600)RATE_LIMIT_MAX
: Maximum requests per IP in 15-minute window (default: 100)ALLOWED_ORIGINS
: Domains allowed to access the API (CORS)
See .env.example
for all available options.
If you encounter issues with the service, check these common problems:
-
WebSocket not defined error: Make sure you've added
global.WebSocket = require('ws');
to the top of src/services/relayManager.js -
User-related systemd errors: Ensure the username in your service file exists on the system
-
Node.js version issues: Verify you're using Node.js 14+ (18+ recommended)
-
Connection refused: Make sure the port isn't blocked by firewall
-
API Key authentication errors: Verify your API key is correctly configured in the .env file
For detailed logging, check systemd logs:
sudo journalctl -u nostr-profile-api -f
To integrate this API with a WordPress plugin:
-
Configure the WordPress plugin with:
- The API endpoint URL (e.g., https://api.yourdomain.com)
- Your API key
-
The plugin should make requests to
/api/v1/profile/:npub
with the API key in the header. -
Parse the JSON response to extract the Lightning address.
- REST API layer for handling HTTP requests
- Relay connection manager for maintaining WebSocket connections
- Cache layer for storing profile data
- Authentication and security middleware