From 7c9851729e9f4a284802a8139db7300e431ca827 Mon Sep 17 00:00:00 2001 From: anonpenguin23 Date: Sat, 25 Oct 2025 08:19:31 +0300 Subject: [PATCH 1/2] chore: update .gitignore and CHANGELOG for new development features - Added .dev/ directory to .gitignore to exclude development process files. - Updated CHANGELOG.md with new entries for the one-command `make dev` target, full stack initialization, and improved configuration management. - Simplified README instructions for generating configuration files and starting the complete network stack. --- .gitignore | 2 + CHANGELOG.md | 23 +++++ Makefile | 145 +++++++++--------------------- README.md | 126 ++++++++++++++------------ cmd/cli/main.go | 225 ++++++++++++++++++++++++++++++++++++++++++++--- pkg/node/node.go | 105 ++++++++++++++-------- 6 files changed, 417 insertions(+), 209 deletions(-) diff --git a/.gitignore b/.gitignore index 4eff86c..01a1c94 100644 --- a/.gitignore +++ b/.gitignore @@ -73,3 +73,5 @@ data/bootstrap/rqlite/ .env.* configs/ + +.dev/ \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index c6f16d3..1e55359 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,14 +8,37 @@ The format is based on [Keep a Changelog][keepachangelog] and adheres to [Semant ### Added +- One-command `make dev` target to start full development stack (bootstrap + node2 + node3 + gateway in background) +- New `network-cli config init` (no --type) generates complete development stack with all configs and identities +- Full stack initialization with auto-generated peer identities for bootstrap and all nodes +- Explicit control over LibP2P listen addresses for better localhost/development support +- Production/development mode detection for NAT services (disabled for localhost, enabled for production) +- Process management with .dev/pids directory for background process tracking +- Centralized logging to ~/.debros/logs/ for all network services + ### Changed +- Simplified Makefile: removed legacy dev commands, replaced with unified `make dev` target +- Updated README with clearer getting started instructions (single `make dev` command) +- Simplified `network-cli config init` behavior: defaults to generating full stack instead of single node +- `network-cli config init` now handles bootstrap peer discovery and join addresses automatically +- LibP2P configuration: removed always-on NAT services for development environments +- Code formatting in pkg/node/node.go (indentation fixes in bootstrapPeerSource) + ### Deprecated ### Removed +- Removed legacy Makefile targets: run-example, show-bootstrap, run-cli, cli-health, cli-peers, cli-status, cli-storage-test, cli-pubsub-test +- Removed verbose dev-setup, dev-cluster, and old dev workflow targets + ### Fixed +- Fixed indentation in bootstrapPeerSource function for consistency +- Fixed gateway.yaml generation with correct YAML indentation for bootstrap_peers + +### Security + ## [0.51.6] - 2025-10-24 ### Added diff --git a/Makefile b/Makefile index b6d9927..4fa79e3 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,7 @@ test-e2e: .PHONY: build clean test run-node run-node2 run-node3 run-example deps tidy fmt vet lint clear-ports -VERSION := 0.51.6-beta +VERSION := 0.51.7-beta COMMIT ?= $(shell git rev-parse --short HEAD 2>/dev/null || echo unknown) DATE ?= $(shell date -u +%Y-%m-%dT%H:%M:%SZ) LDFLAGS := -X 'main.version=$(VERSION)' -X 'main.commit=$(COMMIT)' -X 'main.date=$(DATE)' @@ -77,110 +77,45 @@ run-gateway: @echo "Generate it with: network-cli config init --type gateway" go run ./cmd/gateway -# Run basic usage example -run-example: - @echo "Running basic usage example..." - go run examples/basic_usage.go - -# Show how to run with flags -show-bootstrap: - @echo "Provide join address via flags, e.g.:" - @echo " make run-node2 JOINADDR=/ip4/127.0.0.1/tcp/5001 HTTP=5002 RAFT=7002 P2P=4002" - -# Run network CLI -run-cli: - @echo "Running network CLI help..." - ./bin/network-cli help - -# Network CLI helper commands -cli-health: - @echo "Checking network health..." - ./bin/network-cli health - -cli-peers: - @echo "Listing network peers..." - ./bin/network-cli peers - -cli-status: - @echo "Getting network status..." - ./bin/network-cli status - -cli-storage-test: - @echo "Testing storage operations..." - @./bin/network-cli storage put test-key "Hello Network" || echo "Storage test requires running network" - @./bin/network-cli storage get test-key || echo "Storage test requires running network" - @./bin/network-cli storage list || echo "Storage test requires running network" - -cli-pubsub-test: - @echo "Testing pub/sub operations..." - @./bin/network-cli pubsub publish test-topic "Hello World" || echo "PubSub test requires running network" - @./bin/network-cli pubsub topics || echo "PubSub test requires running network" - -# Download dependencies -deps: - @echo "Downloading dependencies..." - go mod download - -# Tidy dependencies -tidy: - @echo "Tidying dependencies..." - go mod tidy - -# Format code -fmt: - @echo "Formatting code..." - go fmt ./... - -# Vet code -vet: - @echo "Vetting code..." - go vet ./... - -# Lint alias (lightweight for now) -lint: fmt vet - @echo "Linting complete (fmt + vet)" - -# Clear common development ports -clear-ports: - @echo "Clearing common dev ports (4001/4002, 5001/5002, 7001/7002)..." - @chmod +x scripts/clear-ports.sh || true - @scripts/clear-ports.sh - -# Development setup -dev-setup: deps - @echo "Setting up development environment..." - @mkdir -p data/bootstrap data/node data/node2 data/node3 - @mkdir -p data/test-bootstrap data/test-node1 data/test-node2 - @echo "Development setup complete!" - -# Start development cluster (requires multiple terminals) -dev-cluster: - @echo "To start a development cluster with 3 nodes:" +# One-command dev: Start bootstrap, node2, node3, and gateway in background +# Requires: configs already exist in ~/.debros +dev: build + @echo "🚀 Starting development network stack..." + @mkdir -p .dev/pids + @mkdir -p $$HOME/.debros/logs + @echo "Starting bootstrap node..." + @nohup ./bin/node --config bootstrap.yaml > $$HOME/.debros/logs/bootstrap.log 2>&1 & echo $$! > .dev/pids/bootstrap.pid + @sleep 2 + @echo "Starting node2..." + @nohup ./bin/node --config node2.yaml > $$HOME/.debros/logs/node2.log 2>&1 & echo $$! > .dev/pids/node2.pid + @sleep 1 + @echo "Starting node3..." + @nohup ./bin/node --config node3.yaml > $$HOME/.debros/logs/node3.log 2>&1 & echo $$! > .dev/pids/node3.pid + @sleep 1 + @echo "Starting gateway..." + @nohup ./bin/gateway --config gateway.yaml > $$HOME/.debros/logs/gateway.log 2>&1 & echo $$! > .dev/pids/gateway.pid @echo "" - @echo "1. Generate config files in ~/.debros:" - @echo " make build" - @echo " ./bin/network-cli config init --type bootstrap" - @echo " ./bin/network-cli config init --type node --name node.yaml --bootstrap-peers ''" - @echo " ./bin/network-cli config init --type node --name node2.yaml --bootstrap-peers ''" + @echo "============================================================" + @echo "✅ Development stack started!" + @echo "============================================================" @echo "" - @echo "2. Run in separate terminals:" - @echo " Terminal 1: make run-node # Start bootstrap node (bootstrap.yaml)" - @echo " Terminal 2: make run-node2 # Start node 1 (node.yaml)" - @echo " Terminal 3: make run-node3 # Start node 2 (node2.yaml)" - @echo " Terminal 4: make run-gateway # Start gateway" + @echo "Processes:" + @echo " Bootstrap: PID=$$(cat .dev/pids/bootstrap.pid)" + @echo " Node2: PID=$$(cat .dev/pids/node2.pid)" + @echo " Node3: PID=$$(cat .dev/pids/node3.pid)" + @echo " Gateway: PID=$$(cat .dev/pids/gateway.pid)" @echo "" - @echo "3. Or run custom node with any config file:" - @echo " go run ./cmd/node --config custom-node.yaml" + @echo "Ports:" + @echo " Bootstrap P2P: 4001, HTTP: 5001, Raft: 7001" + @echo " Node2 P2P: 4002, HTTP: 5002, Raft: 7002" + @echo " Node3 P2P: 4003, HTTP: 5003, Raft: 7003" + @echo " Gateway: 6001" @echo "" - @echo "4. Test:" - @echo " make cli-health # Check network health" - @echo " make cli-peers # List peers" - @echo " make cli-storage-test # Test storage" - @echo " make cli-pubsub-test # Test messaging" - -# Full development workflow -dev: clean build test - @echo "Development workflow complete!" + @echo "Press Ctrl+C to stop all processes" + @echo "============================================================" + @echo "" + @trap 'echo "Stopping all processes..."; kill $$(cat .dev/pids/*.pid) 2>/dev/null; rm -f .dev/pids/*.pid; exit 0' INT; \ + tail -f $$HOME/.debros/logs/bootstrap.log $$HOME/.debros/logs/node2.log $$HOME/.debros/logs/node3.log $$HOME/.debros/logs/gateway.log # Help help: @@ -189,12 +124,14 @@ help: @echo " clean - Clean build artifacts" @echo " test - Run tests" @echo "" + @echo "Development:" + @echo " dev - Start full dev stack (bootstrap + 2 nodes + gateway)" + @echo " Requires: configs in ~/.debros (run 'network-cli config init' first)" + @echo "" @echo "Configuration (NEW):" @echo " First, generate config files in ~/.debros with:" @echo " make build # Build CLI first" - @echo " ./bin/network-cli config init --type bootstrap # Generate bootstrap config" - @echo " ./bin/network-cli config init --type node --bootstrap-peers ''" - @echo " ./bin/network-cli config init --type gateway" + @echo " ./bin/network-cli config init # Generate full stack" @echo "" @echo "Network Targets (requires config files in ~/.debros):" @echo " run-node - Start bootstrap node" diff --git a/README.md b/README.md index af7c92f..f0826fd 100644 --- a/README.md +++ b/README.md @@ -174,23 +174,36 @@ cd network make build ``` -### 3. Start a Bootstrap Node +### 3. Generate Configuration Files ```bash -make run-node -# Or manually: -go run ./cmd/node --config configs/node.yaml +# Generate all configs (bootstrap, node2, node3, gateway) with one command +./bin/network-cli config init ``` -### 4. Start Additional Nodes +This creates: +- `~/.debros/bootstrap.yaml` - Bootstrap node +- `~/.debros/node2.yaml` - Regular node 2 +- `~/.debros/node3.yaml` - Regular node 3 +- `~/.debros/gateway.yaml` - HTTP Gateway + +Plus auto-generated identities for each node. + +### 4. Start the Complete Network Stack ```bash -make run-node2 -# Or manually: -go run ./cmd/node --config configs/node.yaml +make dev ``` -### 5. Test with CLI +This starts: +- Bootstrap node (P2P: 4001, RQLite HTTP: 5001, Raft: 7001) +- Node 2 (P2P: 4002, RQLite HTTP: 5002, Raft: 7002) +- Node 3 (P2P: 4003, RQLite HTTP: 5003, Raft: 7003) +- Gateway (HTTP: 6001) + +Logs stream to terminal. Press **Ctrl+C** to stop all processes. + +### 5. Test with CLI (in another terminal) ```bash ./bin/network-cli health @@ -261,100 +274,103 @@ The system will **only** load config from `~/.debros/` and will error if require Use the `network-cli config init` command to generate configuration files: -#### Generate a Node Config +### Generate Complete Stack (Recommended) + +```bash +# Generate bootstrap, node2, node3, and gateway configs in one command +./bin/network-cli config init + +# Force regenerate (overwrites existing configs) +./bin/network-cli config init --force +``` + +This is the **recommended way** to get started with a local development network. + +### Generate Individual Configs (Advanced) + +For custom setups or production deployments, you can generate individual configs: + +#### Generate a Single Node Config ```bash # Generate basic node config with bootstrap peers -network-cli config init --type node --bootstrap-peers "/ip4/127.0.0.1/tcp/4001/p2p/QmXxx,/ip4/127.0.0.1/tcp/4002/p2p/QmYyy" +./bin/network-cli config init --type node --bootstrap-peers "/ip4/127.0.0.1/tcp/4001/p2p/QmXxx" # With custom ports -network-cli config init --type node --name node2.yaml --listen-port 4002 --rqlite-http-port 5002 --rqlite-raft-port 7002 --join localhost:5001 --bootstrap-peers "/ip4/127.0.0.1/tcp/4001/p2p/QmXxx" +./bin/network-cli config init --type node --name node2.yaml \ + --listen-port 4002 --rqlite-http-port 5002 --rqlite-raft-port 7002 \ + --join localhost:5001 --bootstrap-peers "/ip4/127.0.0.1/tcp/4001/p2p/QmXxx" # Force overwrite existing config -network-cli config init --type node --force +./bin/network-cli config init --type node --force ``` #### Generate a Bootstrap Node Config ```bash # Generate bootstrap node (no join address required) -network-cli config init --type bootstrap +./bin/network-cli config init --type bootstrap # With custom ports -network-cli config init --type bootstrap --listen-port 4001 --rqlite-http-port 5001 --rqlite-raft-port 7001 +./bin/network-cli config init --type bootstrap --listen-port 4001 --rqlite-http-port 5001 --rqlite-raft-port 7001 ``` #### Generate a Gateway Config ```bash # Generate gateway config -network-cli config init --type gateway +./bin/network-cli config init --type gateway # With bootstrap peers -network-cli config init --type gateway --bootstrap-peers "/ip4/127.0.0.1/tcp/4001/p2p/QmXxx" +./bin/network-cli config init --type gateway --bootstrap-peers "/ip4/127.0.0.1/tcp/4001/p2p/QmXxx" ``` -### Running Multiple Nodes on the Same Machine +### Running the Network -You can run multiple nodes on a single machine by creating separate configuration files and using the `--config` flag: - -#### Create Multiple Node Configs +Once configs are generated, start the complete stack with: ```bash -# Node 1 -./bin/network-cli config init --type node --name node1.yaml \ - --listen-port 4001 --rqlite-http-port 5001 --rqlite-raft-port 7001 \ - --bootstrap-peers "/ip4/127.0.0.1/tcp/4001/p2p/" - -# Node 2 -./bin/network-cli config init --type node --name node2.yaml \ - --listen-port 4002 --rqlite-http-port 5002 --rqlite-raft-port 7002 \ - --join localhost:5001 \ - --bootstrap-peers "/ip4/127.0.0.1/tcp/4001/p2p/" - -# Node 3 -./bin/network-cli config init --type node --name node3.yaml \ - --listen-port 4003 --rqlite-http-port 5003 --rqlite-raft-port 7003 \ - --join localhost:5001 \ - --bootstrap-peers "/ip4/127.0.0.1/tcp/4001/p2p/" +make dev ``` -#### Run Multiple Nodes in Separate Terminals +Or start individual components (in separate terminals): ```bash # Terminal 1 - Bootstrap node go run ./cmd/node --config bootstrap.yaml -# Terminal 2 - Node 1 -go run ./cmd/node --config node1.yaml - -# Terminal 3 - Node 2 +# Terminal 2 - Node 2 go run ./cmd/node --config node2.yaml -# Terminal 4 - Node 3 +# Terminal 3 - Node 3 go run ./cmd/node --config node3.yaml + +# Terminal 4 - Gateway +go run ./cmd/gateway --config gateway.yaml ``` -#### Or Use Makefile Targets +### Running Multiple Nodes on the Same Machine + +The default `make dev` creates a 3-node setup. For additional nodes, generate individual configs: ```bash -# Terminal 1 -make run-node # Runs: go run ./cmd/node --config bootstrap.yaml +# Generate additional node configs with unique ports +./bin/network-cli config init --type node --name node4.yaml \ + --listen-port 4004 --rqlite-http-port 5004 --rqlite-raft-port 7004 \ + --join localhost:5001 \ + --bootstrap-peers "/ip4/127.0.0.1/tcp/4001/p2p/" -# Terminal 2 -make run-node2 # Runs: go run ./cmd/node --config node.yaml - -# Terminal 3 -make run-node3 # Runs: go run ./cmd/node --config node2.yaml +# Start the additional node +go run ./cmd/node --config node4.yaml ``` #### Key Points for Multiple Nodes - **Each node needs unique ports**: P2P port, RQLite HTTP port, and RQLite Raft port must all be different -- **Join address**: Non-bootstrap nodes need `rqlite_join_address` pointing to the bootstrap or an existing node +- **Join address**: Non-bootstrap nodes need `rqlite_join_address` pointing to the bootstrap or an existing node (use Raft port) - **Bootstrap peers**: All nodes need the bootstrap node's multiaddr in `discovery.bootstrap_peers` - **Config files**: Store all configs in `~/.debros/` with different filenames -- **--config flag**: Specify which config file to load (defaults to `node.yaml`) +- **--config flag**: Specify which config file to load ⚠️ **Common Mistake - Same Ports:** If all nodes use the same ports (e.g., 5001, 7001), they will try to bind to the same addresses and fail to communicate. Verify each node has unique ports: @@ -365,11 +381,11 @@ grep "rqlite_port\|rqlite_raft_port" ~/.debros/bootstrap.yaml # Should show: rqlite_port: 5001, rqlite_raft_port: 7001 # Node 2 -grep "rqlite_port\|rqlite_raft_port" ~/.debros/node.yaml +grep "rqlite_port\|rqlite_raft_port" ~/.debros/node2.yaml # Should show: rqlite_port: 5002, rqlite_raft_port: 7002 # Node 3 -grep "rqlite_port\|rqlite_raft_port" ~/.debros/node2.yaml +grep "rqlite_port\|rqlite_raft_port" ~/.debros/node3.yaml # Should show: rqlite_port: 5003, rqlite_raft_port: 7003 ``` diff --git a/cmd/cli/main.go b/cmd/cli/main.go index eff39f4..a2326a3 100644 --- a/cmd/cli/main.go +++ b/cmd/cli/main.go @@ -15,6 +15,7 @@ import ( "github.com/DeBrosOfficial/network/pkg/auth" "github.com/DeBrosOfficial/network/pkg/client" "github.com/DeBrosOfficial/network/pkg/config" + "github.com/DeBrosOfficial/network/pkg/encryption" "github.com/libp2p/go-libp2p/core/crypto" "github.com/libp2p/go-libp2p/core/peer" ) @@ -607,30 +608,35 @@ func showConfigHelp() { fmt.Printf("Config Management Commands\n\n") fmt.Printf("Usage: network-cli config [options]\n\n") fmt.Printf("Subcommands:\n") - fmt.Printf(" init - Generate configuration files in ~/.debros\n") + fmt.Printf(" init - Generate full network stack in ~/.debros (bootstrap + 2 nodes + gateway)\n") fmt.Printf(" validate --name - Validate a config file\n\n") + fmt.Printf("Init Default Behavior (no --type):\n") + fmt.Printf(" Generates bootstrap.yaml, node2.yaml, node3.yaml, gateway.yaml with:\n") + fmt.Printf(" - Auto-generated identities for bootstrap, node2, node3\n") + fmt.Printf(" - Correct bootstrap_peers and join addresses\n") + fmt.Printf(" - Default ports: P2P 4001-4003, HTTP 5001-5003, Raft 7001-7003\n\n") fmt.Printf("Init Options:\n") - fmt.Printf(" --type - Config type: node, bootstrap, gateway (default: node)\n") - fmt.Printf(" --name - Output filename (default: node.yaml)\n") + fmt.Printf(" --type - Single config type: node, bootstrap, gateway (skips stack generation)\n") + fmt.Printf(" --name - Output filename (default: depends on --type or 'stack' for full stack)\n") + fmt.Printf(" --force - Overwrite existing config/stack files\n\n") + fmt.Printf("Single Config Options (with --type):\n") fmt.Printf(" --id - Node ID for bootstrap peers\n") fmt.Printf(" --listen-port - LibP2P listen port (default: 4001)\n") fmt.Printf(" --rqlite-http-port - RQLite HTTP port (default: 5001)\n") fmt.Printf(" --rqlite-raft-port - RQLite Raft port (default: 7001)\n") fmt.Printf(" --join - RQLite address to join (required for non-bootstrap)\n") - fmt.Printf(" --bootstrap-peers - Comma-separated bootstrap peer multiaddrs\n") - fmt.Printf(" --force - Overwrite existing config\n\n") + fmt.Printf(" --bootstrap-peers - Comma-separated bootstrap peer multiaddrs\n\n") fmt.Printf("Examples:\n") - fmt.Printf(" network-cli config init\n") - fmt.Printf(" network-cli config init --type node --bootstrap-peers /ip4/127.0.0.1/tcp/4001/p2p/QmXxx,/ip4/127.0.0.1/tcp/4002/p2p/QmYyy\n") - fmt.Printf(" network-cli config init --type bootstrap\n") - fmt.Printf(" network-cli config init --type gateway\n") + fmt.Printf(" network-cli config init # Generate full stack\n") + fmt.Printf(" network-cli config init --force # Overwrite existing stack\n") + fmt.Printf(" network-cli config init --type bootstrap # Single bootstrap config (legacy)\n") fmt.Printf(" network-cli config validate --name node.yaml\n") } func handleConfigInit(args []string) { // Parse flags var ( - cfgType = "node" + cfgType = "" name = "" // Will be set based on type if not provided id string listenPort = 4001 @@ -694,6 +700,13 @@ func handleConfigInit(args []string) { } } + // If --type is not specified, generate full stack + if cfgType == "" { + initFullStack(force) + return + } + + // Otherwise, continue with single-file generation // Validate type if cfgType != "node" && cfgType != "bootstrap" && cfgType != "gateway" { fmt.Fprintf(os.Stderr, "Invalid --type: %s (expected: node, bootstrap, or gateway)\n", cfgType) @@ -799,6 +812,192 @@ func handleConfigValidate(args []string) { fmt.Printf("✅ Config is valid: %s\n", configPath) } +func initFullStack(force bool) { + fmt.Printf("🚀 Initializing full network stack...\n") + + // Ensure ~/.debros directory exists + homeDir, err := os.UserHomeDir() + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to get home directory: %v\n", err) + os.Exit(1) + } + debrosDir := filepath.Join(homeDir, ".debros") + if err := os.MkdirAll(debrosDir, 0755); err != nil { + fmt.Fprintf(os.Stderr, "Failed to create ~/.debros directory: %v\n", err) + os.Exit(1) + } + + // Step 1: Generate bootstrap identity + bootstrapIdentityDir := filepath.Join(debrosDir, "bootstrap") + bootstrapIdentityPath := filepath.Join(bootstrapIdentityDir, "identity.key") + + if !force { + if _, err := os.Stat(bootstrapIdentityPath); err == nil { + fmt.Fprintf(os.Stderr, "Bootstrap identity already exists at %s (use --force to overwrite)\n", bootstrapIdentityPath) + os.Exit(1) + } + } + + bootstrapInfo, err := encryption.GenerateIdentity() + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to generate bootstrap identity: %v\n", err) + os.Exit(1) + } + if err := os.MkdirAll(bootstrapIdentityDir, 0755); err != nil { + fmt.Fprintf(os.Stderr, "Failed to create bootstrap data directory: %v\n", err) + os.Exit(1) + } + if err := encryption.SaveIdentity(bootstrapInfo, bootstrapIdentityPath); err != nil { + fmt.Fprintf(os.Stderr, "Failed to save bootstrap identity: %v\n", err) + os.Exit(1) + } + fmt.Printf("✅ Generated bootstrap identity: %s (Peer ID: %s)\n", bootstrapIdentityPath, bootstrapInfo.PeerID.String()) + + // Construct bootstrap multiaddr + bootstrapMultiaddr := fmt.Sprintf("/ip4/127.0.0.1/tcp/4001/p2p/%s", bootstrapInfo.PeerID.String()) + fmt.Printf(" Bootstrap multiaddr: %s\n", bootstrapMultiaddr) + + // Step 2: Generate bootstrap.yaml + bootstrapName := "bootstrap.yaml" + bootstrapPath := filepath.Join(debrosDir, bootstrapName) + if !force { + if _, err := os.Stat(bootstrapPath); err == nil { + fmt.Fprintf(os.Stderr, "Bootstrap config already exists at %s (use --force to overwrite)\n", bootstrapPath) + os.Exit(1) + } + } + bootstrapContent := generateBootstrapConfig(bootstrapName, "", 4001, 5001, 7001) + if err := os.WriteFile(bootstrapPath, []byte(bootstrapContent), 0644); err != nil { + fmt.Fprintf(os.Stderr, "Failed to write bootstrap config: %v\n", err) + os.Exit(1) + } + fmt.Printf("✅ Generated bootstrap config: %s\n", bootstrapPath) + + // Step 3: Generate node2 identity and config + node2IdentityDir := filepath.Join(debrosDir, "node2") + node2IdentityPath := filepath.Join(node2IdentityDir, "identity.key") + + if !force { + if _, err := os.Stat(node2IdentityPath); err == nil { + fmt.Fprintf(os.Stderr, "Node2 identity already exists at %s (use --force to overwrite)\n", node2IdentityPath) + os.Exit(1) + } + } + + node2Info, err := encryption.GenerateIdentity() + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to generate node2 identity: %v\n", err) + os.Exit(1) + } + if err := os.MkdirAll(node2IdentityDir, 0755); err != nil { + fmt.Fprintf(os.Stderr, "Failed to create node2 data directory: %v\n", err) + os.Exit(1) + } + if err := encryption.SaveIdentity(node2Info, node2IdentityPath); err != nil { + fmt.Fprintf(os.Stderr, "Failed to save node2 identity: %v\n", err) + os.Exit(1) + } + fmt.Printf("✅ Generated node2 identity: %s (Peer ID: %s)\n", node2IdentityPath, node2Info.PeerID.String()) + + node2Name := "node2.yaml" + node2Path := filepath.Join(debrosDir, node2Name) + if !force { + if _, err := os.Stat(node2Path); err == nil { + fmt.Fprintf(os.Stderr, "Node2 config already exists at %s (use --force to overwrite)\n", node2Path) + os.Exit(1) + } + } + node2Content := generateNodeConfig(node2Name, "", 4002, 5002, 7002, "127.0.0.1:7001", bootstrapMultiaddr) + if err := os.WriteFile(node2Path, []byte(node2Content), 0644); err != nil { + fmt.Fprintf(os.Stderr, "Failed to write node2 config: %v\n", err) + os.Exit(1) + } + fmt.Printf("✅ Generated node2 config: %s\n", node2Path) + + // Step 4: Generate node3 identity and config + node3IdentityDir := filepath.Join(debrosDir, "node3") + node3IdentityPath := filepath.Join(node3IdentityDir, "identity.key") + + if !force { + if _, err := os.Stat(node3IdentityPath); err == nil { + fmt.Fprintf(os.Stderr, "Node3 identity already exists at %s (use --force to overwrite)\n", node3IdentityPath) + os.Exit(1) + } + } + + node3Info, err := encryption.GenerateIdentity() + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to generate node3 identity: %v\n", err) + os.Exit(1) + } + if err := os.MkdirAll(node3IdentityDir, 0755); err != nil { + fmt.Fprintf(os.Stderr, "Failed to create node3 data directory: %v\n", err) + os.Exit(1) + } + if err := encryption.SaveIdentity(node3Info, node3IdentityPath); err != nil { + fmt.Fprintf(os.Stderr, "Failed to save node3 identity: %v\n", err) + os.Exit(1) + } + fmt.Printf("✅ Generated node3 identity: %s (Peer ID: %s)\n", node3IdentityPath, node3Info.PeerID.String()) + + node3Name := "node3.yaml" + node3Path := filepath.Join(debrosDir, node3Name) + if !force { + if _, err := os.Stat(node3Path); err == nil { + fmt.Fprintf(os.Stderr, "Node3 config already exists at %s (use --force to overwrite)\n", node3Path) + os.Exit(1) + } + } + node3Content := generateNodeConfig(node3Name, "", 4003, 5003, 7003, "127.0.0.1:7001", bootstrapMultiaddr) + if err := os.WriteFile(node3Path, []byte(node3Content), 0644); err != nil { + fmt.Fprintf(os.Stderr, "Failed to write node3 config: %v\n", err) + os.Exit(1) + } + fmt.Printf("✅ Generated node3 config: %s\n", node3Path) + + // Step 5: Generate gateway.yaml + gatewayName := "gateway.yaml" + gatewayPath := filepath.Join(debrosDir, gatewayName) + if !force { + if _, err := os.Stat(gatewayPath); err == nil { + fmt.Fprintf(os.Stderr, "Gateway config already exists at %s (use --force to overwrite)\n", gatewayPath) + os.Exit(1) + } + } + gatewayContent := generateGatewayConfig(bootstrapMultiaddr) + if err := os.WriteFile(gatewayPath, []byte(gatewayContent), 0644); err != nil { + fmt.Fprintf(os.Stderr, "Failed to write gateway config: %v\n", err) + os.Exit(1) + } + fmt.Printf("✅ Generated gateway config: %s\n", gatewayPath) + + // Print summary + fmt.Printf("\n" + strings.Repeat("=", 60) + "\n") + fmt.Printf("✅ Full network stack initialized successfully!\n") + fmt.Printf(strings.Repeat("=", 60) + "\n\n") + fmt.Printf("Configuration files created in: %s\n\n", debrosDir) + fmt.Printf("Bootstrap Node:\n") + fmt.Printf(" Config: %s\n", bootstrapPath) + fmt.Printf(" Peer ID: %s\n", bootstrapInfo.PeerID.String()) + fmt.Printf(" Ports: P2P=4001, HTTP=5001, Raft=7001\n\n") + fmt.Printf("Node2:\n") + fmt.Printf(" Config: %s\n", node2Path) + fmt.Printf(" Ports: P2P=4002, HTTP=5002, Raft=7002\n") + fmt.Printf(" Join: 127.0.0.1:7001\n\n") + fmt.Printf("Node3:\n") + fmt.Printf(" Config: %s\n", node3Path) + fmt.Printf(" Ports: P2P=4003, HTTP=5003, Raft=7003\n") + fmt.Printf(" Join: 127.0.0.1:7001\n\n") + fmt.Printf("Gateway:\n") + fmt.Printf(" Config: %s\n\n", gatewayPath) + fmt.Printf("To start the network:\n") + fmt.Printf(" Terminal 1: ./bin/node --config bootstrap.yaml\n") + fmt.Printf(" Terminal 2: ./bin/node --config node2.yaml\n") + fmt.Printf(" Terminal 3: ./bin/node --config node3.yaml\n") + fmt.Printf(" Terminal 4: ./bin/gateway --config gateway.yaml\n") + fmt.Printf("\n" + strings.Repeat("=", 60) + "\n") +} + func generateNodeConfig(name, id string, listenPort, rqliteHTTPPort, rqliteRaftPort int, joinAddr, bootstrapPeers string) string { nodeID := id if nodeID == "" { @@ -923,11 +1122,11 @@ func generateGatewayConfig(bootstrapPeers string) string { var peersYAML strings.Builder if len(peers) == 0 { - peersYAML.WriteString(" bootstrap_peers: []") + peersYAML.WriteString("bootstrap_peers: []") } else { - peersYAML.WriteString(" bootstrap_peers:\n") + peersYAML.WriteString("bootstrap_peers:\n") for _, p := range peers { - fmt.Fprintf(&peersYAML, " - \"%s\"\n", p) + fmt.Fprintf(&peersYAML, " - \"%s\"\n", p) } } diff --git a/pkg/node/node.go b/pkg/node/node.go index 2bf1f02..12327e2 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -84,35 +84,35 @@ func (n *Node) startRQLite(ctx context.Context) error { // bootstrapPeerSource returns a PeerSource that yields peers from BootstrapPeers. func bootstrapPeerSource(bootstrapAddrs []string, logger *zap.Logger) func(context.Context, int) <-chan peer.AddrInfo { - return func(ctx context.Context, num int) <-chan peer.AddrInfo { - out := make(chan peer.AddrInfo, num) - go func() { - defer close(out) - count := 0 - for _, s := range bootstrapAddrs { - if count >= num { - return - } - ma, err := multiaddr.NewMultiaddr(s) - if err != nil { - logger.Debug("invalid bootstrap multiaddr", zap.String("addr", s), zap.Error(err)) - continue - } - ai, err := peer.AddrInfoFromP2pAddr(ma) - if err != nil { - logger.Debug("failed to parse bootstrap peer", zap.String("addr", s), zap.Error(err)) - continue - } - select { - case out <- *ai: - count++ - case <-ctx.Done(): - return - } - } - }() - return out - } + return func(ctx context.Context, num int) <-chan peer.AddrInfo { + out := make(chan peer.AddrInfo, num) + go func() { + defer close(out) + count := 0 + for _, s := range bootstrapAddrs { + if count >= num { + return + } + ma, err := multiaddr.NewMultiaddr(s) + if err != nil { + logger.Debug("invalid bootstrap multiaddr", zap.String("addr", s), zap.Error(err)) + continue + } + ai, err := peer.AddrInfoFromP2pAddr(ma) + if err != nil { + logger.Debug("failed to parse bootstrap peer", zap.String("addr", s), zap.Error(err)) + continue + } + select { + case out <- *ai: + count++ + case <-ctx.Done(): + return + } + } + }() + return out + } } // hasBootstrapConnections checks if we're connected to any bootstrap peers @@ -250,21 +250,52 @@ func (n *Node) startLibP2P() error { return fmt.Errorf("failed to load identity: %w", err) } - // Create LibP2P host with NAT traversal support + // Create LibP2P host with explicit listen addresses var opts []libp2p.Option opts = append(opts, libp2p.Identity(identity), libp2p.Security(noise.ID, noise.New), libp2p.DefaultMuxers, - libp2p.EnableNATService(), - libp2p.EnableAutoNATv2(), - libp2p.EnableRelay(), - libp2p.NATPortMap(), - libp2p.EnableAutoRelayWithPeerSource( - bootstrapPeerSource(n.config.Discovery.BootstrapPeers, n.logger.Logger), - ), ) + // Add explicit listen addresses from config + if len(n.config.Node.ListenAddresses) > 0 { + listenAddrs := make([]multiaddr.Multiaddr, 0, len(n.config.Node.ListenAddresses)) + for _, addr := range n.config.Node.ListenAddresses { + ma, err := multiaddr.NewMultiaddr(addr) + if err != nil { + return fmt.Errorf("invalid listen address %s: %w", addr, err) + } + listenAddrs = append(listenAddrs, ma) + } + opts = append(opts, libp2p.ListenAddrs(listenAddrs...)) + n.logger.ComponentInfo(logging.ComponentLibP2P, "Configured listen addresses", + zap.Strings("addrs", n.config.Node.ListenAddresses)) + } + + // For localhost/development, disable NAT services + // For production, these would be enabled + isLocalhost := len(n.config.Node.ListenAddresses) > 0 && + (strings.Contains(n.config.Node.ListenAddresses[0], "127.0.0.1") || + strings.Contains(n.config.Node.ListenAddresses[0], "localhost")) + + if isLocalhost { + n.logger.ComponentInfo(logging.ComponentLibP2P, "Localhost detected - disabling NAT services for local development") + // Don't add NAT/AutoRelay options for localhost + } else { + // Production: enable NAT traversal + n.logger.ComponentInfo(logging.ComponentLibP2P, "Production mode - enabling NAT services") + opts = append(opts, + libp2p.EnableNATService(), + libp2p.EnableAutoNATv2(), + libp2p.EnableRelay(), + libp2p.NATPortMap(), + libp2p.EnableAutoRelayWithPeerSource( + bootstrapPeerSource(n.config.Discovery.BootstrapPeers, n.logger.Logger), + ), + ) + } + h, err := libp2p.New(opts...) if err != nil { return err From a9d624c0f6321ff690e2f546bc0194c8ee484b52 Mon Sep 17 00:00:00 2001 From: anonpenguin23 Date: Sat, 25 Oct 2025 08:40:06 +0300 Subject: [PATCH 2/2] refactor: enhance DeBros network installation script - Updated script to support a complete DeBros network node installation with gateway. - Improved user management by introducing a variable for the debros user. - Added support for idempotent updates and secure systemd service management for both node and gateway services. - Replaced the configuration wizard with automated configuration file generation using network-cli. - Enhanced firewall configuration instructions and service management commands for better usability. --- CHANGELOG.md | 1 + scripts/install-debros-network.sh | 301 ++++++++++++++++-------------- 2 files changed, 159 insertions(+), 143 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e55359..f4bf482 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,7 @@ The format is based on [Keep a Changelog][keepachangelog] and adheres to [Semant - Fixed indentation in bootstrapPeerSource function for consistency - Fixed gateway.yaml generation with correct YAML indentation for bootstrap_peers +- Fixed script for running and added gateway running as well ### Security diff --git a/scripts/install-debros-network.sh b/scripts/install-debros-network.sh index 82e04e1..20c18ef 100755 --- a/scripts/install-debros-network.sh +++ b/scripts/install-debros-network.sh @@ -1,8 +1,8 @@ #!/bin/bash -# DeBros Network Node Installation Script (Modern Node-Only Setup) -# Installs, configures, and manages a DeBros network node with secure defaults. -# Supports update-in-place, systemd service, and CLI management. +# DeBros Network Production Installation Script +# Installs and configures a complete DeBros network node (bootstrap) with gateway. +# Supports idempotent updates and secure systemd service management. set -e trap 'echo -e "${RED}An error occurred. Installation aborted.${NOCOLOR}"; exit 1' ERR @@ -25,6 +25,7 @@ GATEWAY_PORT="6001" RAFT_PORT="7001" UPDATE_MODE=false NON_INTERACTIVE=false +DEBROS_USER="debros" log() { echo -e "${CYAN}[$(date '+%Y-%m-%d %H:%M:%S')]${NOCOLOR} $1"; } error() { echo -e "${RED}[ERROR]${NOCOLOR} $1"; } @@ -115,7 +116,7 @@ check_existing_installation() { remove_existing_installation() { log "Removing existing installation..." - for service in debros-node; do + for service in debros-node debros-gateway; do if systemctl list-unit-files | grep -q "$service.service"; then log "Stopping $service service..." sudo systemctl stop $service.service 2>/dev/null || true @@ -128,8 +129,8 @@ remove_existing_installation() { sudo rm -rf "$INSTALL_DIR" log "Removed installation directory" fi - if id "debros" &>/dev/null; then - sudo userdel debros 2>/dev/null || true + if id "$DEBROS_USER" &>/dev/null; then + sudo userdel "$DEBROS_USER" 2>/dev/null || true log "Removed debros user" fi success "Existing installation removed" @@ -260,50 +261,24 @@ check_ports() { success "All required ports are available" } -configuration_wizard() { - log "${BLUE}==================================================${NOCOLOR}" - log "${GREEN} DeBros Network Configuration Wizard ${NOCOLOR}" - log "${BLUE}==================================================${NOCOLOR}" - if [ "$NON_INTERACTIVE" = true ]; then - log "Non-interactive mode: using default configuration" - SOLANA_WALLET="11111111111111111111111111111111" - CONFIGURE_FIREWALL="yes" - log "Installation Directory: $INSTALL_DIR" - log "Firewall Configuration: $CONFIGURE_FIREWALL" - success "Configuration completed with defaults" - return 0 - fi - log "${GREEN}Enter your Solana wallet address 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 - read -rp "Installation directory [default: $INSTALL_DIR]: " CUSTOM_INSTALL_DIR - if [[ -n "$CUSTOM_INSTALL_DIR" ]]; then INSTALL_DIR="$CUSTOM_INSTALL_DIR"; fi - read -rp "Configure firewall automatically? (yes/no) [default: yes]: " CONFIGURE_FIREWALL - CONFIGURE_FIREWALL="${CONFIGURE_FIREWALL:-yes}" - success "Configuration completed" -} - setup_directories() { log "Setting up directories and permissions..." - if ! id "debros" &>/dev/null; then - sudo useradd -r -s /bin/false -d "$INSTALL_DIR" debros + if ! id "$DEBROS_USER" &>/dev/null; then + sudo useradd -r -s /usr/sbin/nologin -d "$INSTALL_DIR" "$DEBROS_USER" log "Created debros user" else log "User 'debros' already exists" fi - sudo mkdir -p "$INSTALL_DIR"/{bin,configs,keys,data,logs,src} - sudo mkdir -p "$INSTALL_DIR/keys/node" - sudo mkdir -p "$INSTALL_DIR/data/node"/{rqlite,storage} - sudo chown -R debros:debros "$INSTALL_DIR" + sudo mkdir -p "$INSTALL_DIR"/{bin,src} + sudo chown -R "$DEBROS_USER:$DEBROS_USER" "$INSTALL_DIR" sudo chmod 755 "$INSTALL_DIR" - sudo chmod 700 "$INSTALL_DIR/keys" - sudo chmod 700 "$INSTALL_DIR/keys/node" - sudo chmod 755 "$INSTALL_DIR/data" - sudo chmod 755 "$INSTALL_DIR/logs" - sudo chmod 755 "$INSTALL_DIR/configs" sudo chmod 755 "$INSTALL_DIR/bin" + + # Create ~/.debros for the debros user + DEBROS_HOME=$(sudo -u "$DEBROS_USER" sh -c 'echo ~') + sudo -u "$DEBROS_USER" mkdir -p "$DEBROS_HOME/.debros" + sudo chmod 0700 "$DEBROS_HOME/.debros" + success "Directory structure ready" } @@ -312,39 +287,20 @@ setup_source_code() { if [ -d "$INSTALL_DIR/src/.git" ]; then log "Updating existing repository..." cd "$INSTALL_DIR/src" - sudo -u debros git pull + sudo -u "$DEBROS_USER" git pull else log "Cloning repository..." - sudo -u debros git clone "$REPO_URL" "$INSTALL_DIR/src" + sudo -u "$DEBROS_USER" git clone "$REPO_URL" "$INSTALL_DIR/src" cd "$INSTALL_DIR/src" fi success "Source code ready" } -generate_identity() { - local identity_file="$INSTALL_DIR/keys/node/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..." - cd "$INSTALL_DIR/src" - export PATH=$PATH:/usr/local/go/bin - sudo -u debros env "PATH=$PATH:/usr/local/go/bin" go run ./cmd/identity -output "$identity_file" - success "Node identity generated" -} - build_binaries() { log "Building DeBros Network binaries..." cd "$INSTALL_DIR/src" export PATH=$PATH:/usr/local/go/bin - sudo -u debros env "PATH=$PATH:/usr/local/go/bin" make build + local services_were_running=() if [ "$UPDATE_MODE" = true ]; then log "Update mode: checking for running services before binary update..." @@ -353,13 +309,22 @@ build_binaries() { sudo systemctl stop debros-node.service services_were_running+=("debros-node") fi + if systemctl is-active --quiet debros-gateway.service 2>/dev/null; then + log "Stopping debros-gateway service to update binaries..." + sudo systemctl stop debros-gateway.service + services_were_running+=("debros-gateway") + fi if [ ${#services_were_running[@]} -gt 0 ]; then log "Waiting for services to stop completely..." sleep 3 fi fi + + sudo -u "$DEBROS_USER" env "PATH=$PATH:/usr/local/go/bin" make build sudo cp bin/* "$INSTALL_DIR/bin/" - sudo chown debros:debros "$INSTALL_DIR/bin/"* + sudo chown "$DEBROS_USER:$DEBROS_USER" "$INSTALL_DIR/bin/"* + sudo chmod 755 "$INSTALL_DIR/bin/"* + if [ "$UPDATE_MODE" = true ] && [ ${#services_were_running[@]} -gt 0 ]; then log "Restarting previously running services..." for service in "${services_were_running[@]}"; do @@ -371,81 +336,75 @@ build_binaries() { } generate_configs() { - log "Generating configuration files..." - cat > /tmp/node.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_PORT - rqlite_raft_port: $RAFT_PORT -logging: - level: "info" - file: "$INSTALL_DIR/logs/node.log" -EOF - sudo mv /tmp/node.yaml "$INSTALL_DIR/configs/node.yaml" - sudo chown debros:debros "$INSTALL_DIR/configs/node.yaml" + log "Generating configuration files via network-cli..." + DEBROS_HOME=$(sudo -u "$DEBROS_USER" sh -c 'echo ~') + + # Generate bootstrap config + log "Generating bootstrap.yaml..." + sudo -u "$DEBROS_USER" "$INSTALL_DIR/bin/network-cli" config init --type bootstrap --force + + # Generate gateway config + log "Generating gateway.yaml..." + sudo -u "$DEBROS_USER" "$INSTALL_DIR/bin/network-cli" config init --type gateway --force + success "Configuration files generated" } configure_firewall() { - if [[ "$CONFIGURE_FIREWALL" == "yes" ]]; then - log "Configuring firewall rules..." - if command -v ufw &> /dev/null; then - log "Adding UFW rules for DeBros Network ports..." - for port in $NODE_PORT $RQLITE_PORT $RAFT_PORT $GATEWAY_PORT; do - if ! sudo ufw allow $port; then - error "Failed to allow port $port" - exit 1 - fi - log "Added UFW rule: allow port $port" - done - UFW_STATUS=$(sudo ufw status | grep -o "Status: [a-z]\+" | awk '{print $2}' || echo "inactive") - if [[ "$UFW_STATUS" == "active" ]]; then - success "Firewall rules added and active" - else - success "Firewall rules added (UFW is inactive - rules will take effect when UFW is enabled)" - log "To enable UFW with current rules: sudo ufw enable" + log "Configuring firewall rules..." + if command -v ufw &> /dev/null; then + log "Adding UFW rules for DeBros Network ports..." + for port in $NODE_PORT $RQLITE_PORT $RAFT_PORT $GATEWAY_PORT; do + if ! sudo ufw allow $port 2>/dev/null; then + error "Failed to allow port $port" + exit 1 fi + log "Added UFW rule: allow port $port" + done + UFW_STATUS=$(sudo ufw status | grep -o "Status: [a-z]\+" | awk '{print $2}' || echo "inactive") + if [[ "$UFW_STATUS" == "active" ]]; then + success "Firewall rules added and active" else - warning "UFW not found. Please configure firewall manually." - log "Required ports to allow:" - log " - Port $NODE_PORT (Node)" - log " - Port $RQLITE_PORT (RQLite)" - log " - Port $RAFT_PORT (Raft)" + success "Firewall rules added (UFW is inactive - rules will take effect when UFW is enabled)" + log "To enable UFW with current rules: sudo ufw enable" fi + else + warning "UFW not found. Please configure firewall manually." + log "Required ports to allow:" + log " - Port $NODE_PORT (Node P2P)" + log " - Port $RQLITE_PORT (RQLite HTTP)" + log " - Port $RAFT_PORT (RQLite Raft)" + log " - Port $GATEWAY_PORT (Gateway)" fi } -create_systemd_service() { - local service_file="/etc/systemd/system/debros-node.service" - if [ -f "$service_file" ]; then +create_systemd_services() { + log "Creating systemd service units..." + + # Node service + local node_service_file="/etc/systemd/system/debros-node.service" + if [ -f "$node_service_file" ]; then log "Cleaning up existing node service..." sudo systemctl stop debros-node.service 2>/dev/null || true sudo systemctl disable debros-node.service 2>/dev/null || true - sudo rm -f "$service_file" + sudo rm -f "$node_service_file" fi - sudo systemctl daemon-reload - log "Creating new systemd service..." - local exec_start="$INSTALL_DIR/bin/node -data $INSTALL_DIR/data/node" - cat > /tmp/debros-node.service << EOF + + log "Creating debros-node.service..." + cat > /tmp/debros-node.service << 'EOF' [Unit] -Description=DeBros Network Node -After=network.target +Description=DeBros Network Node (Bootstrap) +After=network-online.target Wants=network-online.target [Service] Type=simple User=debros Group=debros -WorkingDirectory=$INSTALL_DIR -Environment=ENVIRONMENT=production -ExecStart=$exec_start +WorkingDirectory=/opt/debros/src +ExecStart=/opt/debros/bin/node --config bootstrap.yaml Restart=always -RestartSec=10 +RestartSec=5 StandardOutput=journal StandardError=journal SyslogIdentifier=debros-node @@ -454,26 +413,78 @@ NoNewPrivileges=yes PrivateTmp=yes ProtectSystem=strict ProtectHome=yes -ReadWritePaths=$INSTALL_DIR +ReadWritePaths=/opt/debros [Install] WantedBy=multi-user.target EOF - sudo mv /tmp/debros-node.service "$service_file" + sudo mv /tmp/debros-node.service "$node_service_file" + + # Gateway service + local gateway_service_file="/etc/systemd/system/debros-gateway.service" + if [ -f "$gateway_service_file" ]; then + log "Cleaning up existing gateway service..." + sudo systemctl stop debros-gateway.service 2>/dev/null || true + sudo systemctl disable debros-gateway.service 2>/dev/null || true + sudo rm -f "$gateway_service_file" + fi + + log "Creating debros-gateway.service..." + cat > /tmp/debros-gateway.service << 'EOF' +[Unit] +Description=DeBros Gateway (HTTP/WebSocket) +After=debros-node.service +Wants=debros-node.service + +[Service] +Type=simple +User=debros +Group=debros +WorkingDirectory=/opt/debros/src +ExecStart=/opt/debros/bin/gateway +Restart=always +RestartSec=5 +StandardOutput=journal +StandardError=journal +SyslogIdentifier=debros-gateway + +NoNewPrivileges=yes +PrivateTmp=yes +ProtectSystem=strict +ProtectHome=yes +ReadWritePaths=/opt/debros + +[Install] +WantedBy=multi-user.target +EOF + sudo mv /tmp/debros-gateway.service "$gateway_service_file" + sudo systemctl daemon-reload sudo systemctl enable debros-node.service - success "Systemd service ready" + sudo systemctl enable debros-gateway.service + success "Systemd services ready" } -start_service() { - log "Starting DeBros Network service..." +start_services() { + log "Starting DeBros Network services..." sudo systemctl start debros-node.service sleep 3 if systemctl is-active --quiet debros-node.service; then - success "DeBros Network service started successfully" + success "DeBros Node service started successfully" else - error "Failed to start DeBros Network service" - log "Check logs with: sudo journalctl -u debros-node.service" + error "Failed to start DeBros Node service" + log "Check logs with: sudo journalctl -u debros-node.service -f" + exit 1 + fi + + sleep 2 + sudo systemctl start debros-gateway.service + sleep 2 + if systemctl is-active --quiet debros-gateway.service; then + success "DeBros Gateway service started successfully" + else + error "Failed to start DeBros Gateway service" + log "Check logs with: sudo journalctl -u debros-gateway.service -f" exit 1 fi } @@ -501,14 +512,8 @@ main() { if ! check_go_installation; then install_go; fi install_dependencies install_rqlite - if [ "$UPDATE_MODE" != true ]; then configuration_wizard; else - log "Update mode: skipping configuration wizard" - SOLANA_WALLET="11111111111111111111111111111111" - CONFIGURE_FIREWALL="yes" - fi setup_directories setup_source_code - generate_identity build_binaries if [ "$UPDATE_MODE" != true ]; then generate_configs @@ -516,8 +521,11 @@ main() { else log "Update mode: keeping existing configuration" fi - create_systemd_service - start_service + create_systemd_services + start_services + + DEBROS_HOME=$(sudo -u "$DEBROS_USER" sh -c 'echo ~') + log "${BLUE}==================================================${NOCOLOR}" if [ "$UPDATE_MODE" = true ]; then log "${GREEN} Update Complete! ${NOCOLOR}" @@ -526,21 +534,28 @@ main() { fi log "${BLUE}==================================================${NOCOLOR}" log "${GREEN}Installation Directory:${NOCOLOR} ${CYAN}$INSTALL_DIR${NOCOLOR}" - log "${GREEN}Configuration:${NOCOLOR} ${CYAN}$INSTALL_DIR/configs/node.yaml${NOCOLOR}" - log "${GREEN}Logs:${NOCOLOR} ${CYAN}$INSTALL_DIR/logs/node.log${NOCOLOR}" + log "${GREEN}Config Directory:${NOCOLOR} ${CYAN}$DEBROS_HOME/.debros${NOCOLOR}" log "${GREEN}LibP2P Port:${NOCOLOR} ${CYAN}$NODE_PORT${NOCOLOR}" log "${GREEN}RQLite Port:${NOCOLOR} ${CYAN}$RQLITE_PORT${NOCOLOR}" log "${GREEN}Gateway Port:${NOCOLOR} ${CYAN}$GATEWAY_PORT${NOCOLOR}" log "${GREEN}Raft Port:${NOCOLOR} ${CYAN}$RAFT_PORT${NOCOLOR}" log "${BLUE}==================================================${NOCOLOR}" - log "${GREEN}Management Commands:${NOCOLOR}" - log "${CYAN} - sudo systemctl status debros-node${NOCOLOR} (Check status)" - log "${CYAN} - sudo systemctl restart debros-node${NOCOLOR} (Restart service)" - log "${CYAN} - sudo systemctl stop debros-node${NOCOLOR} (Stop service)" - log "${CYAN} - sudo systemctl start debros-node${NOCOLOR} (Start service)" - log "${CYAN} - sudo journalctl -u debros-node.service -f${NOCOLOR} (View logs)" - log "${CYAN} - $INSTALL_DIR/bin/network-cli${NOCOLOR} (Use CLI tools)" + log "${GREEN}Service Management:${NOCOLOR}" + log "${CYAN} - sudo systemctl status debros-node${NOCOLOR} (Check node status)" + log "${CYAN} - sudo systemctl status debros-gateway${NOCOLOR} (Check gateway status)" + log "${CYAN} - sudo systemctl restart debros-node${NOCOLOR} (Restart node)" + log "${CYAN} - sudo systemctl restart debros-gateway${NOCOLOR} (Restart gateway)" + log "${CYAN} - sudo systemctl stop debros-node${NOCOLOR} (Stop node)" + log "${CYAN} - sudo systemctl stop debros-gateway${NOCOLOR} (Stop gateway)" + log "${CYAN} - sudo journalctl -u debros-node.service -f${NOCOLOR} (View node logs)" + log "${CYAN} - sudo journalctl -u debros-gateway.service -f${NOCOLOR} (View gateway logs)" log "${BLUE}==================================================${NOCOLOR}" + log "${GREEN}Verify Installation:${NOCOLOR}" + log "${CYAN} - Node health: curl http://127.0.0.1:5001/status${NOCOLOR}" + log "${CYAN} - Gateway health: curl http://127.0.0.1:6001/health${NOCOLOR}" + log "${CYAN} - Show bootstrap peer: cat $DEBROS_HOME/.debros/bootstrap/peer.info${NOCOLOR}" + log "${BLUE}==================================================${NOCOLOR}" + if [ "$UPDATE_MODE" = true ]; then success "DeBros Network has been updated and is running!" else