This repository is home to the hornet storage panel which is a typescript / react web application designed for managing a hornet storage nostr multimedia relay which can be found here: https://github.com/HORNET-Storage/HORNETS-Nostr-Relay
Before installing, ensure you have:
- A Nostr browser extension (Alby, nos2x, etc.) - REQUIRED
- Node.js 16+ and yarn installed
- The HORNETS relay service running (see here)
Without these, the panel will not function.
We have a live demo that can be found at http://hornetstorage.net for anyone that wants to see what the panel looks like.
- Manage your hornet-storage relay config directly from the panel
- Switch between our new whitelist and blacklist model for accepting nostr notes
- Decide from which of the supported nostr kinds to enable
- Choose which supported transport protocols to enable such as libp2p and websockets
- Enable / disable which media extensions are accepted by the relay such as png and mp4
- View statistics about stored notes and media
- Upload relay icons with integrated Blossom server support
The HORNETS Relay Panel requires a NIP-07 compatible Nostr browser extension to function.
You must install one of these browser extensions before using the panel:
- Alby - Bitcoin Lightning & Nostr browser extension
- nos2x - Simple Nostr browser extension
- Flamingo - Nostr browser extension
- Horse - Nostr browser extension
The panel uses NIP-07 (window.nostr capability) for:
- User authentication and login
- Event signing for relay configuration
- File uploads with cryptographic verification
π Learn more about NIP-07: https://nostr-nips.com/nip-07
Essential steps to get running:
- Install a NIP-07 browser extension (required - see above)
- Install dependencies:
npm install -g serveandyarn install - Start frontend-only development:
yarn start - For relay integration:
yarn build, copybuild/*into the relay'sweb/directory, then start the relay
For full deployment with reverse proxy, see the detailed setup guide below.
All preview images are taken from the live demo

The HORNETS Relay Panel is built with a microservices architecture comprising:
The panel is now integrated directly into the relay server for simplified deployment:
- Relay + Panel Server: Port 9002 - Serves both the React app (static files) and panel API
- Relay WebSocket: Port 9001 - WebSocket service for Nostr relay functionality
- Wallet Service: Port 9003 - Backend service for wallet operations
- Media Moderation: Port 8000 - Content moderation and filtering service
Client Request (http://localhost or your-domain.com)
β
Nginx Proxy (Port 80/443) - Optional but recommended for production
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Route Distribution: β
β βββββββββββββββββββββββββββ βββββββββββββββββββββββββββ β
β β / β Relay + Panel β β /wallet/ β Wallet API β β
β β (Port 9002) β β (Port 9003) β β
β β βββ /api/* β Panel API β β β β
β β βββ /* β React App β β β β
β βββββββββββββββββββββββββββ βββββββββββββββββββββββββββ β
β β
β WebSocket Connection: β
β βββββββββββββββββββββββββββ β
β β ws:// β Relay WebSocket β β
β β (Port 9001) β β
β βββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
For integrated testing, serve the panel build from the relay so browser requests and the panel API share one origin:
- Relay + Panel:
http://localhost:9002(no proxy needed) - Standalone React dev server: frontend-only unless a development proxy forwards API routes to the relay
For production deployment, nginx handles:
- Relay WebSocket Proxying:
/relayand/relay/βlocalhost:9001(strips prefix) - Wallet Service Proxying:
/wallet/*βlocalhost:9003 - SSL Termination: Single certificate for entire application
- WebSocket Proxying: Proper upgrade headers for relay WebSocket
- Static Asset Caching: Optimal performance for React app
- Security Headers: CORS, CSP, and other protections
Here's a complete working nginx configuration for the HORNETS Relay Panel (tested on macOS and Linux):
# Define upstream servers for each service (using explicit IPv4 addresses)
upstream transcribe_api {
server 127.0.0.1:8000;
}
upstream relay_service {
server 127.0.0.1:9001;
}
upstream panel_service {
server 127.0.0.1:9002;
}
upstream wallet_service {
server 127.0.0.1:9003;
}
# WebSocket connection upgrade mapping
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
# Main server block listening on HTTP
server {
listen 80; # Nginx listens on port 80 locally
server_name _; # Accept all hostnames (localhost, ngrok, custom domains, etc.)
# Basic Security Headers
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";
add_header X-XSS-Protection "1; mode=block";
server_tokens off;
# Increase buffer sizes for large files
client_max_body_size 100M;
# Forward client IP and protocol
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
# Health check endpoint - exact match first
location = /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
# Relay WebSocket service - handle both /relay and /relay/
location ~ ^/relay/?$ {
# Strip the /relay prefix (with or without trailing slash) when forwarding to the service
rewrite ^/relay/?$ / break;
proxy_pass http://relay_service;
# WebSocket-specific headers
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
# Extended timeouts for WebSocket connections
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
proxy_connect_timeout 60s;
# Additional headers for tunnel compatibility
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
}
# Transcribe service
location /transcribe/ {
rewrite ^/transcribe/(.*)$ /$1 break;
proxy_pass http://transcribe_api;
}
# Wallet service
location /wallet/ {
rewrite ^/wallet/(.*)$ /$1 break;
proxy_pass http://wallet_service;
}
# Blossom file storage routes
location /blossom/ {
proxy_pass http://panel_service;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Disable buffering for file uploads/downloads
proxy_buffering off;
proxy_request_buffering off;
# Set appropriate headers
proxy_set_header Accept-Encoding "";
# Larger timeouts for file operations
proxy_read_timeout 300s;
proxy_send_timeout 300s;
proxy_connect_timeout 60s;
}
# Default location - Panel service (frontend + API) - MUST BE LAST
location / {
# Add CORS headers for the panel service
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Origin, Content-Type, Accept, Authorization' always;
# Handle preflight OPTIONS requests
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Origin, Content-Type, Accept, Authorization';
add_header 'Content-Length' 0;
return 204;
}
proxy_pass http://panel_service;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Handle WebSocket if needed
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}Key Configuration Details:
- Relay WebSocket: Uses regex matching
^/relay/?$to handle both/relayand/relay/paths - Rewrite Rule: Strips the
/relayprefix before forwarding to the relay service at port 9001 - WebSocket Support: Proper upgrade headers and extended timeouts for WebSocket connections
- Service Routing: Panel (root), wallet (
/wallet/), transcribe (/transcribe/), and relay (/relay) - Security: Basic security headers and proper client IP forwarding
Deployment Steps:
- Save this configuration to
/etc/nginx/sites-available/hornets(or/opt/homebrew/etc/nginx/conf.d/hornets.confon macOS) - Enable the site:
sudo ln -s /etc/nginx/sites-available/hornets /etc/nginx/sites-enabled/ - Test configuration:
sudo nginx -t - Reload nginx:
sudo nginx -s reload
- Node.js version >=16.0.0
- Yarn package manager
- Git for version control
- serve for production builds:
npm install -g serve
- Nginx for reverse proxy (Linux server configuration)
- SSL certificate (Let's Encrypt recommended)
- Domain name
- NIP-07 compatible browser extension (see Important Prerequisites section above)
git clone https://github.com/HORNET-Storage/HORNETS-Relay-Panel.git
cd HORNETS-Relay-Panelyarn installThe panel and relay API are same-origin. API and wallet origins are not configurable in the browser bundle; every request uses the origin that served the panel.
The environment files contain only non-origin build options:
REACT_APP_ASSETS_BUCKET=http://localhost
REACT_APP_DEMO_MODE=false
REACT_APP_BASENAME=
PUBLIC_URL=/
ESLINT_NO_DEV_ERRORS=true
TSC_COMPILE_ON_ERROR=trueπ― Key Requirements:
- β Wallet Always Available - Wallet operations routed through panel API, no configuration needed
- β Panel Routing Auto-Detection - Panel paths (REACT_APP_BASENAME/PUBLIC_URL) can be auto-detected
- β Simplified Configuration - Uses default Nostr relay URLs, no custom configuration needed
- β Simple Deployment - No reverse proxy needed for basic functionality
./start-app.sh # Linux/macOS
start.bat # Windowsyarn startThe development server starts on http://localhost:3000. It is frontend-only unless a development proxy forwards API routes; use a relay-served production build for same-origin integration testing.
# Production build
yarn build
# Using provided script (handles Node.js compatibility)
./build.bat # Windows
yarn build # Linux/macOSCopy the built files to your relay server's web directory and start the services:
# Copy build files to relay server web directory
cp -r build/* /path/to/relay/web/
# Start services (adjust ports as needed)
./relay-websocket-service & # Port 9001
./relay-server-with-panel & # Port 9002 (serves both API and panel)
./wallet-service & # Port 9003- Panel:
http://localhost:9002/(or your configured domain) - Wallet Service:
http://localhost:9003/(direct access) - Relay WebSocket:
ws://localhost:9001/(WebSocket connection)
β This setup works without any reverse proxy configuration!
Note: Reverse proxy setup with nginx is possible but currently requires additional configuration. The direct access method above is the recommended approach for most users.
π Major Improvement: The panel now uses dynamic URL detection instead of hardcoded environment variables. This means one build works everywhere - no more environment-specific builds or complex URL configuration!
Controls the React app's routing base path:
- `` (empty) - App accessible at
https://domain.com/(recommended for direct access) /panel- App accessible athttps://domain.com/panel/(for reverse proxy setups)
Note: For the current working setup, leave this empty (REACT_APP_BASENAME=) since the panel is served from the root path.
The panel API and wallet proxy are always contacted through the page origin. Deploy the static build in the relay's web directory and expose that relay origin directly or through a reverse proxy. No browser API endpoint configuration is required or supported.
Set REACT_APP_DEMO_MODE=true to enable demo functionality with mock data.
Error: digital envelope routines::unsupported
Solution: Scripts include NODE_OPTIONS=--openssl-legacy-provider
Error: JavaScript heap out of memory
Solution: Increase memory allocation:
export NODE_OPTIONS="--openssl-legacy-provider --max-old-space-size=4096"Error: Network errors, connection refusals, or unexpected API hosts
Solution: Verify that the relay web service is reachable at the same origin shown in the browser address bar. The deployed panel must be served by the relay (or a reverse proxy that forwards both the panel and API routes to it).
When replacing an older deployment, remove the destination web directory before copying the new build, then unregister the site's service worker and clear site data so an obsolete cached bundle cannot remain active.
Error: 404 on refresh or direct URL access Solution: Configure nginx to handle React Router:
location /front/ {
try_files $uri $uri/ /front/index.html;
}Error: WebSocket connection refused Solution: Ensure proper WebSocket configuration in nginx:
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;Start services in this order:
- Relay Service (Port 9001) - Core WebSocket functionality
- Panel API (Port 9002) - Main backend
- Wallet Service (Port 9003) - Payment processing
- Media Moderation (Port 8000) - Content filtering (optional)
- Frontend (Port 3000) - User interface
- Nginx health:
curl http://localhost/health - Individual services:
curl http://localhost:PORT/health
- Hot reloading enabled
- Source maps included
- Verbose error messages
- API requests remain same-origin; a standalone dev server needs an API proxy for integration testing
- Optimized builds with minification
- Source maps excluded
- Error boundaries for user-friendly errors
- Same-origin API calls served directly by the relay or forwarded with the panel through one reverse-proxy origin
- Use HTTPS in production
- Configure proper CORS policies
- Implement rate limiting
- Regular security headers via nginx
- Keep dependencies updated
- Never commit
.env.productionto version control - Use secure random values for secrets
- Regularly rotate API keys and tokens
Development mode
yarn install && yarn start
Production mode
yarn install && yarn build
.bat and .sh files are included for starting the panel in dev mode and for creating a production build if needed
- Fork the repository
- Create a feature branch
- Make your changes
- Test thoroughly
- Submit a pull request
This project is licensed under the MIT License - see the LICENSE file for details.
- π This panel relies heavily on the Ant Design component library with some modifications
- Based on the Lightence template
- Part of the HORNETS Storage ecosystem
This panel was created using the lightence template which can be found here
For issues and support:
- GitHub Issues: Report bugs and request features
- Community: Join our discussions
- Documentation: Check the wiki for detailed guides
Note: This panel is designed to work with the HORNETS Storage ecosystem:
- HORNETS Nostr Relay - Core relay service (required)
- Super Neutrino Wallet - Payment processing (required for paid features)
- NestShield - Media moderation service (optional)
Ensure you have at minimum the relay service running for basic functionality.