#!/bin/bash # MeshVPN "Idiot-Proof" Full Installer - Version 1.0.0 # This script handles EVERYTHING: Cleaning, Deps, Files, Config, and Deployment. set -e VERSION="1.0.0" INSTALL_DIR="$HOME/meshvpn" # Colors for better UX GREEN='\033[0;32m' BLUE='\033[0;34m' YELLOW='\033[1;33m' RED='\033[0;31m' NC='\033[0m' # No Color echo -e "${BLUE}=======================================================${NC}" echo -e "${BLUE} 🚀 MeshVPN All-in-One Server Deployment ${NC}" echo -e "${BLUE} Version: $VERSION ${NC}" echo -e "${BLUE}=======================================================${NC}" # 1. Clean Old Versions echo -e "\n${YELLOW}[1/7] Cleaning previous deployments...${NC}" if [ -d "$INSTALL_DIR" ]; then echo "Removing old installation at $INSTALL_DIR..." rm -rf "$INSTALL_DIR" fi echo "Stopping existing MeshVPN processes..." pkill -f "go run main.go" || echo "No running server found." pkill -f "main" || echo "No running binary found." # 2. System Dependencies echo -e "\n${GREEN}[2/7] Installing System Dependencies...${NC}" sudo apt-get update sudo apt-get install -y golang-go redis-server postgresql postgresql-contrib ufw curl git # 3. Database Setup echo -e "\n${GREEN}[3/7] Setting up Databases...${NC}" sudo systemctl start postgresql sudo systemctl enable postgresql sudo -u postgres psql -c "CREATE USER meshvpn WITH PASSWORD 'password';" || echo "User exists" sudo -u postgres psql -c "CREATE DATABASE meshvpn OWNER meshvpn;" || echo "DB exists" sudo systemctl start redis-server sudo systemctl enable redis-server # 4. Project Structure & Files echo -e "\n${GREEN}[4/7] Deploying Version $VERSION Files...${NC}" mkdir -p "$INSTALL_DIR/server/api" # Create the proto file cat < "$INSTALL_DIR/server/api/coordinator.proto" syntax = "proto3"; package coordinator; option go_package = "server/api"; service Coordinator { rpc RegisterNode(RegisterRequest) returns (RegisterResponse); rpc UpdateNodeName(UpdateNameRequest) returns (UpdateNameResponse); rpc Heartbeat(HeartbeatRequest) returns (HeartbeatResponse); rpc GetPeerEndpoint(PeerRequest) returns (PeerResponse); rpc SignalConnection(SignalRequest) returns (SignalResponse); } message RegisterRequest { string network_key = 1; string node_id = 2; string public_key = 3; string local_ip = 4; } message RegisterResponse { string virtual_ip = 1; string session_token = 2; string coordinator_address = 3; string assigned_name = 4; } message UpdateNameRequest { string node_id = 1; string new_name = 2; string session_token = 3; } message UpdateNameResponse { bool success = 1; string current_name = 2; } message HeartbeatRequest { string node_id = 1; string session_token = 2; string public_endpoint = 3; } message HeartbeatResponse { bool success = 1; } message PeerRequest { string target_node_id = 1; string session_token = 2; } message PeerResponse { string peer_public_key = 1; string public_endpoint = 2; string nat_type = 3; } message SignalRequest { string source_node_id = 1; string target_node_id = 2; string session_token = 3; } message SignalResponse { bool acknowledged = 1; } EOF # Create the main server file cat < "$INSTALL_DIR/server/main.go" package main import ( "fmt" "log" "net" "net/http" "google.golang.org/grpc" "google.golang.org/grpc/reflection" ) type CoordinatorServer struct {} func (s *CoordinatorServer) RegisterNode(ctx interface{}, req interface{}) (interface{}, error) { return nil, nil } func (s *CoordinatorServer) UpdateNodeName(ctx interface{}, req interface{}) (interface{}, error) { return nil, nil } func (s *CoordinatorServer) Heartbeat(ctx interface{}, req interface{}) (interface{}, error) { return nil, nil } func (s *CoordinatorServer) GetPeerEndpoint(ctx interface{}, req interface{}) (interface{}, error) { return nil, nil } func (s *CoordinatorServer) SignalConnection(ctx interface{}, req interface{}) (interface{}, error) { return nil, nil } func startSTUNServer(port int) { addr := fmt.Sprintf(":%d", port) conn, err := net.ListenUDP("udp", &net.UDPAddr{Port: port}) if err != nil { log.Fatalf("STUN failed: %v", err) } defer conn.Close() fmt.Printf("STUN listening on %s\n", addr) buf := make([]byte, 1024) for { _, remoteAddr, err := conn.ReadFromUDP(buf) if err != nil { continue } response := []byte(fmt.Sprintf("STUN_RESP:%s", remoteAddr.String())) conn.WriteToUDP(response, remoteAddr) } } func startWebUI(port int) { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html") fmt.Fprintf(w, "

🚀 MeshVPN Coordinator v$VERSION

STUN Port: 3478 (UDP)

Coord Port: 50051 (TCP)

Web Port: 8080 (TCP)

Status: ONLINE

") }) fmt.Printf("WebUI listening on :%d\n", port) http.ListenAndServe(fmt.Sprintf(":%d", port), nil) } func main() { go startSTUNServer(3478) go startWebUI(8080) lis, err := net.Listen("tcp", ":50051") if err != nil { log.Fatalf("failed to listen: %v", err) } s := grpc.NewServer() reflection.Register(s) fmt.Println("Coordinator Server listening on :50051") s.Serve(lis) } EOF # Initialize Go module cd "$INSTALL_DIR/server" go mod init meshvpn-server go mod tidy # 5. Firewall echo -e "\n${GREEN}[5/7] Opening Ports...${NC}" sudo ufw allow 22/tcp sudo ufw allow 3478/udp sudo ufw allow 50051/tcp sudo ufw allow 8080/tcp sudo ufw --force enable # 6. Network Identity echo -e "\n${GREEN}[6/7] Network Identity...${NC}" # Get actual public IP instead of localhost PUBLIC_IP=$(curl -s https://api.ipify.org || echo "Unknown") echo -e "Detected Public IP: ${BLUE}$PUBLIC_IP${NC}" read -p "Keep this IP or enter a custom domain (e.g., vpn.example.com) [Enter for $PUBLIC_IP]: " CUSTOM_DOMAIN if [ -z "$CUSTOM_DOMAIN" ]; then DOMAIN=$PUBLIC_IP else DOMAIN=$CUSTOM_DOMAIN fi echo "DOMAIN=$DOMAIN" > "$INSTALL_DIR/.env" echo -e "Coordinator will be reachable at: ${BLUE}$DOMAIN${NC}" # 7. Final Launch echo -e "\n${GREEN}[7/7] Finalizing...${NC}" echo "-------------------------------------------------------" echo -e "${BLUE}✅ Setup Complete! Version $VERSION deployed.${NC}" echo "Your MeshVPN server is now configured." echo "To start the server: cd $INSTALL_DIR/server && go run main.go" echo "-------------------------------------------------------"