Compare commits

...

3 Commits

3 changed files with 312 additions and 589 deletions

View File

@ -2,6 +2,68 @@
A distributed peer-to-peer network built with Go and LibP2P, providing decentralized database capabilities with RQLite consensus and replication. A distributed peer-to-peer network built with Go and LibP2P, providing decentralized database capabilities with RQLite consensus and replication.
## Table of Contents
- [Features](#features)
- [System Requirements](#system-requirements)
- [Software Dependencies](#software-dependencies)
- [Installation](#installation)
- [macOS](#macos)
- [Ubuntu/Debian](#ubuntudebian)
- [Windows](#windows)
- [Hardware Requirements](#hardware-requirements)
- [Network Ports](#network-ports)
- [Quick Start](#quick-start)
- [1. Clone and Setup Environment](#1-clone-and-setup-environment)
- [2. Generate Bootstrap Identity (Development Only)](#2-generate-bootstrap-identity-development-only)
- [3. Build the Project](#3-build-the-project)
- [4. Start the Network](#4-start-the-network)
- [5. Test with CLI](#5-test-with-cli)
- [6. Test Anchat Messaging](#6-test-anchat-messaging)
- [Deployment](#deployment)
- [Production Installation Script](#production-installation-script)
- [One-Command Installation](#one-command-installation)
- [What the Script Does](#what-the-script-does)
- [Directory Structure](#directory-structure)
- [Node Types](#node-types)
- [Service Management](#service-management)
- [Configuration Files](#configuration-files)
- [Security Features](#security-features)
- [Network Discovery](#network-discovery)
- [Updates and Maintenance](#updates-and-maintenance)
- [Monitoring and Troubleshooting](#monitoring-and-troubleshooting)
- [Environment Configuration](#environment-configuration)
- [Bootstrap Peers Configuration](#bootstrap-peers-configuration)
- [Setup for Development](#setup-for-development)
- [Configuration Files](#configuration-files-1)
- [Multiple Bootstrap Peers](#multiple-bootstrap-peers)
- [Checking Configuration](#checking-configuration)
- [CLI Commands](#cli-commands)
- [Network Operations](#network-operations)
- [Storage Operations](#storage-operations)
- [Database Operations](#database-operations)
- [Pub/Sub Messaging](#pubsub-messaging)
- [CLI Options](#cli-options)
- [Development](#development)
- [Project Structure](#project-structure)
- [Building and Testing](#building-and-testing)
- [Development Workflow](#development-workflow)
- [Environment Setup](#environment-setup)
- [Configuration System](#configuration-system)
- [Client Library Usage](#client-library-usage)
- [Anchat - Decentralized Messaging Application](#anchat---decentralized-messaging-application)
- [Features](#features-1)
- [Quick Start with Anchat](#quick-start-with-anchat)
- [Anchat Commands](#anchat-commands)
- [Anchat Configuration](#anchat-configuration)
- [Troubleshooting](#troubleshooting)
- [Common Issues](#common-issues)
- [Debug Commands](#debug-commands)
- [Environment-specific Issues](#environment-specific-issues)
- [Configuration Validation](#configuration-validation)
- [Logs and Data](#logs-and-data)
- [License](#license)
## Features ## Features
- **Peer-to-Peer Networking**: Built on LibP2P for robust P2P communication - **Peer-to-Peer Networking**: Built on LibP2P for robust P2P communication

View File

@ -1,554 +0,0 @@
#!/bin/bash
set -e # Exit on any error
trap 'echo -e "${RED}An error occurred. Installation aborted.${NOCOLOR}"; exit 1' ERR
# Color codes
RED='\033[0;31m'
GREEN='\033[0;32m'
CYAN='\033[0;36m'
BLUE='\033[38;2;2;128;175m'
YELLOW='\033[1;33m'
NOCOLOR='\033[0m'
# Default values
INSTALL_DIR="/opt/debros"
REPO_URL="https://github.com/DeBrosOfficial/debros-network.git"
MIN_GO_VERSION="1.19"
BOOTSTRAP_PORT="4001"
NODE_PORT="4002"
RQLITE_BOOTSTRAP_PORT="5001"
RQLITE_NODE_PORT="5002"
RAFT_BOOTSTRAP_PORT="7001"
RAFT_NODE_PORT="7002"
log() {
echo -e "${CYAN}[$(date '+%Y-%m-%d %H:%M:%S')]${NOCOLOR} $1"
}
error() {
echo -e "${RED}[ERROR]${NOCOLOR} $1"
}
success() {
echo -e "${GREEN}[SUCCESS]${NOCOLOR} $1"
}
warning() {
echo -e "${YELLOW}[WARNING]${NOCOLOR} $1"
}
# Check if running as root
if [[ $EUID -eq 0 ]]; then
error "This script should not be run as root. Please run as a regular user with sudo privileges."
exit 1
fi
# Check if sudo is available
if ! command -v sudo &>/dev/null; then
error "sudo command not found. Please ensure you have sudo privileges."
exit 1
fi
# Detect OS
detect_os() {
if [ -f /etc/os-release ]; then
. /etc/os-release
OS=$ID
VERSION=$VERSION_ID
else
error "Cannot detect operating system"
exit 1
fi
case $OS in
ubuntu|debian)
PACKAGE_MANAGER="apt"
;;
centos|rhel|fedora)
PACKAGE_MANAGER="yum"
if command -v dnf &> /dev/null; then
PACKAGE_MANAGER="dnf"
fi
;;
*)
error "Unsupported operating system: $OS"
exit 1
;;
esac
log "Detected OS: $OS $VERSION"
}
# Check Go installation and version
check_go_installation() {
if command -v go &> /dev/null; then
GO_VERSION=$(go version | awk '{print $3}' | sed 's/go//')
log "Found Go version: $GO_VERSION"
# Compare versions (simplified)
if [ "$(printf '%s\n' "$MIN_GO_VERSION" "$GO_VERSION" | sort -V | head -n1)" = "$MIN_GO_VERSION" ]; then
success "Go version is sufficient"
return 0
else
warning "Go version $GO_VERSION is too old. Minimum required: $MIN_GO_VERSION"
return 1
fi
else
log "Go not found on system"
return 1
fi
}
# Install Go
install_go() {
log "Installing Go..."
case $PACKAGE_MANAGER in
apt)
sudo apt update
sudo apt install -y wget
;;
yum|dnf)
sudo $PACKAGE_MANAGER install -y wget
;;
esac
# Download and install Go
GO_TARBALL="go1.21.0.linux-amd64.tar.gz"
ARCH=$(uname -m)
if [ "$ARCH" = "aarch64" ]; then
GO_TARBALL="go1.21.0.linux-arm64.tar.gz"
fi
cd /tmp
wget -q "https://golang.org/dl/$GO_TARBALL"
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf "$GO_TARBALL"
# Add Go to PATH
if ! grep -q "/usr/local/go/bin" ~/.bashrc; then
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc
fi
export PATH=$PATH:/usr/local/go/bin
success "Go installed successfully"
}
# Install system dependencies
install_dependencies() {
log "Installing system dependencies..."
case $PACKAGE_MANAGER in
apt)
sudo apt update
sudo apt install -y git make build-essential curl
;;
yum|dnf)
sudo $PACKAGE_MANAGER groupinstall -y "Development Tools"
sudo $PACKAGE_MANAGER install -y git make curl
;;
esac
success "System dependencies installed"
}
# Check port availability
check_ports() {
local ports=($BOOTSTRAP_PORT $NODE_PORT $RQLITE_BOOTSTRAP_PORT $RQLITE_NODE_PORT $RAFT_BOOTSTRAP_PORT $RAFT_NODE_PORT)
for port in "${ports[@]}"; do
if sudo netstat -tuln 2>/dev/null | grep -q ":$port " || ss -tuln 2>/dev/null | grep -q ":$port "; then
error "Port $port is already in use. Please free it up and try again."
exit 1
fi
done
success "All required ports are available"
}
# Configuration wizard
configuration_wizard() {
log "${BLUE}==================================================${NOCOLOR}"
log "${GREEN} DeBros Network Configuration Wizard ${NOCOLOR}"
log "${BLUE}==================================================${NOCOLOR}"
# Node type selection
while true; do
echo -e "${GREEN}Select node type:${NOCOLOR}"
echo -e "${CYAN}1) Bootstrap Node (Network entry point)${NOCOLOR}"
echo -e "${CYAN}2) Regular Node (Connects to existing network)${NOCOLOR}"
read -rp "Enter your choice (1 or 2): " NODE_TYPE_CHOICE
case $NODE_TYPE_CHOICE in
1)
NODE_TYPE="bootstrap"
break
;;
2)
NODE_TYPE="regular"
break
;;
*)
error "Invalid choice. Please enter 1 or 2."
;;
esac
done
# Solana wallet address
log "${GREEN}Enter your Solana wallet address to be eligible for node operator rewards:${NOCOLOR}"
while true; do
read -rp "Solana Wallet Address: " SOLANA_WALLET
if [[ -n "$SOLANA_WALLET" && ${#SOLANA_WALLET} -ge 32 ]]; then
break
else
error "Please enter a valid Solana wallet address"
fi
done
# Data directory
read -rp "Installation directory [default: $INSTALL_DIR]: " CUSTOM_INSTALL_DIR
if [[ -n "$CUSTOM_INSTALL_DIR" ]]; then
INSTALL_DIR="$CUSTOM_INSTALL_DIR"
fi
# Firewall configuration
read -rp "Configure firewall automatically? (yes/no) [default: yes]: " CONFIGURE_FIREWALL
CONFIGURE_FIREWALL="${CONFIGURE_FIREWALL:-yes}"
success "Configuration completed"
}
# Create user and directories
setup_directories() {
log "Setting up directories and permissions..."
# Create debros user if it doesn't exist
if ! id "debros" &>/dev/null; then
sudo useradd -r -s /bin/false -d "$INSTALL_DIR" debros
log "Created debros user"
fi
# Create directory structure
sudo mkdir -p "$INSTALL_DIR"/{bin,configs,keys,data,logs}
sudo mkdir -p "$INSTALL_DIR/keys/$NODE_TYPE"
sudo mkdir -p "$INSTALL_DIR/data/$NODE_TYPE"/{rqlite,storage}
# Set ownership and permissions
sudo chown -R debros:debros "$INSTALL_DIR"
sudo chmod 755 "$INSTALL_DIR"
sudo chmod 700 "$INSTALL_DIR/keys"
sudo chmod 600 "$INSTALL_DIR/keys/$NODE_TYPE" 2>/dev/null || true
success "Directory structure created"
}
# Clone or update repository
setup_source_code() {
log "Setting up source code..."
if [ -d "$INSTALL_DIR/src" ]; then
log "Updating existing repository..."
cd "$INSTALL_DIR/src"
sudo -u debros git pull
else
log "Cloning repository..."
sudo -u debros git clone "$REPO_URL" "$INSTALL_DIR/src"
cd "$INSTALL_DIR/src"
fi
success "Source code ready"
}
# Generate identity key
generate_identity() {
log "Generating node identity..."
cd "$INSTALL_DIR/src"
# Create a temporary Go program for key generation
cat > /tmp/generate_identity.go << 'EOF'
package main
import (
"crypto/rand"
"fmt"
"os"
"path/filepath"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/peer"
)
func main() {
if len(os.Args) != 2 {
fmt.Println("Usage: go run generate_identity.go <key_file_path>")
os.Exit(1)
}
keyFile := os.Args[1]
// Generate identity
priv, pub, err := crypto.GenerateKeyPairWithReader(crypto.Ed25519, 2048, rand.Reader)
if err != nil {
panic(err)
}
// Get peer ID
peerID, err := peer.IDFromPublicKey(pub)
if err != nil {
panic(err)
}
// Marshal private key
data, err := crypto.MarshalPrivateKey(priv)
if err != nil {
panic(err)
}
// Create directory
if err := os.MkdirAll(filepath.Dir(keyFile), 0700); err != nil {
panic(err)
}
// Save identity
if err := os.WriteFile(keyFile, data, 0600); err != nil {
panic(err)
}
fmt.Printf("Generated Peer ID: %s\n", peerID.String())
fmt.Printf("Identity saved to: %s\n", keyFile)
}
EOF
# Generate the identity key
sudo -u debros go run /tmp/generate_identity.go "$INSTALL_DIR/keys/$NODE_TYPE/identity.key"
rm /tmp/generate_identity.go
success "Node identity generated"
}
# Build binaries
build_binaries() {
log "Building DeBros Network binaries..."
cd "$INSTALL_DIR/src"
# Build all binaries
sudo -u debros make build
# Copy binaries to installation directory
sudo cp bin/* "$INSTALL_DIR/bin/"
sudo chown debros:debros "$INSTALL_DIR/bin/"*
success "Binaries built and installed"
}
# Generate configuration files
generate_configs() {
log "Generating configuration files..."
if [ "$NODE_TYPE" = "bootstrap" ]; then
cat > /tmp/config.yaml << EOF
node:
data_dir: "$INSTALL_DIR/data/bootstrap"
key_file: "$INSTALL_DIR/keys/bootstrap/identity.key"
listen_addresses:
- "/ip4/0.0.0.0/tcp/$BOOTSTRAP_PORT"
solana_wallet: "$SOLANA_WALLET"
database:
rqlite_port: $RQLITE_BOOTSTRAP_PORT
rqlite_raft_port: $RAFT_BOOTSTRAP_PORT
logging:
level: "info"
file: "$INSTALL_DIR/logs/bootstrap.log"
EOF
else
cat > /tmp/config.yaml << EOF
node:
data_dir: "$INSTALL_DIR/data/node"
key_file: "$INSTALL_DIR/keys/node/identity.key"
listen_addresses:
- "/ip4/0.0.0.0/tcp/$NODE_PORT"
solana_wallet: "$SOLANA_WALLET"
database:
rqlite_port: $RQLITE_NODE_PORT
rqlite_raft_port: $RAFT_NODE_PORT
logging:
level: "info"
file: "$INSTALL_DIR/logs/node.log"
EOF
fi
sudo mv /tmp/config.yaml "$INSTALL_DIR/configs/$NODE_TYPE.yaml"
sudo chown debros:debros "$INSTALL_DIR/configs/$NODE_TYPE.yaml"
success "Configuration files generated"
}
# Configure firewall
configure_firewall() {
if [[ "$CONFIGURE_FIREWALL" == "yes" ]]; then
log "Configuring firewall..."
if command -v ufw &> /dev/null; then
if [ "$NODE_TYPE" = "bootstrap" ]; then
sudo ufw allow $BOOTSTRAP_PORT
sudo ufw allow $RQLITE_BOOTSTRAP_PORT
sudo ufw allow $RAFT_BOOTSTRAP_PORT
else
sudo ufw allow $NODE_PORT
sudo ufw allow $RQLITE_NODE_PORT
sudo ufw allow $RAFT_NODE_PORT
fi
# Enable ufw if not already active
UFW_STATUS=$(sudo ufw status | grep -o "Status: [a-z]*" | awk '{print $2}' || echo "inactive")
if [[ "$UFW_STATUS" != "active" ]]; then
echo "y" | sudo ufw enable
fi
success "Firewall configured"
else
warning "UFW not found. Please configure firewall manually."
fi
fi
}
# Create systemd service
create_systemd_service() {
log "Creating systemd service..."
cat > /tmp/debros-$NODE_TYPE.service << EOF
[Unit]
Description=DeBros Network $NODE_TYPE Node
After=network.target
Wants=network-online.target
[Service]
Type=simple
User=debros
Group=debros
WorkingDirectory=$INSTALL_DIR
ExecStart=$INSTALL_DIR/bin/$NODE_TYPE -config $INSTALL_DIR/configs/$NODE_TYPE.yaml
Restart=always
RestartSec=10
StandardOutput=journal
StandardError=journal
SyslogIdentifier=debros-$NODE_TYPE
# Security settings
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=$INSTALL_DIR
[Install]
WantedBy=multi-user.target
EOF
sudo mv /tmp/debros-$NODE_TYPE.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable debros-$NODE_TYPE.service
success "Systemd service created and enabled"
}
# Start the service
start_service() {
log "Starting DeBros Network $NODE_TYPE node..."
sudo systemctl start debros-$NODE_TYPE.service
sleep 3
if systemctl is-active --quiet debros-$NODE_TYPE.service; then
success "DeBros Network $NODE_TYPE node started successfully"
else
error "Failed to start DeBros Network $NODE_TYPE node"
log "Check logs with: sudo journalctl -u debros-$NODE_TYPE.service"
exit 1
fi
}
# Display banner
display_banner() {
echo -e "${BLUE}========================================================================${NOCOLOR}"
echo -e "${CYAN}
____ ____ _ _ _ _
| _ \ ___| __ ) _ __ ___ ___ | \ | | ___| |___ _____ _ __| | __
| | | |/ _ \ _ \| __/ _ \/ __| | \| |/ _ \ __\ \ /\ / / _ \| __| |/ /
| |_| | __/ |_) | | | (_) \__ \ | |\ | __/ |_ \ V V / (_) | | | <
|____/ \___|____/|_| \___/|___/ |_| \_|\___|\__| \_/\_/ \___/|_| |_|\_\\
${NOCOLOR}"
echo -e "${BLUE}========================================================================${NOCOLOR}"
}
# Main installation function
main() {
display_banner
log "${BLUE}==================================================${NOCOLOR}"
log "${GREEN} Starting DeBros Network Installation ${NOCOLOR}"
log "${BLUE}==================================================${NOCOLOR}"
detect_os
check_ports
# Check and install Go if needed
if ! check_go_installation; then
install_go
fi
install_dependencies
configuration_wizard
setup_directories
setup_source_code
generate_identity
build_binaries
generate_configs
configure_firewall
create_systemd_service
start_service
# Display completion information
log "${BLUE}==================================================${NOCOLOR}"
log "${GREEN} Installation Complete! ${NOCOLOR}"
log "${BLUE}==================================================${NOCOLOR}"
log "${GREEN}Node Type:${NOCOLOR} ${CYAN}$NODE_TYPE${NOCOLOR}"
log "${GREEN}Installation Directory:${NOCOLOR} ${CYAN}$INSTALL_DIR${NOCOLOR}"
log "${GREEN}Configuration:${NOCOLOR} ${CYAN}$INSTALL_DIR/configs/$NODE_TYPE.yaml${NOCOLOR}"
log "${GREEN}Logs:${NOCOLOR} ${CYAN}$INSTALL_DIR/logs/$NODE_TYPE.log${NOCOLOR}"
if [ "$NODE_TYPE" = "bootstrap" ]; then
log "${GREEN}Bootstrap Port:${NOCOLOR} ${CYAN}$BOOTSTRAP_PORT${NOCOLOR}"
log "${GREEN}RQLite Port:${NOCOLOR} ${CYAN}$RQLITE_BOOTSTRAP_PORT${NOCOLOR}"
log "${GREEN}Raft Port:${NOCOLOR} ${CYAN}$RAFT_BOOTSTRAP_PORT${NOCOLOR}"
else
log "${GREEN}Node Port:${NOCOLOR} ${CYAN}$NODE_PORT${NOCOLOR}"
log "${GREEN}RQLite Port:${NOCOLOR} ${CYAN}$RQLITE_NODE_PORT${NOCOLOR}"
log "${GREEN}Raft Port:${NOCOLOR} ${CYAN}$RAFT_NODE_PORT${NOCOLOR}"
fi
log "${BLUE}==================================================${NOCOLOR}"
log "${GREEN}Management Commands:${NOCOLOR}"
log "${CYAN} - sudo systemctl status debros-$NODE_TYPE${NOCOLOR} (Check status)"
log "${CYAN} - sudo systemctl restart debros-$NODE_TYPE${NOCOLOR} (Restart service)"
log "${CYAN} - sudo systemctl stop debros-$NODE_TYPE${NOCOLOR} (Stop service)"
log "${CYAN} - sudo systemctl start debros-$NODE_TYPE${NOCOLOR} (Start service)"
log "${CYAN} - sudo journalctl -u debros-$NODE_TYPE.service -f${NOCOLOR} (View logs)"
log "${CYAN} - $INSTALL_DIR/bin/cli${NOCOLOR} (Use CLI tools)"
log "${BLUE}==================================================${NOCOLOR}"
success "DeBros Network $NODE_TYPE node is now running!"
log "${CYAN}For documentation visit: https://docs.debros.io${NOCOLOR}"
}
# Run main function
main "$@"

View File

@ -13,7 +13,7 @@ NOCOLOR='\033[0m'
# Default values # Default values
INSTALL_DIR="/opt/debros" INSTALL_DIR="/opt/debros"
REPO_URL="https://github.com/DeBrosOfficial/debros-network.git" REPO_URL="https://git.debros.io/DeBros/network.git"
MIN_GO_VERSION="1.19" MIN_GO_VERSION="1.19"
BOOTSTRAP_PORT="4001" BOOTSTRAP_PORT="4001"
NODE_PORT="4002" NODE_PORT="4002"
@ -21,6 +21,7 @@ RQLITE_BOOTSTRAP_PORT="5001"
RQLITE_NODE_PORT="5002" RQLITE_NODE_PORT="5002"
RAFT_BOOTSTRAP_PORT="7001" RAFT_BOOTSTRAP_PORT="7001"
RAFT_NODE_PORT="7002" RAFT_NODE_PORT="7002"
UPDATE_MODE=false
log() { log() {
echo -e "${CYAN}[$(date '+%Y-%m-%d %H:%M:%S')]${NOCOLOR} $1" echo -e "${CYAN}[$(date '+%Y-%m-%d %H:%M:%S')]${NOCOLOR} $1"
@ -80,6 +81,91 @@ detect_os() {
log "Detected OS: $OS $VERSION" log "Detected OS: $OS $VERSION"
} }
# Check if DeBros Network is already installed
check_existing_installation() {
if [ -d "$INSTALL_DIR" ] && [ -f "$INSTALL_DIR/bin/bootstrap" ] && [ -f "$INSTALL_DIR/bin/node" ]; then
log "Found existing DeBros Network installation at $INSTALL_DIR"
# Check if services are running
BOOTSTRAP_RUNNING=false
NODE_RUNNING=false
if systemctl is-active --quiet debros-bootstrap.service 2>/dev/null; then
BOOTSTRAP_RUNNING=true
log "Bootstrap service is currently running"
fi
if systemctl is-active --quiet debros-node.service 2>/dev/null; then
NODE_RUNNING=true
log "Node service is currently running"
fi
echo -e "${YELLOW}Existing installation detected!${NOCOLOR}"
echo -e "${CYAN}Options:${NOCOLOR}"
echo -e "${CYAN}1) Update existing installation${NOCOLOR}"
echo -e "${CYAN}2) Remove and reinstall${NOCOLOR}"
echo -e "${CYAN}3) Exit installer${NOCOLOR}"
while true; do
read -rp "Enter your choice (1, 2, or 3): " EXISTING_CHOICE
case $EXISTING_CHOICE in
1)
UPDATE_MODE=true
log "Will update existing installation"
return 0
;;
2)
log "Will remove and reinstall"
remove_existing_installation
UPDATE_MODE=false
return 0
;;
3)
log "Installation cancelled by user"
exit 0
;;
*)
error "Invalid choice. Please enter 1, 2, or 3."
;;
esac
done
else
UPDATE_MODE=false
return 0
fi
}
# Remove existing installation
remove_existing_installation() {
log "Removing existing installation..."
# Stop services if they exist
for service in debros-bootstrap debros-node; do
if systemctl list-unit-files | grep -q "$service.service"; then
log "Stopping $service service..."
sudo systemctl stop $service.service 2>/dev/null || true
sudo systemctl disable $service.service 2>/dev/null || true
sudo rm -f /etc/systemd/system/$service.service
fi
done
sudo systemctl daemon-reload
# Remove installation directory
if [ -d "$INSTALL_DIR" ]; then
sudo rm -rf "$INSTALL_DIR"
log "Removed installation directory"
fi
# Remove debros user
if id "debros" &>/dev/null; then
sudo userdel debros 2>/dev/null || true
log "Removed debros user"
fi
success "Existing installation removed"
}
# Check Go installation and version # Check Go installation and version
check_go_installation() { check_go_installation() {
if command -v go &> /dev/null; then if command -v go &> /dev/null; then
@ -127,31 +213,76 @@ install_go() {
sudo rm -rf /usr/local/go sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf "$GO_TARBALL" sudo tar -C /usr/local -xzf "$GO_TARBALL"
# Add Go to PATH # Add Go to system-wide PATH
if ! grep -q "/usr/local/go/bin" /etc/environment 2>/dev/null; then
echo 'PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/local/go/bin"' | sudo tee /etc/environment > /dev/null
fi
# Also add to current user's bashrc for compatibility
if ! grep -q "/usr/local/go/bin" ~/.bashrc; then if ! grep -q "/usr/local/go/bin" ~/.bashrc; then
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc
fi fi
# Update current session PATH
export PATH=$PATH:/usr/local/go/bin export PATH=$PATH:/usr/local/go/bin
success "Go installed successfully" success "Go installed successfully"
} }
# Install system dependencies # Install system dependencies
install_dependencies() { install_dependencies() {
log "Installing system dependencies..." log "Checking system dependencies..."
# Check which dependencies are missing
MISSING_DEPS=()
case $PACKAGE_MANAGER in case $PACKAGE_MANAGER in
apt) apt)
sudo apt update # Check for required packages
sudo apt install -y git make build-essential curl for pkg in git make build-essential curl; do
if ! dpkg -l | grep -q "^ii $pkg "; then
MISSING_DEPS+=($pkg)
fi
done
if [ ${#MISSING_DEPS[@]} -gt 0 ]; then
log "Installing missing dependencies: ${MISSING_DEPS[*]}"
sudo apt update
sudo apt install -y "${MISSING_DEPS[@]}"
else
success "All system dependencies already installed"
fi
;; ;;
yum|dnf) yum|dnf)
sudo $PACKAGE_MANAGER groupinstall -y "Development Tools" # Check for required packages
sudo $PACKAGE_MANAGER install -y git make curl for pkg in git make curl; do
if ! rpm -q $pkg &>/dev/null; then
MISSING_DEPS+=($pkg)
fi
done
# Check for development tools
if ! rpm -q gcc &>/dev/null; then
MISSING_DEPS+=("Development Tools")
fi
if [ ${#MISSING_DEPS[@]} -gt 0 ]; then
log "Installing missing dependencies: ${MISSING_DEPS[*]}"
if [[ " ${MISSING_DEPS[*]} " =~ " Development Tools " ]]; then
sudo $PACKAGE_MANAGER groupinstall -y "Development Tools"
fi
# Remove "Development Tools" from array for individual package installation
MISSING_DEPS=($(printf '%s\n' "${MISSING_DEPS[@]}" | grep -v "Development Tools"))
if [ ${#MISSING_DEPS[@]} -gt 0 ]; then
sudo $PACKAGE_MANAGER install -y "${MISSING_DEPS[@]}"
fi
else
success "All system dependencies already installed"
fi
;; ;;
esac esac
success "System dependencies installed" success "System dependencies ready"
} }
# Check port availability # Check port availability
@ -228,6 +359,8 @@ setup_directories() {
if ! id "debros" &>/dev/null; then if ! id "debros" &>/dev/null; then
sudo useradd -r -s /bin/false -d "$INSTALL_DIR" debros sudo useradd -r -s /bin/false -d "$INSTALL_DIR" debros
log "Created debros user" log "Created debros user"
else
log "User 'debros' already exists"
fi fi
# Create directory structure # Create directory structure
@ -235,13 +368,19 @@ setup_directories() {
sudo mkdir -p "$INSTALL_DIR/keys/$NODE_TYPE" sudo mkdir -p "$INSTALL_DIR/keys/$NODE_TYPE"
sudo mkdir -p "$INSTALL_DIR/data/$NODE_TYPE"/{rqlite,storage} sudo mkdir -p "$INSTALL_DIR/data/$NODE_TYPE"/{rqlite,storage}
# Set ownership and permissions # Set ownership first, then permissions
sudo chown -R debros:debros "$INSTALL_DIR" sudo chown -R debros:debros "$INSTALL_DIR"
sudo chmod 755 "$INSTALL_DIR" sudo chmod 755 "$INSTALL_DIR"
sudo chmod 700 "$INSTALL_DIR/keys" sudo chmod 700 "$INSTALL_DIR/keys"
sudo chmod 600 "$INSTALL_DIR/keys/$NODE_TYPE" 2>/dev/null || true sudo chmod 700 "$INSTALL_DIR/keys/$NODE_TYPE"
success "Directory structure created" # Ensure the debros user can write to the keys directory
sudo chmod 755 "$INSTALL_DIR/data"
sudo chmod 755 "$INSTALL_DIR/logs"
sudo chmod 755 "$INSTALL_DIR/configs"
sudo chmod 755 "$INSTALL_DIR/bin"
success "Directory structure ready"
} }
# Clone or update repository # Clone or update repository
@ -263,16 +402,30 @@ setup_source_code() {
# Generate identity key # Generate identity key
generate_identity() { generate_identity() {
local identity_file="$INSTALL_DIR/keys/$NODE_TYPE/identity.key"
if [ -f "$identity_file" ]; then
if [ "$UPDATE_MODE" = true ]; then
log "Identity key already exists, keeping existing key"
success "Using existing node identity"
return 0
else
log "Identity key already exists, regenerating..."
sudo rm -f "$identity_file"
fi
fi
log "Generating node identity..." log "Generating node identity..."
cd "$INSTALL_DIR/src" cd "$INSTALL_DIR/src"
# Create a temporary Go program for key generation # Create a custom identity generation script with output path support
cat > /tmp/generate_identity.go << 'EOF' cat > /tmp/generate_identity_custom.go << 'EOF'
package main package main
import ( import (
"crypto/rand" "crypto/rand"
"flag"
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
@ -282,13 +435,15 @@ import (
) )
func main() { func main() {
if len(os.Args) != 2 { var outputPath string
fmt.Println("Usage: go run generate_identity.go <key_file_path>") flag.StringVar(&outputPath, "output", "", "Output path for identity key")
flag.Parse()
if outputPath == "" {
fmt.Println("Usage: go run generate_identity_custom.go -output <path>")
os.Exit(1) os.Exit(1)
} }
keyFile := os.Args[1]
// Generate identity // Generate identity
priv, pub, err := crypto.GenerateKeyPairWithReader(crypto.Ed25519, 2048, rand.Reader) priv, pub, err := crypto.GenerateKeyPairWithReader(crypto.Ed25519, 2048, rand.Reader)
if err != nil { if err != nil {
@ -308,23 +463,24 @@ func main() {
} }
// Create directory // Create directory
if err := os.MkdirAll(filepath.Dir(keyFile), 0700); err != nil { if err := os.MkdirAll(filepath.Dir(outputPath), 0700); err != nil {
panic(err) panic(err)
} }
// Save identity // Save identity
if err := os.WriteFile(keyFile, data, 0600); err != nil { if err := os.WriteFile(outputPath, data, 0600); err != nil {
panic(err) panic(err)
} }
fmt.Printf("Generated Peer ID: %s\n", peerID.String()) fmt.Printf("Generated Peer ID: %s\n", peerID.String())
fmt.Printf("Identity saved to: %s\n", keyFile) fmt.Printf("Identity saved to: %s\n", outputPath)
} }
EOF EOF
# Generate the identity key # Ensure Go is in PATH and generate the identity key
sudo -u debros go run /tmp/generate_identity.go "$INSTALL_DIR/keys/$NODE_TYPE/identity.key" export PATH=$PATH:/usr/local/go/bin
rm /tmp/generate_identity.go sudo -u debros env "PATH=$PATH:/usr/local/go/bin" "GOMOD=$(pwd)" go run /tmp/generate_identity_custom.go -output "$identity_file"
rm /tmp/generate_identity_custom.go
success "Node identity generated" success "Node identity generated"
} }
@ -335,8 +491,9 @@ build_binaries() {
cd "$INSTALL_DIR/src" cd "$INSTALL_DIR/src"
# Build all binaries # Ensure Go is in PATH and build all binaries
sudo -u debros make build export PATH=$PATH:/usr/local/go/bin
sudo -u debros env "PATH=$PATH:/usr/local/go/bin" make build
# Copy binaries to installation directory # Copy binaries to installation directory
sudo cp bin/* "$INSTALL_DIR/bin/" sudo cp bin/* "$INSTALL_DIR/bin/"
@ -422,7 +579,32 @@ configure_firewall() {
# Create systemd service # Create systemd service
create_systemd_service() { create_systemd_service() {
log "Creating systemd service..." local service_file="/etc/systemd/system/debros-$NODE_TYPE.service"
# Always clean up any existing service files to ensure fresh start
for service in debros-bootstrap debros-node; do
if [ -f "/etc/systemd/system/$service.service" ]; then
log "Cleaning up existing $service service..."
sudo systemctl stop $service.service 2>/dev/null || true
sudo systemctl disable $service.service 2>/dev/null || true
sudo rm -f /etc/systemd/system/$service.service
fi
done
sudo systemctl daemon-reload
log "Creating new systemd service..."
# Determine the correct ExecStart command based on node type
local exec_start=""
if [ "$NODE_TYPE" = "bootstrap" ]; then
exec_start="$INSTALL_DIR/bin/bootstrap -data $INSTALL_DIR/data/bootstrap -port $BOOTSTRAP_PORT"
else
# For regular nodes, we need to specify the bootstrap peer
# This should be configured based on the bootstrap node's address
exec_start="$INSTALL_DIR/bin/node -data $INSTALL_DIR/data/node -port $NODE_PORT"
# Note: Bootstrap peer address would need to be configured separately
# exec_start="$INSTALL_DIR/bin/node -data $INSTALL_DIR/data/node -port $NODE_PORT -bootstrap /ip4/BOOTSTRAP_IP/tcp/$BOOTSTRAP_PORT/p2p/BOOTSTRAP_PEER_ID"
fi
cat > /tmp/debros-$NODE_TYPE.service << EOF cat > /tmp/debros-$NODE_TYPE.service << EOF
[Unit] [Unit]
@ -435,7 +617,7 @@ Type=simple
User=debros User=debros
Group=debros Group=debros
WorkingDirectory=$INSTALL_DIR WorkingDirectory=$INSTALL_DIR
ExecStart=$INSTALL_DIR/bin/$NODE_TYPE -config $INSTALL_DIR/configs/$NODE_TYPE.yaml ExecStart=$exec_start
Restart=always Restart=always
RestartSec=10 RestartSec=10
StandardOutput=journal StandardOutput=journal
@ -453,11 +635,11 @@ ReadWritePaths=$INSTALL_DIR
WantedBy=multi-user.target WantedBy=multi-user.target
EOF EOF
sudo mv /tmp/debros-$NODE_TYPE.service /etc/systemd/system/ sudo mv /tmp/debros-$NODE_TYPE.service "$service_file"
sudo systemctl daemon-reload sudo systemctl daemon-reload
sudo systemctl enable debros-$NODE_TYPE.service sudo systemctl enable debros-$NODE_TYPE.service
success "Systemd service created and enabled" success "Systemd service ready"
} }
# Start the service # Start the service
@ -498,6 +680,7 @@ main() {
log "${BLUE}==================================================${NOCOLOR}" log "${BLUE}==================================================${NOCOLOR}"
detect_os detect_os
check_existing_installation
check_ports check_ports
# Check and install Go if needed # Check and install Go if needed
@ -506,19 +689,47 @@ main() {
fi fi
install_dependencies install_dependencies
configuration_wizard
# Skip configuration wizard in update mode
if [ "$UPDATE_MODE" != true ]; then
configuration_wizard
else
log "Update mode: skipping configuration wizard"
# Detect existing node type
if [ -f "$INSTALL_DIR/configs/bootstrap.yaml" ]; then
NODE_TYPE="bootstrap"
elif [ -f "$INSTALL_DIR/configs/node.yaml" ]; then
NODE_TYPE="node"
else
error "Cannot determine existing node type"
exit 1
fi
log "Detected existing node type: $NODE_TYPE"
fi
setup_directories setup_directories
setup_source_code setup_source_code
generate_identity generate_identity
build_binaries build_binaries
generate_configs
configure_firewall # Only generate new configs if not in update mode
if [ "$UPDATE_MODE" != true ]; then
generate_configs
configure_firewall
else
log "Update mode: keeping existing configuration"
fi
create_systemd_service create_systemd_service
start_service start_service
# Display completion information # Display completion information
log "${BLUE}==================================================${NOCOLOR}" log "${BLUE}==================================================${NOCOLOR}"
log "${GREEN} Installation Complete! ${NOCOLOR}" if [ "$UPDATE_MODE" = true ]; then
log "${GREEN} Update Complete! ${NOCOLOR}"
else
log "${GREEN} Installation Complete! ${NOCOLOR}"
fi
log "${BLUE}==================================================${NOCOLOR}" log "${BLUE}==================================================${NOCOLOR}"
log "${GREEN}Node Type:${NOCOLOR} ${CYAN}$NODE_TYPE${NOCOLOR}" log "${GREEN}Node Type:${NOCOLOR} ${CYAN}$NODE_TYPE${NOCOLOR}"
@ -543,10 +754,14 @@ main() {
log "${CYAN} - sudo systemctl stop debros-$NODE_TYPE${NOCOLOR} (Stop service)" log "${CYAN} - sudo systemctl stop debros-$NODE_TYPE${NOCOLOR} (Stop service)"
log "${CYAN} - sudo systemctl start debros-$NODE_TYPE${NOCOLOR} (Start service)" log "${CYAN} - sudo systemctl start debros-$NODE_TYPE${NOCOLOR} (Start service)"
log "${CYAN} - sudo journalctl -u debros-$NODE_TYPE.service -f${NOCOLOR} (View logs)" log "${CYAN} - sudo journalctl -u debros-$NODE_TYPE.service -f${NOCOLOR} (View logs)"
log "${CYAN} - $INSTALL_DIR/bin/cli${NOCOLOR} (Use CLI tools)" log "${CYAN} - $INSTALL_DIR/bin/network-cli${NOCOLOR} (Use CLI tools)"
log "${BLUE}==================================================${NOCOLOR}" log "${BLUE}==================================================${NOCOLOR}"
success "DeBros Network $NODE_TYPE node is now running!" if [ "$UPDATE_MODE" = true ]; then
success "DeBros Network $NODE_TYPE node has been updated and is running!"
else
success "DeBros Network $NODE_TYPE node is now running!"
fi
log "${CYAN}For documentation visit: https://docs.debros.io${NOCOLOR}" log "${CYAN}For documentation visit: https://docs.debros.io${NOCOLOR}"
} }