#!/usr/bin/env bash # Setup ThirdWeb RPC Node LXC Containers # Creates and configures Besu RPC nodes optimized for ThirdWeb integration # # VMIDs: 2400-2402 (ThirdWeb RPC nodes) - aligned with IP addresses # IP Range: 192.168.11.240-242 (VMIDs 2400-2402) # IP Management: VMID 2400 = 192.168.11.240, VMID 2401 = 192.168.11.241, etc. set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" CONFIG_DIR="$PROJECT_ROOT/smom-dbis-138/config" # Configuration PROXMOX_HOST="${PROXMOX_HOST:-192.168.11.10}" STORAGE="${STORAGE:-local-lvm}" # Use local-lvm (LVM-thin) like other containers TEMPLATE="${TEMPLATE:-local:vztmpl/debian-12-standard_12.12-1_amd64.tar.zst}" NETWORK="${NETWORK:-vmbr0}" GATEWAY="${GATEWAY:-192.168.11.1}" # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' log_info() { echo -e "${BLUE}[INFO]${NC} $1"; } log_success() { echo -e "${GREEN}[✓]${NC} $1"; } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } log_error() { echo -e "${RED}[ERROR]${NC} $1"; } # VMID to IP Address Mapping Function # Maps VMID to IP based on VMID pattern for 192.168.11.X network: # - 4-digit VMID (2400-2499) -> last octet matches last 2 digits # - Example: VMID 2400 = 192.168.11.240, VMID 2401 = 192.168.11.241 vmid_to_ip() { local vmid=$1 local base_network="${2:-192.168.11}" # For 4-digit VMIDs in 192.168.11.X network if [[ $vmid =~ ^[0-9]{4}$ ]] && [[ "$base_network" == "192.168.11" ]]; then local last_octet=$((vmid % 1000)) # Ensure last octet is in valid range (1-254, since .255 is broadcast) if [[ $last_octet -ge 1 ]] && [[ $last_octet -le 254 ]]; then echo "${base_network}.${last_octet}" return 0 fi fi # Fallback: return empty (should not happen with valid VMIDs) echo "" return 1 } # ThirdWeb RPC Node Configuration # VMIDs 2400-2402 map to IPs 192.168.11.240-242 (aligned numbering) # Note: .254 is last usable IP, .255 is broadcast in /24 network # Existing RPC nodes use .250-252 (VMIDs 2500-2502) declare -A THIRDWEB_RPC_NODES=( [2400]="thirdweb-rpc-1:192.168.11.240:ThirdWeb RPC Node 1 (Primary)" [2401]="thirdweb-rpc-2:192.168.11.241:ThirdWeb RPC Node 2 (Secondary)" [2402]="thirdweb-rpc-3:192.168.11.242:ThirdWeb RPC Node 3 (Tertiary)" ) # Resource specifications per node MEMORY_GB=16 CPU_CORES=4 DISK_GB=200 # Check SSH access check_ssh_access() { log_info "Checking SSH access to $PROXMOX_HOST..." if ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no root@${PROXMOX_HOST} "echo 'SSH OK'" &>/dev/null; then log_success "SSH access confirmed" return 0 else log_error "Cannot access $PROXMOX_HOST via SSH" log_error "Please ensure:" log_error " 1. SSH key is set up" log_error " 2. Host is reachable" log_error " 3. Root access is available" return 1 fi } # Check if container exists container_exists() { local vmid=$1 ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no root@${PROXMOX_HOST} \ "pct list | grep -q '^$vmid ' && echo 'exists' || echo 'missing'" 2>/dev/null || echo "error" } # Create a container create_container() { local vmid=$1 local hostname=$2 local ip=$3 local description="$4" log_info "Creating container $vmid: $hostname ($ip)..." # Check if already exists local exists=$(container_exists "$vmid") if [[ "$exists" == "exists" ]]; then log_warn "Container $vmid already exists, skipping creation..." return 0 fi log_info " Memory: ${MEMORY_GB}GB, CPU: ${CPU_CORES} cores, Disk: ${DISK_GB}GB" log_info " Creating with DHCP first, then configuring static IP..." # Create container with DHCP (more reliable) ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no root@${PROXMOX_HOST} </dev/null | awk '{print \$2}'" || echo "unknown") if [[ "$status" == "running" ]]; then log_success " Container $vmid is running" # Now configure static IP log_info " Configuring static IP: $ip/24" local configure_result=$(ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no root@${PROXMOX_HOST} bash -s </dev/null || true sleep 2 # Get current MAC address from config (if exists) MAC_ADDRESS=\$(pct config \$VMID 2>/dev/null | grep "^net0:" | sed -n 's/.*hwaddr=\\([^,]*\\).*/\\1/p' || echo "") if [[ -z "\$MAC_ADDRESS" ]]; then # Generate a new MAC address if not found MAC_ADDRESS=\$(printf "02:00:27:%02x:%02x:%02x" \$((RANDOM%256)) \$((RANDOM%256)) \$((RANDOM%256))) fi # Configure static IP if pct set \$VMID --net0 name=eth0,bridge=\$NETWORK,hwaddr=\$MAC_ADDRESS,ip=\$IP/24,gw=\$GATEWAY,type=veth; then # Start container pct start \$VMID echo "SUCCESS" else echo "FAILED" exit 1 fi CONFIGURE_IP_EOF ) if echo "$configure_result" | grep -q "SUCCESS"; then log_success " Static IP configured: $ip/24" sleep 5 else log_warn " Failed to configure static IP, container is running with DHCP" log_info " Attempting to start container anyway..." ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no root@${PROXMOX_HOST} "pct start $vmid 2>/dev/null || true" fi else log_warn " Container $vmid status: $status" fi return 0 else log_error "Failed to create container $vmid" return 1 fi } # Setup container with Besu RPC setup_besu_rpc() { local vmid=$1 local hostname=$2 local ip=$3 log_info "Setting up Besu RPC on container $vmid..." # Copy installation script local install_script="$SCRIPT_DIR/../smom-dbis-138-proxmox/install/besu-rpc-install.sh" if [[ ! -f "$install_script" ]]; then log_error "Besu installation script not found: $install_script" return 1 fi # Copy config file local config_file="$CONFIG_DIR/config-rpc-thirdweb.toml" if [[ ! -f "$config_file" ]]; then log_warn "ThirdWeb config not found, will create default..." create_thirdweb_config "$config_file" fi # First, copy files to Proxmox host, then push to container log_info " Copying files to Proxmox host..." local remote_install="/tmp/besu-rpc-install-$$.sh" local remote_config="/tmp/config-rpc-thirdweb-$$.toml" # Define paths for genesis and permissions (before heredoc) local genesis_dir="$PROJECT_ROOT/smom-dbis-138/genesis" local permissions_dir="$PROJECT_ROOT/smom-dbis-138/permissions" scp -o ConnectTimeout=5 -o StrictHostKeyChecking=no "$install_script" root@${PROXMOX_HOST}:${remote_install} || { log_error "Failed to copy installation script to Proxmox host" return 1 } scp -o ConnectTimeout=5 -o StrictHostKeyChecking=no "$config_file" root@${PROXMOX_HOST}:${remote_config} || { log_error "Failed to copy config file to Proxmox host" return 1 } # Execute setup inside container ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no root@${PROXMOX_HOST} </dev/null; then break fi sleep 1 done # Copy installation script from Proxmox host to container pct push $vmid ${remote_install} /tmp/besu-rpc-install.sh # Copy config from Proxmox host to container pct push $vmid ${remote_config} /tmp/config-rpc-thirdweb.toml # Install Besu pct exec $vmid -- bash /tmp/besu-rpc-install.sh # Move config to proper location pct exec $vmid -- mkdir -p /etc/besu pct exec $vmid -- cp /tmp/config-rpc-thirdweb.toml /etc/besu/config-rpc-thirdweb.toml # Update systemd service to use ThirdWeb config pct exec $vmid -- sed -i 's|config-rpc.toml|config-rpc-thirdweb.toml|g' /etc/systemd/system/besu-rpc.service || true # Reload systemd and enable service pct exec $vmid -- systemctl daemon-reload pct exec $vmid -- systemctl enable besu-rpc.service echo "Besu RPC setup completed for $vmid" SETUP_EOF # Copy genesis and permissions files if they exist (after heredoc to avoid variable issues) local genesis_dir="$PROJECT_ROOT/smom-dbis-138/genesis" local permissions_dir="$PROJECT_ROOT/smom-dbis-138/permissions" if [[ -d "$genesis_dir" ]]; then log_info " Copying genesis files..." ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no root@${PROXMOX_HOST} "pct exec $vmid -- mkdir -p /genesis /permissions" || true if [[ -f "$genesis_dir/genesis.json" ]]; then local remote_genesis="/tmp/genesis-$$.json" scp -o ConnectTimeout=5 -o StrictHostKeyChecking=no "$genesis_dir/genesis.json" root@${PROXMOX_HOST}:${remote_genesis} && { ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no root@${PROXMOX_HOST} "pct push $vmid ${remote_genesis} /genesis/genesis.json && rm -f ${remote_genesis}" || true } fi if [[ -f "$genesis_dir/static-nodes.json" ]]; then local remote_static="/tmp/static-nodes-$$.json" scp -o ConnectTimeout=5 -o StrictHostKeyChecking=no "$genesis_dir/static-nodes.json" root@${PROXMOX_HOST}:${remote_static} && { ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no root@${PROXMOX_HOST} "pct push $vmid ${remote_static} /genesis/static-nodes.json && rm -f ${remote_static}" || true } fi fi if [[ -d "$permissions_dir" ]] && [[ -f "$permissions_dir/permissions-nodes.toml" ]]; then log_info " Copying permissions files..." local remote_perms="/tmp/permissions-$$.toml" scp -o ConnectTimeout=5 -o StrictHostKeyChecking=no "$permissions_dir/permissions-nodes.toml" root@${PROXMOX_HOST}:${remote_perms} && { ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no root@${PROXMOX_HOST} "pct exec $vmid -- mkdir -p /permissions && pct push $vmid ${remote_perms} /permissions/permissions-nodes.toml && rm -f ${remote_perms}" || true } fi # Clean up temporary files on Proxmox host ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no root@${PROXMOX_HOST} "rm -f ${remote_install} ${remote_config}" || true if [ $? -eq 0 ]; then log_success "Besu RPC setup completed for container $vmid" return 0 else log_error "Failed to setup Besu RPC on container $vmid" # Clean up on failure ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no root@${PROXMOX_HOST} "rm -f ${remote_install} ${remote_config}" || true return 1 fi } # Create ThirdWeb-optimized Besu config create_thirdweb_config() { local config_file="$1" log_info "Creating ThirdWeb RPC configuration: $config_file" mkdir -p "$(dirname "$config_file")" cat > "$config_file" <<'EOF' # Besu Configuration for ThirdWeb RPC Nodes # Optimized for ThirdWeb SDK and dApp integration data-path="/data/besu" genesis-file="/genesis/genesis.json" # Network Configuration network-id=138 p2p-host="0.0.0.0" p2p-port=30303 # Consensus (RPC nodes don't participate) miner-enabled=false # Sync Configuration sync-mode="FULL" fast-sync-min-peers=2 # RPC Configuration (ThirdWeb-compatible APIs) rpc-http-enabled=true rpc-http-host="0.0.0.0" rpc-http-port=8545 rpc-http-api=["ETH","NET","WEB3","DEBUG","TRACE"] rpc-http-cors-origins=["*"] rpc-http-host-allowlist=["*"] # WebSocket RPC (recommended for ThirdWeb) rpc-ws-enabled=true rpc-ws-host="0.0.0.0" rpc-ws-port=8546 rpc-ws-api=["ETH","NET","WEB3"] rpc-ws-origins=["*"] # Metrics metrics-enabled=true metrics-port=9545 metrics-host="0.0.0.0" metrics-push-enabled=false # Logging logging="INFO" # Permissioning permissions-nodes-config-file-enabled=true permissions-nodes-config-file="/permissions/permissions-nodes.toml" permissions-accounts-config-file-enabled=false # Transaction Pool (optimized for ThirdWeb transaction volume) tx-pool-max-size=16384 tx-pool-price-bump=10 tx-pool-retention-hours=12 # Network Peering bootnodes=[] # Static Nodes (validators and other nodes) static-nodes-file="/genesis/static-nodes.json" # Discovery (enabled for redundancy) discovery-enabled=true # Privacy (disabled for public network) privacy-enabled=false # Gas Configuration (no fee cap for ThirdWeb compatibility) rpc-tx-feecap="0x0" # P2P Configuration (more peers for better connectivity) max-peers=50 # GraphQL (optional, for advanced queries) graphql-http-enabled=false # JSON-RPC timeout (increased for ThirdWeb operations) rpc-http-timeout=60 EOF log_success "ThirdWeb RPC configuration created" } # Main execution main() { echo "" log_info "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" log_info "ThirdWeb RPC Node Setup Script" log_info "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" log_info "Target: $PROXMOX_HOST" log_info "Storage: $STORAGE" log_info "Template: $TEMPLATE" echo "" # Check SSH access if ! check_ssh_access; then exit 1 fi echo "" log_info "This will create ${#THIRDWEB_RPC_NODES[@]} ThirdWeb RPC nodes:" for vmid in "${!THIRDWEB_RPC_NODES[@]}"; do IFS=':' read -r hostname ip description <<< "${THIRDWEB_RPC_NODES[$vmid]}" log_info " • VMID $vmid: $hostname ($ip) - $description" done echo "" # Check for non-interactive mode if [[ "${NON_INTERACTIVE:-}" == "1" ]] || [[ ! -t 0 ]]; then log_info "Non-interactive mode: proceeding automatically" else read -p "Continue? (y/N): " -n 1 -r echo "" if [[ ! $REPLY =~ ^[Yy]$ ]]; then log_info "Setup cancelled" exit 0 fi fi local success_count=0 local fail_count=0 local skip_count=0 echo "" log_info "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" log_info "Creating ThirdWeb RPC Containers" log_info "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" # Create containers for vmid in "${!THIRDWEB_RPC_NODES[@]}"; do IFS=':' read -r hostname ip description <<< "${THIRDWEB_RPC_NODES[$vmid]}" local exists=$(container_exists "$vmid") if [[ "$exists" == "exists" ]]; then log_warn "Container $vmid already exists, skipping creation..." skip_count=$((skip_count + 1)) elif create_container "$vmid" "$hostname" "$ip" "$description"; then success_count=$((success_count + 1)) else fail_count=$((fail_count + 1)) fi echo "" done echo "" log_info "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" log_info "Configuring Besu RPC on Containers" log_info "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" # Setup Besu on each container for vmid in "${!THIRDWEB_RPC_NODES[@]}"; do IFS=':' read -r hostname ip description <<< "${THIRDWEB_RPC_NODES[$vmid]}" log_info "Setting up container $vmid..." if setup_besu_rpc "$vmid" "$hostname" "$ip"; then log_success "Container $vmid configured successfully" else log_error "Failed to configure container $vmid" fail_count=$((fail_count + 1)) fi echo "" done # Summary echo "" log_info "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" log_info "Setup Summary" log_info "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" log_info "Created: $success_count" log_info "Skipped: $skip_count" log_info "Failed: $fail_count" echo "" if [[ $fail_count -eq 0 ]]; then log_success "ThirdWeb RPC nodes setup completed!" echo "" log_info "Next steps:" log_info "1. Verify containers are running:" for vmid in "${!THIRDWEB_RPC_NODES[@]}"; do IFS=':' read -r hostname ip description <<< "${THIRDWEB_RPC_NODES[$vmid]}" log_info " ssh root@$PROXMOX_HOST 'pct status $vmid'" done echo "" log_info "2. Start Besu services (if not auto-started):" for vmid in "${!THIRDWEB_RPC_NODES[@]}"; do IFS=':' read -r hostname ip description <<< "${THIRDWEB_RPC_NODES[$vmid]}" log_info " ssh root@$PROXMOX_HOST 'pct exec $vmid -- systemctl start besu-rpc.service'" done echo "" log_info "3. Test RPC endpoints:" for vmid in "${!THIRDWEB_RPC_NODES[@]}"; do IFS=':' read -r hostname ip description <<< "${THIRDWEB_RPC_NODES[$vmid]}" log_info " curl -X POST http://${ip}:8545 -H 'Content-Type: application/json' --data '{\"jsonrpc\":\"2.0\",\"method\":\"eth_blockNumber\",\"params\":[],\"id\":1}'" done echo "" log_info "4. Configure ThirdWeb to use these RPC endpoints:" for vmid in "${!THIRDWEB_RPC_NODES[@]}"; do IFS=':' read -r hostname ip description <<< "${THIRDWEB_RPC_NODES[$vmid]}" log_info " HTTP: http://${ip}:8545" log_info " WebSocket: ws://${ip}:8546" done else log_warn "Some containers failed to setup. Check logs above." fi } # Run main function main "$@"