Documentation Index
Fetch the complete documentation index at: https://mintlify.com/amark/gun/llms.txt
Use this file to discover all available pages before exploring further.
This guide covers deploying GUN relay peers to production environments. Relay peers help browser clients discover each other and provide persistent storage for your decentralized application.
Quick Deploy Options
Heroku
One-click deploy to Heroku:
Source: ~/workspace/source/README.md:271
Or manually:
git clone https://github.com/amark/gun.git
cd gun
heroku create
git push -f heroku HEAD:master
Source: ~/workspace/source/README.md:277-282
Note: Heroku’s ephemeral filesystem deletes data every ~15 minutes. For production, add persistent storage.
Source: ~/workspace/source/README.md:273
Docker
Pull from Docker Hub:
docker run -p 8765:8765 gundb/gun
Source: ~/workspace/source/README.md:301
Or build locally:
git clone https://github.com/amark/gun.git
cd gun
docker build -t myrepo/gundb:v1 .
docker run -p 8765:8765 myrepo/gundb:v1
Source: ~/workspace/source/README.md:306-311
Dockerfile Reference
GUN’s Dockerfile uses a multi-stage build:
# Build stage
FROM node:lts-alpine as builder
RUN mkdir /work
WORKDIR /work
RUN apk add --no-cache alpine-sdk python3
COPY package*.json ./
RUN npm ci --only=production
# Runtime stage
FROM node:lts-alpine
WORKDIR /work
COPY --from=builder /work/node_modules ./node_modules
ADD . .
EXPOSE 8080
EXPOSE 8765
CMD ["npm","start"]
Source: ~/workspace/source/Dockerfile
Exposed Ports:
8765: Default GUN relay port
8080: Alternative HTTP port
Linux Server
Deploy on a clean Linux server:
curl -o- https://raw.githubusercontent.com/amark/gun/master/examples/install.sh | bash
Source: ~/workspace/source/README.md:254
Note: Review the install script before running. It installs Node.js, clones GUN, and starts the relay peer.
Detach from the session:
# Press CTRL+A+D to detach
# Stop everything: killall screen or killall node
Source: ~/workspace/source/README.md:260-261
Environment Variables
Core Configuration
# Port configuration
export PORT=8765 # HTTP/WebSocket port
# HTTPS configuration
export HTTPS_KEY=~/key.pem # Path to SSL private key
export HTTPS_CERT=~/cert.pem # Path to SSL certificate
# Peer configuration
export PEERS="http://peer1.example.com/gun,http://peer2.example.com/gun"
# Feature flags
export AXE=true # Enable AXE routing (default: true)
export MULTICAST=false # Disable multicast (default: auto)
Source: ~/workspace/source/examples/http.js:7-11, ~/workspace/source/lib/axe.js:12, ~/workspace/source/lib/multicast.js:7
Build Configuration
# Prevent build warnings from failing deployment
export CI=false
Source: ~/workspace/source/README.md:245
Why needed: When deploying web apps with GUN on cloud providers, build systems may treat GUN’s warnings as errors.
HTTPS Configuration
Automatic HTTPS Detection
GUN automatically enables HTTPS if certificate files exist:
const fs = require('fs');
const Gun = require('gun');
const opt = {
port: process.env.PORT || 8765,
peers: process.env.PEERS?.split(',') || []
};
// Auto-detect certificates in home directory
const home = require('os').homedir();
if(fs.existsSync(home + '/cert.pem')){
opt.key = fs.readFileSync(home + '/key.pem');
opt.cert = fs.readFileSync(home + '/cert.pem');
opt.port = 443;
}
Source: ~/workspace/source/examples/http.js:14-21
Manual HTTPS Configuration
const Gun = require('gun');
const fs = require('fs');
const server = require('https').createServer({
key: fs.readFileSync(process.env.HTTPS_KEY),
cert: fs.readFileSync(process.env.HTTPS_CERT)
}, Gun.serve(__dirname));
const gun = Gun({web: server.listen(443)});
// Redirect HTTP to HTTPS
require('http').createServer(function(req, res){
res.writeHead(301, {"Location": "https://" + req.headers['host'] + req.url});
res.end();
}).listen(80);
Source: ~/workspace/source/examples/http.js:22-27
Let’s Encrypt
Use Certbot for free SSL certificates:
# Install Certbot
sudo apt-get update
sudo apt-get install certbot
# Obtain certificate
sudo certbot certonly --standalone -d yourdomain.com
# Set environment variables
export HTTPS_KEY=/etc/letsencrypt/live/yourdomain.com/privkey.pem
export HTTPS_CERT=/etc/letsencrypt/live/yourdomain.com/fullchain.pem
export PORT=443
# Start GUN
node server.js
Nginx Reverse Proxy
For complex setups, use Nginx:
server {
listen 80;
server_name yourdomain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
location /gun {
proxy_pass http://localhost:8765;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
Source: Referenced in ~/workspace/source/README.md:262
Storage Configuration
File System Storage (Default)
const Gun = require('gun');
require('gun/lib/server'); // Includes file storage
const gun = Gun({
file: 'data.json' // Relative to server root
});
Source: File storage is included in ~/workspace/source/lib/server.js:15
RAD Storage (Optimized)
Radix storage for better performance:
const gun = Gun({
rad: true // Enables radix storage
});
Amazon S3 Storage
For Heroku and other ephemeral filesystems:
# Set environment variables
export AWS_ACCESS_KEY_ID=your_access_key
export AWS_SECRET_ACCESS_KEY=your_secret_key
export AWS_S3_BUCKET=your-bucket-name
const Gun = require('gun');
require('gun/lib/rs3'); // S3 adapter
const gun = Gun({
s3: {
key: process.env.AWS_ACCESS_KEY_ID,
secret: process.env.AWS_SECRET_ACCESS_KEY,
bucket: process.env.AWS_S3_BUCKET
}
});
Source: S3 adapter at ~/workspace/source/lib/rs3.js, mentioned in ~/workspace/source/README.md:273
Custom Storage Adapter
Implement your own storage:
Gun.on('create', function(root){
this.to.next(root);
root.on('put', function(msg){
this.to.next(msg);
// Save msg.put to your storage
saveToDatabase(msg.put);
});
root.on('get', function(msg){
this.to.next(msg);
// Load from your storage
loadFromDatabase(msg.get, function(data){
root.on('in', {'@': msg['#'], put: data});
});
});
});
Process Management
PM2 (Recommended)
# Install PM2
npm install -g pm2
# Start GUN
pm2 start examples/http.js --name gun-relay
# Auto-restart on reboot
pm2 startup
pm2 save
# Monitor
pm2 monit
# View logs
pm2 logs gun-relay
Systemd Service
Create /etc/systemd/system/gun.service:
[Unit]
Description=GUN Relay Peer
After=network.target
[Service]
Type=simple
User=gunuser
WorkingDirectory=/home/gunuser/gun
Environment=PORT=8765
Environment=NODE_ENV=production
ExecStart=/usr/bin/node examples/http.js
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
# Enable and start
sudo systemctl enable gun
sudo systemctl start gun
# Check status
sudo systemctl status gun
# View logs
sudo journalctl -u gun -f
Clustering
GUN includes automatic clustering:
const cluster = require('cluster');
if(cluster.isMaster){
// Fork workers for each CPU
require('os').cpus().forEach(() => cluster.fork());
// Restart on crash
cluster.on('exit', () => {
cluster.fork();
});
} else {
// Worker process
const Gun = require('gun');
Gun({web: require('http').createServer().listen(8765)});
}
Source: ~/workspace/source/examples/http.js:2-5
Network Topology
Single Relay Peer
Simplest setup for small applications:
Browser ←→ Relay Peer ←→ Browser
// Client
const gun = Gun({
peers: ['https://relay.example.com/gun']
});
Multiple Relay Peers
Redundancy and load balancing:
Relay 1
/ \
Browser Relay 2 ←→ Browser
\ /
Relay 3
// Client
const gun = Gun({
peers: [
'https://relay1.example.com/gun',
'https://relay2.example.com/gun',
'https://relay3.example.com/gun'
]
});
// Relay peer configuration
const gun = Gun({
web: server.listen(8765),
peers: [
'https://relay2.example.com/gun',
'https://relay3.example.com/gun'
]
});
Geographic Distribution
Distribute relays globally for lower latency:
US-West Relay ←→ US-East Relay ←→ EU Relay ←→ Asia Relay
Clients connect to nearest relay.
Hybrid Architecture
Public Relay Peers
↕
Private Relay Peers
↕
Internal Network
Public relays for browser clients, private relays for backend services.
Monitoring and Logging
Enable Statistics
console.STAT = {};
setInterval(() => {
console.log('Gun Stats:', {
peers: console.STAT.peers,
memory: console.STAT.memused,
timestamp: new Date().toISOString()
});
}, 60000);
Source: Referenced in ~/workspace/source/src/mesh.js:328
Structured Logging
const Gun = require('gun');
const gun = Gun({
log: function(...args){
console.log(JSON.stringify({
timestamp: new Date().toISOString(),
level: 'info',
message: args.join(' ')
}));
}
});
Health Check Endpoint
const Gun = require('gun');
const express = require('express');
const app = express();
// Health check
app.get('/health', (req, res) => {
res.json({
status: 'healthy',
uptime: process.uptime(),
memory: process.memoryUsage(),
peers: gun._.opt.peers ? Object.keys(gun._.opt.peers).length : 0
});
});
app.use(Gun.serve);
const server = app.listen(8765);
const gun = Gun({web: server});
Error Tracking
const Gun = require('gun');
Gun.on('create', function(root){
this.to.next(root);
root.on('in', function(msg){
try {
this.to.next(msg);
} catch(err) {
console.error('Error processing message:', err);
// Send to error tracking service
}
});
});
Security Best Practices
1. Use HTTPS/WSS
Always use encrypted connections in production:
// Force HTTPS
if(req.headers['x-forwarded-proto'] !== 'https'){
res.redirect('https://' + req.headers.host + req.url);
}
2. Rate Limiting
const rateLimit = require('express-rate-limit');
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 1000 // Limit each IP to 1000 requests per windowMs
});
app.use('/gun', limiter);
3. Message Size Limits
const gun = Gun({
max: 10000000 // 10MB max message size
});
Source: ~/workspace/source/src/mesh.js:15
4. Authentication
Use GUN’s SEA for user authentication:
const Gun = require('gun');
require('gun/sea');
const gun = Gun();
// Server-side validation
gun.on('in', function(msg){
if(msg.put){
// Verify signature
Gun.SEA.verify(msg.put, msg.put.auth).then(verified => {
if(!verified){
console.log('Invalid signature');
return; // Reject message
}
this.to.next(msg);
});
} else {
this.to.next(msg);
}
});
5. CORS Configuration
const cors = require('cors');
app.use(cors({
origin: ['https://yourapp.com'],
credentials: true
}));
Optimize for Relay Role
const gun = Gun({
super: true, // Optimize for relay
faith: true, // Skip some validations
axe: true // Enable smart routing
});
Source: ~/workspace/source/lib/server.js:8-9
Connection Limits
const gun = Gun({
rtc: {
max: 55 // Limit WebRTC connections
}
});
Memory Management
const gun = Gun({
memory: 1000000000 // 1GB memory limit
});
Backup and Recovery
Automated Backups
#!/bin/bash
# backup.sh
BACKUP_DIR=/var/backups/gun
DATE=$(date +%Y%m%d_%H%M%S)
# Create backup
tar -czf $BACKUP_DIR/gun-data-$DATE.tar.gz /path/to/gun/radata/
# Keep only last 7 days
find $BACKUP_DIR -name "gun-data-*.tar.gz" -mtime +7 -delete
# Run daily at 2 AM
0 2 * * * /path/to/backup.sh
Data Export
const Gun = require('gun');
const fs = require('fs');
const gun = Gun();
const output = fs.createWriteStream('export.json');
gun.get('data').once(data => {
output.write(JSON.stringify(data, null, 2));
output.end();
});
Data Import
const Gun = require('gun');
const fs = require('fs');
const gun = Gun();
const data = JSON.parse(fs.readFileSync('export.json'));
gun.get('data').put(data);
Troubleshooting
Connection Issues
// Test peer connectivity
gun.on('hi', peer => {
console.log('Connected to peer:', peer.id);
});
gun.on('bye', peer => {
console.log('Disconnected from peer:', peer.id);
});
Memory Leaks
# Monitor memory usage
node --expose-gc --max-old-space-size=4096 server.js
// Force garbage collection periodically
setInterval(() => {
if(global.gc){
global.gc();
console.log('Memory:', process.memoryUsage());
}
}, 60000);
Storage Issues
// Check file permissions
const fs = require('fs');
try {
fs.accessSync('./radata', fs.constants.W_OK);
console.log('Storage directory is writable');
} catch(err) {
console.error('Storage directory is not writable:', err);
}
Deployment Checklist
Next Steps