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.
P2P Networking with GUN
Learn how to build peer-to-peer mesh networks with GUN. This guide covers relay servers, peer discovery, WebRTC connections, and distributed architecture patterns.
Understanding GUN’s Network Architecture
GUN uses a mesh network topology where:
Peers connect directly to each other
Data syncs automatically across all peers
No single point of failure
Works offline with automatic sync when reconnected
Optional relay servers for peer discovery
Network Topology
Peer A ←→ Peer B
↕ ↕
Relay ←→ Peer C
↕ ↕
Peer D ←→ Peer E
Setting Up a Basic P2P Network
Client-Side Only (Browser-to-Browser)
Simplest setup using public relay servers:
// Connect to public relay servers
const gun = Gun ([
'https://gun-manhattan.herokuapp.com/gun' ,
'https://gun-us.herokuapp.com/gun'
]);
// All peers using these relays will sync automatically
const app = gun . get ( 'myapp' );
With Local Relay Server
For better control and performance:
// Client connects to local relay
const gun = Gun ([
'http://localhost:8765/gun' ,
'https://gun-manhattan.herokuapp.com/gun' // fallback
]);
Building a Relay Server
Simple HTTP Relay
Basic relay server using Node.js:
// server.js
const Gun = require ( 'gun' );
const http = require ( 'http' );
const port = process . env . PORT || 8765 ;
// Create HTTP server
const server = http . createServer ();
// Attach GUN
const gun = Gun ({
web: server ,
file: 'data' // persist to disk
});
server . listen ( port , () => {
console . log ( 'GUN relay server started on port' , port );
});
module . exports = gun ;
Run it:
Express.js Integration
Integrate with an existing Express app:
// express-server.js
const express = require ( 'express' );
const Gun = require ( 'gun' );
const app = express ();
const port = process . env . PORT || 8765 ;
// Serve GUN
app . use ( Gun . serve );
// Serve static files
app . use ( express . static ( __dirname + '/public' ));
// Create server
const server = app . listen ( port , () => {
console . log ( 'Server started on port' , port );
});
// Attach GUN
const gun = Gun ({
web: server ,
file: 'data' ,
peers: [
'https://gun-manhattan.herokuapp.com/gun'
]
});
console . log ( 'Relay peer started on port ' + port + ' with /gun' );
Production Relay with Clustering
High-availability relay with clustering:
// production-relay.js
const cluster = require ( 'cluster' );
const os = require ( 'os' );
if ( cluster . isMaster ) {
// Fork workers
const numCPUs = os . cpus (). length ;
console . log ( `Master process starting ${ numCPUs } workers` );
for ( let i = 0 ; i < numCPUs ; i ++ ) {
cluster . fork ();
}
// Restart dead workers
cluster . on ( 'exit' , ( worker ) => {
console . log ( `Worker ${ worker . process . pid } died, restarting...` );
cluster . fork ();
});
} else {
// Worker process
const Gun = require ( 'gun' );
const http = require ( 'http' );
const fs = require ( 'fs' );
const env = process . env ;
const opt = {
port: env . PORT || 8765 ,
peers: env . PEERS ? env . PEERS . split ( ',' ) : []
};
// HTTPS support
if ( env . HTTPS_KEY && fs . existsSync ( env . HTTPS_KEY )) {
opt . key = fs . readFileSync ( env . HTTPS_KEY );
opt . cert = fs . readFileSync ( env . HTTPS_CERT );
opt . server = require ( 'https' ). createServer ( opt , Gun . serve ());
// Redirect HTTP to HTTPS
require ( 'http' ). createServer (( req , res ) => {
res . writeHead ( 301 , {
"Location" : "https://" + req . headers [ 'host' ] + req . url
});
res . end ();
}). listen ( 80 );
} else {
opt . server = http . createServer ( Gun . serve ());
}
// Start GUN
const gun = Gun ({
web: opt . server . listen ( opt . port ),
peers: opt . peers ,
file: `data- ${ cluster . worker . id } `
});
console . log ( `Worker ${ cluster . worker . id } started on port ${ opt . port } ` );
}
Run with environment variables:
PORT = 8765 PEERS = https://gun-manhattan.herokuapp.com/gun node production-relay.js
Peer Discovery
Static Peer Configuration
const gun = Gun ({
peers: [
'http://server1.example.com/gun' ,
'http://server2.example.com/gun' ,
'http://server3.example.com/gun'
]
});
Dynamic Peer Discovery
// Add peers dynamically
const gun = Gun ();
// Discover peers from a directory service
fetch ( 'https://api.example.com/gun-peers' )
. then ( res => res . json ())
. then ( peers => {
peers . forEach ( peer => {
gun . opt ({ peers: [ peer ] });
});
});
// Or from DNS records
const peerAddresses = await dns . resolve ( '_gun._tcp.example.com' , 'SRV' );
peerAddresses . forEach ( addr => {
gun . opt ({ peers: [ `http:// ${ addr . name } : ${ addr . port } /gun` ] });
});
WebRTC Peer Discovery
// Using WebRTC for direct peer-to-peer
const gun = Gun ();
// Access mesh for WebRTC
const mesh = gun . back ( 'opt.mesh' );
// Initiate WebRTC connection
mesh . hi ( localStream ); // Share your stream
// Listen for incoming WebRTC connections
gun . on ( 'rtc' , ( event ) => {
console . log ( 'WebRTC connection:' , event );
if ( event . streams ) {
const remoteStream = event . streams [ 0 ];
// Use remote stream
}
});
Network Status and Monitoring
Check Connection Status
// Monitor connection status
const gun = Gun ([ 'http://localhost:8765/gun' ]);
gun . on ( 'hi' , ( peer ) => {
console . log ( 'Connected to peer:' , peer );
});
gun . on ( 'bye' , ( peer ) => {
console . log ( 'Disconnected from peer:' , peer );
});
// Get current peers
const peers = gun . back ( 'opt.peers' );
Object . keys ( peers ). forEach ( url => {
console . log ( 'Peer:' , url );
});
Network Statistics
// Track sync status
let syncCount = 0 ;
let errorCount = 0 ;
gun . on ( 'out' , ( msg ) => {
syncCount ++ ;
console . log ( 'Outgoing message:' , msg );
});
gun . on ( 'in' , ( msg ) => {
console . log ( 'Incoming message:' , msg );
});
gun . on ( 'create' , ( at ) => {
console . log ( 'New peer created:' , at );
});
Health Check Endpoint
// Add health check to relay server
app . get ( '/health' , ( req , res ) => {
const mesh = gun . back ( 'opt.mesh' );
const peers = Object . keys ( mesh . opt . peers || {});
res . json ({
status: 'ok' ,
peers: peers . length ,
uptime: process . uptime (),
memory: process . memoryUsage ()
});
});
Offline-First Architecture
Local-First with Background Sync
// Initialize with no peers for offline
const gun = Gun ();
// App works offline
gun . get ( 'myapp' ). get ( 'data' ). put ({ value: 'hello' });
// Connect to network when available
window . addEventListener ( 'online' , () => {
gun . opt ({
peers: [ 'http://localhost:8765/gun' ]
});
});
// Disconnect when offline
window . addEventListener ( 'offline' , () => {
console . log ( 'Working offline...' );
});
Service Worker for Offline Support
// service-worker.js
self . addEventListener ( 'install' , ( event ) => {
event . waitUntil (
caches . open ( 'gun-cache-v1' ). then (( cache ) => {
return cache . addAll ([
'/' ,
'/gun.js' ,
'/app.js' ,
'/style.css'
]);
})
);
});
self . addEventListener ( 'fetch' , ( event ) => {
event . respondWith (
caches . match ( event . request ). then (( response ) => {
return response || fetch ( event . request );
})
);
});
Data Replication Strategies
Full Replication
// Replicate entire database
const sourceGun = Gun ([ 'http://source.example.com/gun' ]);
const targetGun = Gun ([ 'http://target.example.com/gun' ]);
// Copy all data
sourceGun . get ( 'myapp' ). once (( data ) => {
targetGun . get ( 'myapp' ). put ( data );
});
// Continuous sync
sourceGun . get ( 'myapp' ). on (( data ) => {
targetGun . get ( 'myapp' ). put ( data );
});
Selective Replication
// Only replicate specific paths
const paths = [ 'users' , 'messages' , 'posts' ];
paths . forEach ( path => {
sourceGun . get ( path ). on (( data ) => {
targetGun . get ( path ). put ( data );
});
});
Time-Based Sync
// Only sync recent data
const cutoffTime = Date . now () - ( 24 * 60 * 60 * 1000 ); // 24 hours
gun . get ( 'messages' ). map (). on (( msg , id ) => {
if ( msg . timestamp > cutoffTime ) {
// Include in sync
replicaGun . get ( 'messages' ). get ( id ). put ( msg );
}
});
Security and Access Control
Peer Whitelisting
// Only allow specific peers
const allowedPeers = [
'http://trusted1.example.com/gun' ,
'http://trusted2.example.com/gun'
];
const gun = Gun ({
peers: allowedPeers ,
// Reject other peers
multicast: false
});
Rate Limiting
// Add rate limiting to relay
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 );
Authenticated Relays
// Require authentication for relay access
app . use ( '/gun' , ( req , res , next ) => {
const token = req . headers [ 'authorization' ];
if ( ! token || ! validateToken ( token )) {
return res . status ( 401 ). send ( 'Unauthorized' );
}
next ();
});
Deployment Options
Docker Deployment
# Dockerfile
FROM node:16-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 8765
CMD [ "node" , "server.js" ]
# Build and run
docker build -t gun-relay .
docker run -p 8765:8765 -v gun-data:/app/data gun-relay
Kubernetes Deployment
# gun-deployment.yaml
apiVersion : apps/v1
kind : Deployment
metadata :
name : gun-relay
spec :
replicas : 3
selector :
matchLabels :
app : gun-relay
template :
metadata :
labels :
app : gun-relay
spec :
containers :
- name : gun-relay
image : gun-relay:latest
ports :
- containerPort : 8765
env :
- name : PORT
value : "8765"
volumeMounts :
- name : data
mountPath : /app/data
volumes :
- name : data
persistentVolumeClaim :
claimName : gun-data-pvc
---
apiVersion : v1
kind : Service
metadata :
name : gun-relay-service
spec :
selector :
app : gun-relay
ports :
- port : 8765
targetPort : 8765
type : LoadBalancer
Systemd Service
# /etc/systemd/system/gun-relay.service
[Unit]
Description =GUN Relay Server
After =network.target
[Service]
Type =simple
User =gun
WorkingDirectory =/opt/gun-relay
ExecStart =/usr/bin/node server.js
Restart =on-failure
Environment = PORT =8765
Environment = NODE_ENV =production
[Install]
WantedBy =multi-user.target
# Enable and start
sudo systemctl enable gun-relay
sudo systemctl start gun-relay
sudo systemctl status gun-relay
Best Practices
Use Multiple Relays - Don’t rely on a single server
Enable HTTPS - Secure your connections
Monitor Health - Track peer connections and sync status
Implement Backups - Regularly backup relay data
Rate Limit - Protect against abuse
Geographic Distribution - Place relays near users
Graceful Degradation - Work offline when network unavailable
Troubleshooting
Connection Issues
// Debug connection problems
const gun = Gun ({
peers: [ 'http://localhost:8765/gun' ],
axe: false // disable connection timeout
});
// Log all events
gun . on ( 'hi' , peer => console . log ( 'Connected:' , peer ));
gun . on ( 'bye' , peer => console . log ( 'Disconnected:' , peer ));
gun . on ( 'error' , err => console . error ( 'Error:' , err ));
Network Inspector
// Monitor all network traffic
const gun = Gun ();
gun . on ( 'out' , msg => {
console . log ( '→ Outgoing:' , msg );
});
gun . on ( 'in' , msg => {
console . log ( '← Incoming:' , msg );
});
Next Steps
Chat App Build a P2P chat application
Security Learn about securing your network
Storage Adapters Persist data with custom adapters
Scaling Scale your GUN network