198 lines
6.6 KiB
Bash
198 lines
6.6 KiB
Bash
#!/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 <<EOF > "$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 <<EOF > "$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, "<html><body style='background:#1a1a1a;color:#eee;text-align:center;padding:50px;font-family:sans-serif;'><h1>🚀 MeshVPN Coordinator v$VERSION</h1><div style='background:#2a2a2a;padding:20px;border-radius:10px;display:inline-block;border:1px solid #444;'><p>STUN Port: <b style='color:#00ffaa;'>3478 (UDP)</b></p><p>Coord Port: <b style='color:#00ffaa;'>50051 (TCP)</b></p><p>Web Port: <b style='color:#00ffaa;'>8080 (TCP)</b></p></div><p style='margin-top:20px;color:#666;'>Status: <span style='color:#00ffaa;'>ONLINE</span></p></body></html>")
|
|
})
|
|
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 "-------------------------------------------------------"
|