Replace DHT-based discovery with bootstrap peerstore and peer exchange. Update config and code to remove DHT references and dependencies. Add data directory override support in node config. Cleanup related config files and dependencies.
Network - Distributed P2P Database System v0.19.0-beta
A distributed peer-to-peer network built with Go and LibP2P, providing decentralized database capabilities with RQLite consensus and replication.
Table of Contents
- Features
- System Requirements
- Quick Start
- Deployment
- Configuration
- CLI Commands
- Development
- Client Library Usage
- Troubleshooting
- License
Features
- Peer-to-Peer Networking: Built on LibP2P for robust P2P communication
- Distributed Database: RQLite-based distributed SQLite with Raft consensus
- Automatic Peer Discovery: Nodes help new peers join the network
- CLI Tool: Command-line interface for network operations and testing
- Client Library: Simple Go API for applications to interact with the network
- Application Isolation: Namespaced storage and messaging per application
System Requirements
Software Dependencies
- Go: Version 1.21 or later
- RQLite: Distributed SQLite database
- Git: For cloning the repository
- Make: For build automation (optional but recommended)
Installation
macOS
# Install Homebrew if you don't have it
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# Install dependencies
brew install go rqlite git make
# Verify installation
go version # Should show Go 1.21+
rqlited --version
Ubuntu/Debian
# Install Go (latest version)
sudo rm -rf /usr/local/go
wget https://go.dev/dl/go1.21.6.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.21.6.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin
# Install RQLite
wget https://github.com/rqlite/rqlite/releases/download/v8.43.0/rqlite-v8.43.0-linux-amd64.tar.gz
tar -xzf rqlite-v8.43.0-linux-amd64.tar.gz
sudo mv rqlite-v8.43.0-linux-amd64/rqlited /usr/local/bin/
# Install other dependencies
sudo apt update
sudo apt install git make
# Verify installation
go version
rqlited --version
Windows
# Install Go from https://golang.org/dl/
# Install Git from https://git-scm.com/download/win
# Install RQLite from https://github.com/rqlite/rqlite/releases
# Or use Chocolatey
choco install golang git make
# Download RQLite manually from releases page
Hardware Requirements
Minimum:
- CPU: 2 cores
- RAM: 4GB
- Storage: 10GB free space
- Network: Stable internet connection
Recommended:
- CPU: 4+ cores
- RAM: 8GB+
- Storage: 50GB+ SSD
- Network: Low-latency internet connection
Network Ports
The system uses these ports by default:
- 4001: LibP2P communication
- 5001: RQLite HTTP API
- 7001: RQLite Raft consensus
Ensure these ports are available or configure firewall rules accordingly. The system will also use +1 for each extra node started. For example 4002, 5002, 7002
Quick Start
1. Clone and Setup Environment
# Clone the repository
git clone https://git.debros.io/DeBros/network.git
cd network
2. Build the Project
# Build all network executables
make build
# Build all network executables
make build
3. Start the Network
Terminal 1 - Bootstrap Node:
# Start the bootstrap node (LibP2P 4001, RQLite 5001/7001)
make run-node
Terminal 2 - Regular Node:
# Start a regular node and join the cluster using the bootstrap node's RQLite HTTP address
go run ./cmd/node --id node2 --data ./data/node2 --p2p-port 4002 --rqlite-http-port 5002 --rqlite-raft-port 7002 --rqlite-join-address http://127.0.0.1:5001 --disable-anonrc
Terminal 3 - Another Node (optional):
go run ./cmd/node --id node3 --data ./data/node3 --p2p-port 4003 --rqlite-http-port 5003 --rqlite-raft-port 7003 --rqlite-join-address http://127.0.0.1:5001 --disable-anonrc
5. Test with CLI
# Check current bootstrap configuration
make show-bootstrap
# Check network health
./bin/network-cli health
# Test storage operations
./bin/network-cli storage put test-key "Hello Network"
./bin/network-cli storage get test-key
# List connected peers
./bin/network-cli peers
Deployment
Production Installation Script
For production deployments on Linux servers, we provide an automated installation script that handles all dependencies, configuration, and service setup.
One-Command Installation
# Download and run the installation script
curl -sSL https://git.debros.io/DeBros/network/raw/branch/main/scripts/install-debros-network.sh | sudo bash
What the Script Does
-
System Setup:
- Detects OS (Ubuntu/Debian/CentOS/RHEL/Fedora)
- Installs Go 1.21+ with architecture detection
- Installs system dependencies (git, make, build tools)
- Checks port availability (4001, 5001, 7001)
-
Configuration Wizard:
- Solana wallet address for node operator rewards
- Installation directory (default:
/opt/debros
) - Automatic firewall configuration (UFW)
-
Secure Installation:
- Creates dedicated
debros
system user - Sets up secure directory structure with proper permissions
- Generates LibP2P identity keys with secure storage
- Clones source code and builds binaries
- Creates dedicated
-
Service Management:
- Creates systemd service with security hardening
- Enables automatic startup and restart on failure
- Configures structured logging to systemd journal
Directory Structure
The script creates a production-ready directory structure:
/opt/debros/
├── bin/ # Compiled binaries
│ ├── bootstrap # Bootstrap node executable
│ ├── node # Node executable
│ └── cli # CLI tools
├── configs/ # Configuration files
│ └── node.yaml # Node configuration
├── keys/ # Identity keys (secure 700 permissions)
│ └── node/
│ └── identity.key
├── data/ # Runtime data
│ └── node/
│ ├── rqlite/ # RQLite database files
│ └── storage/ # P2P storage data
├── logs/ # Application logs
│ └── node.log
└── src/ # Source code (for updates)
Node Setup
The installation script sets up a network node:
- Runs on ports: 4001 (P2P), 5001 (RQLite), 7001 (Raft)
- Participates in DHT for peer discovery and data replication
- Can be deployed on any server or VPS
For setup, please run these commands with adequate permissions:
- Ensure you have elevated privileges or run as a user with the necessary permissions for server setup.
- Follow the installation steps correctly to ensure a smooth deployment.
Service Management
After installation, manage your node with these commands:
# Check service status
sudo systemctl status debros-node
# Start/stop/restart service
sudo systemctl start debros-node
sudo systemctl stop debros-node
sudo systemctl restart debros-node
# View real-time logs
sudo journalctl -u debros-node.service -f
# Enable/disable auto-start
sudo systemctl enable debros-node
sudo systemctl disable debros-node
# Use CLI tools
/opt/debros/bin/network-cli health
/opt/debros/bin/network-cli peers
/opt/debros/bin/network-cli storage put key value
Configuration Files
The script generates YAML configuration files:
Node Configuration (/opt/debros/configs/node.yaml
):
node:
data_dir: "/opt/debros/data/node"
key_file: "/opt/debros/keys/node/identity.key"
listen_addresses:
- "/ip4/0.0.0.0/tcp/4001"
solana_wallet: "YOUR_WALLET_ADDRESS"
database:
rqlite_port: 5001
rqlite_raft_port: 7001
logging:
level: "info"
file: "/opt/debros/logs/node.log"
Security Features
The installation script implements production security best practices:
- Dedicated User: Runs as
debros
system user (not root) - File Permissions: Key files have 600 permissions, directories have proper ownership
- Systemd Security: Service runs with
NoNewPrivileges
,PrivateTmp
,ProtectSystem=strict
- Firewall: Automatic UFW configuration for required ports
- Network Isolation: Proper port management to avoid conflicts
Network Discovery
- Network Peers: Hardcoded in the application for automatic connection
- DHT Discovery: Nodes automatically join Kademlia DHT for peer discovery
- Peer Exchange: Connected nodes share information about other peers
- No Manual Configuration: Nodes connect automatically without user intervention
Updates and Maintenance
# Update to latest version (re-run the installation script)
curl -sSL https://git.debros.io/DeBros/network/raw/branch/main/scripts/install-debros-network.sh | bash
# Manual source update
cd /opt/debros/src
sudo -u debros git pull
sudo -u debros make build
sudo cp bin/* /opt/debros/bin/
sudo systemctl restart debros-node
# Backup configuration and keys
sudo cp -r /opt/debros/configs /backup/
sudo cp -r /opt/debros/keys /backup/
Monitoring and Troubleshooting
# Check if ports are open
sudo netstat -tuln | grep -E "(4001|5001|7001)"
# Check service logs
sudo journalctl -u debros-node.service --since "1 hour ago"
# Check network connectivity
/opt/debros/bin/network-cli health
/opt/debros/bin/network-cli peers
# Check disk usage
du -sh /opt/debros/data/*
# Process information
ps aux | grep debros
For more advanced configuration options and development setup, see the sections below.
Configuration
Node Startup Flags
- Bootstrap node: Just run
make run-node
(auto-selects data dir and identity) - Regular node: Use
--id
,--data
,--p2p-port
,--rqlite-http-port
,--rqlite-raft-port
, and--rqlite-join-address <http://bootstrap_host:5001>
- Disable anonymous routing:
--disable-anonrc
(optional) - Development localhost defaults: Use
--disable-anonrc
for local-only testing; the library returns localhost DB endpoints and bootstrap peers. - RQLite ports:
--rqlite-http-port
(default 5001),--rqlite-raft-port
(default 7001)
Examples are shown in Quick Start above for local multi-node on a single machine.
Environment Variables
Precedence: CLI flags > Environment variables > Code defaults. Set any of the following in your shell or .env
:
-
NODE_ID: custom node identifier (e.g. "node2")
-
NODE_TYPE: "bootstrap" or "node"
-
NODE_LISTEN_ADDRESSES: comma-separated multiaddrs (e.g. "/ip4/0.0.0.0/tcp/4001,/ip4/0.0.0.0/udp/4001/quic")
-
DATA_DIR: node data directory (default
./data
) -
MAX_CONNECTIONS: max peer connections (int)
-
DB_DATA_DIR: database data directory (default
./data/db
) -
REPLICATION_FACTOR: int (default 3)
-
SHARD_COUNT: int (default 16)
-
MAX_DB_SIZE: e.g. "1g", "512m", or bytes
-
BACKUP_INTERVAL: Go duration (e.g. "24h")
-
RQLITE_HTTP_PORT: int (default 5001)
-
RQLITE_RAFT_PORT: int (default 7001)
-
RQLITE_JOIN_ADDRESS: host:port for Raft join (regular nodes)
-
RQLITE_NODES: comma/space-separated DB endpoints (e.g. "http://n1:5001,http://n2:5001"). Used by client if
ClientConfig.DatabaseEndpoints
is empty. -
RQLITE_PORT: default DB HTTP port for constructing library defaults (fallback 5001)
-
NETWORK_DEV_LOCAL: when truthy (1/true/yes/on), client defaults use localhost for DB endpoints; default bootstrap peers also return localhost values.
-
LOCAL_BOOTSTRAP_MULTIADDR: when set with NETWORK_DEV_LOCAL, overrides default bootstrap with a specific local multiaddr (e.g.
/ip4/127.0.0.1/tcp/4001/p2p/<ID>
) -
ADVERTISE_MODE: "auto" | "localhost" | "ip"
-
BOOTSTRAP_PEERS: comma-separated multiaddrs for bootstrap peers
-
ENABLE_MDNS: true/false
-
ENABLE_DHT: true/false
-
DHT_PREFIX: string (default
/network/kad/1.0.0
) -
DISCOVERY_INTERVAL: duration (e.g. "5m")
-
ENABLE_TLS: true/false
-
PRIVATE_KEY_FILE: path
-
CERT_FILE: path
-
AUTH_ENABLED: true/false
-
LOG_LEVEL: "debug" | "info" | "warn" | "error"
-
LOG_FORMAT: "json" | "console"
-
LOG_OUTPUT_FILE: path (empty = stdout)
Centralized Flag/Env Mapping
Flag and environment variable mapping is centralized in cmd/node/configmap.go
via MapFlagsAndEnvToConfig
.
This enforces precedence (flags > env > defaults) consistently across the node startup path.
Centralized Defaults: Bootstrap & Database
- The network library is the single source of truth for defaults.
- Bootstrap peers:
pkg/constants/bootstrap.go
exposed viaclient.DefaultBootstrapPeers()
. - Database HTTP endpoints: derived from bootstrap peers via
client.DefaultDatabaseEndpoints()
.
Database Endpoints Precedence
When the client connects to RQLite, endpoints are resolved with this precedence:
ClientConfig.DatabaseEndpoints
(explicitly set by the app)RQLITE_NODES
environment variable (comma/space separated), e.g.http://x:5001,http://y:5001
client.DefaultDatabaseEndpoints()
(constructed from default bootstrap peers)
Notes:
- Default DB port is 5001. Override with
RQLITE_PORT
when constructing defaults. - Endpoints are normalized to include scheme and port; duplicates are removed.
Client Usage Example
cfg := client.DefaultClientConfig("my-app")
// Optional: override bootstrap peers
cfg.BootstrapPeers = []string{"/ip4/127.0.0.1/tcp/4001/p2p/<PEER_ID>"}
// Optional: prefer explicit DB endpoints
cfg.DatabaseEndpoints = []string{"http://127.0.0.1:5001"}
cli, err := client.NewClient(cfg)
// cli.Connect() will prefer cfg.DatabaseEndpoints, then RQLITE_NODES, then defaults
Development Mode (localhost-only)
To force localhost defaults for both database endpoints and bootstrap peers:
export NETWORK_DEV_LOCAL=1
# Optional: specify a local bootstrap peer multiaddr with peer ID
export LOCAL_BOOTSTRAP_MULTIADDR="/ip4/127.0.0.1/tcp/4001/p2p/<BOOTSTRAP_PEER_ID>"
# Optional: customize default DB port used in localhost endpoints
export RQLITE_PORT=5001
Notes:
- With
NETWORK_DEV_LOCAL
,client.DefaultDatabaseEndpoints()
returnshttp://127.0.0.1:$RQLITE_PORT
. client.DefaultBootstrapPeers()
returnsLOCAL_BOOTSTRAP_MULTIADDR
if set, otherwise/ip4/127.0.0.1/tcp/4001
.- If you construct config via
client.DefaultClientConfig(...)
, DB endpoints are pinned to localhost and will overrideRQLITE_NODES
automatically. - When
NETWORK_DEV_LOCAL
is set andLOCAL_BOOTSTRAP_MULTIADDR
is NOT set, the client attempts to auto-load the local bootstrap multiaddr (with peer ID) from./data/bootstrap/peer.info
(orLOCAL_BOOTSTRAP_INFO
path if provided). Only if no file is found does it fall back to/ip4/127.0.0.1/tcp/4001
.
Migration Guide for Apps (e.g., anchat)
- Stop hardcoding endpoints: Replace any hardcoded bootstrap peers and DB URLs with calls to
client.DefaultBootstrapPeers()
and, if needed, setClientConfig.DatabaseEndpoints
. - Prefer config over env: Set
ClientConfig.DatabaseEndpoints
in your app config. If not set, the library will readRQLITE_NODES
for backward compatibility. - Keep env compatibility: Existing environments using
RQLITE_NODES
andRQLITE_PORT
continue to work. - Minimal changes: Most apps only need to populate
ClientConfig.DatabaseEndpoints
and/or rely onclient.DefaultDatabaseEndpoints()
; no other code changes required.
Example migration snippet:
import netclient "git.debros.io/DeBros/network/pkg/client"
cfg := netclient.DefaultClientConfig("anchat")
// Use library defaults for bootstrap peers
cfg.BootstrapPeers = netclient.DefaultBootstrapPeers()
// Prefer explicit DB endpoints (can also leave empty to use env or defaults)
cfg.DatabaseEndpoints = []string{"http://127.0.0.1:5001"}
c, err := netclient.NewClient(cfg)
if err != nil { /* handle */ }
if err := c.Connect(); err != nil { /* handle */ }
defer c.Disconnect()
CLI Commands
The CLI can still accept --bootstrap <multiaddr>
to override discovery when needed.
Network Operations
./bin/network-cli health # Check network health
./bin/network-cli status # Get network status
./bin/network-cli peers # List connected peers
Storage Operations
./bin/network-cli storage put <key> <value> # Store data
./bin/network-cli storage get <key> # Retrieve data
./bin/network-cli storage list [prefix] # List keys
Database Operations
./bin/network-cli query "SELECT * FROM table" # Execute SQL
./bin/network-cli query "CREATE TABLE users (id INTEGER)" # DDL operations
Pub/Sub Messaging
./bin/network-cli pubsub publish <topic> <message> # Send message
./bin/network-cli pubsub subscribe <topic> [duration] # Listen for messages
./bin/network-cli pubsub topics # List active topics
CLI Options
--format json # Output in JSON format
--timeout 30s # Set operation timeout
--bootstrap <multiaddr> # Override bootstrap peer
Development
Project Structure
network/
├── cmd/
│ ├── node/ # Network node (bootstrap via flag)
│ │ ├── main.go # Entrypoint
│ │ └── configmap.go # Centralized flags/env → config mapping
│ └── cli/ # Command-line interface
├── pkg/
│ ├── client/ # Client library
│ ├── node/ # Node implementation
│ ├── database/ # RQLite integration
│ ├── storage/ # Storage service
│ ├── constants/ # Bootstrap configuration
│ └── config/ # System configuration
├── scripts/ # Helper scripts (install, security, tests)
├── bin/ # Built executables
Building and Testing
# Build all network executables
make build
# Show current bootstrap configuration
make show-bootstrap
# Run node (auto-detects bootstrap vs regular based on .env)
make run-node
# Clean data directories
make clean
# Run tests
go test ./...
# Full development workflow
make dev
Development Workflow
-
Initial Setup:
# Copy environment templates cp .env.example .env # Generate consistent bootstrap identity go run scripts/generate-bootstrap-identity.go # Update .env files with the generated peer ID
-
Build Everything:
make build # Build network components
-
Start Development Cluster:
# Terminal 1: Bootstrap node (auto-detected) make run-node # Terminal 2: Regular node (auto-connects via .env) make run-node # Terminal 3: Test with CLI ./bin/network-cli health ./bin/network-cli peers
Environment Setup
-
Install Dependencies:
# macOS brew install go rqlite git make # Ubuntu/Debian sudo apt install golang-go git make # Install RQLite from https://github.com/rqlite/rqlite/releases
-
Verify Installation:
go version # Should be 1.21+ rqlited --version make --version
-
Configure Environment:
# Setup .env files cp .env.example .env # Generate bootstrap identity go run scripts/generate-bootstrap-identity.go # Update .env files with generated peer ID
Configuration System
The network uses a dual configuration system:
- Environment Variables (.env files): Primary configuration method
- Hardcoded Constants: Fallback when .env files are not found
Bootstrap Configuration Priority:
- Command line flags (if provided)
- Environment variables from
.env
files - Hardcoded constants in
pkg/constants/bootstrap.go
- Auto-discovery from running bootstrap nodes
This ensures the network can start even without configuration files, while allowing easy customization for different environments.
Client Library Usage
package main
import (
"context"
"log"
"git.debros.io/DeBros/network/pkg/client"
)
func main() {
// Create client (bootstrap peer discovered automatically)
config := client.DefaultClientConfig("my-app")
networkClient, err := client.NewClient(config)
if err != nil {
log.Fatal(err)
}
// Connect to network
if err := networkClient.Connect(); err != nil {
log.Fatal(err)
}
defer networkClient.Disconnect()
// Use storage
ctx := context.Background()
storage := networkClient.Storage()
err = storage.Put(ctx, "user:123", []byte("user data"))
if err != nil {
log.Fatal(err)
}
data, err := storage.Get(ctx, "user:123")
if err != nil {
log.Fatal(err)
}
log.Printf("Retrieved: %s", string(data))
}
Troubleshooting
Common Issues
Bootstrap peer not found / Peer ID mismatch:
- Generate a new bootstrap identity:
go run scripts/generate-bootstrap-identity.go
- Update
.env
with the new peer ID - Restart the bootstrap node:
make run-node
- Check configuration:
make show-bootstrap
Nodes can't connect:
- Verify
.env
files have the correct bootstrap peer ID - Check that the bootstrap node is running:
ps aux | grep node
- Verify firewall settings and port availability (4001, 5001, 7001)
- Try restarting with clean data:
make clean && make run-node
Storage operations fail:
- Ensure at least one node is running and connected
- Check network health:
./bin/cli health
- Verify RQLite is properly installed:
rqlited --version
- Check for port conflicts:
netstat -an | grep -E "(4001|5001|7001)"
Debug Commands
# Check current configuration
make show-bootstrap
cat .env
# Check running processes
ps aux | grep -E "(bootstrap|node|rqlite)"
# Check port usage
netstat -an | grep -E "(4001|5001|7001)"
# Check bootstrap peer info
cat data/bootstrap/peer.info
# Clean and restart everything
make clean
make run-node # In one terminal (auto-detects as bootstrap)
make run-node # In another terminal (runs as regular node)
Environment-specific Issues
Development Environment:
- Always run
go run scripts/generate-bootstrap-identity.go
first - Update
.env
files with the generated peer ID - Use
make run-node
- the system auto-detects if it should run as bootstrap
Production Environment:
- Use stable, external bootstrap peer addresses
- Configure multiple bootstrap peers for redundancy
- Set
ENVIRONMENT=production
in.env
files
Configuration Validation
# Test bootstrap configuration loading
go run -c 'package main; import "fmt"; import "network/pkg/constants"; func main() { fmt.Printf("Bootstrap peers: %v\n", constants.GetBootstrapPeers()) }'
# Verify .env file syntax
grep -E "^[A-Z_]+=.*" .env
Logs and Data
- Node logs: Console output from each running process
- Data directories:
./data/bootstrap/
,./data/node/
, etc. - RQLite data:
./data/<node>/rqlite/
- Peer info:
./data/<node>/peer.info
- Bootstrap identity:
./data/bootstrap/identity.key
- Environment config:
./.env
License
MIT License - see LICENSE file for details.