package main import ( "flag" "fmt" "os" "strings" "github.com/bdw/deploy/internal/config" "github.com/bdw/deploy/internal/ssh" "github.com/bdw/deploy/internal/state" ) func runInit(args []string) { fs := flag.NewFlagSet("init", flag.ExitOnError) host := fs.String("host", "", "VPS host (SSH config alias or user@host)") fs.Parse(args) // Get host from flag or config if *host == "" { cfg, err := config.Load() if err != nil { fmt.Fprintf(os.Stderr, "Error loading config: %v\n", err) os.Exit(1) } *host = cfg.Host } if *host == "" { fmt.Fprintf(os.Stderr, "Error: --host is required\n") fs.Usage() os.Exit(1) } fmt.Printf("Initializing VPS: %s\n", *host) // Connect to VPS client, err := ssh.Connect(*host) if err != nil { fmt.Fprintf(os.Stderr, "Error connecting to VPS: %v\n", err) os.Exit(1) } defer client.Close() // Detect OS fmt.Println("→ Detecting OS...") osRelease, err := client.Run("cat /etc/os-release") if err != nil { fmt.Fprintf(os.Stderr, "Error detecting OS: %v\n", err) os.Exit(1) } if !strings.Contains(osRelease, "Ubuntu") && !strings.Contains(osRelease, "Debian") { fmt.Fprintf(os.Stderr, "Error: Unsupported OS (only Ubuntu and Debian are supported)\n") os.Exit(1) } fmt.Println(" ✓ Detected Ubuntu/Debian") // Check if Caddy is already installed fmt.Println("→ Checking for Caddy...") _, err = client.Run("which caddy") if err == nil { fmt.Println(" ✓ Caddy already installed") } else { // Install Caddy fmt.Println(" Installing Caddy...") installCaddy(client) fmt.Println(" ✓ Caddy installed") } // Create Caddyfile fmt.Println("→ Configuring Caddy...") caddyfile := `{ email admin@example.com } import /etc/caddy/sites-enabled/* ` if err := client.WriteSudoFile("/etc/caddy/Caddyfile", caddyfile); err != nil { fmt.Fprintf(os.Stderr, "Error creating Caddyfile: %v\n", err) os.Exit(1) } fmt.Println(" ✓ Caddyfile created") // Create directories fmt.Println("→ Creating directories...") if _, err := client.RunSudo("mkdir -p /etc/deploy/env"); err != nil { fmt.Fprintf(os.Stderr, "Error creating /etc/deploy/env: %v\n", err) os.Exit(1) } if _, err := client.RunSudo("mkdir -p /etc/caddy/sites-enabled"); err != nil { fmt.Fprintf(os.Stderr, "Error creating /etc/caddy/sites-enabled: %v\n", err) os.Exit(1) } fmt.Println(" ✓ Directories created") // Enable and start Caddy fmt.Println("→ Starting Caddy...") if _, err := client.RunSudo("systemctl enable caddy"); err != nil { fmt.Fprintf(os.Stderr, "Error enabling Caddy: %v\n", err) os.Exit(1) } if _, err := client.RunSudo("systemctl restart caddy"); err != nil { fmt.Fprintf(os.Stderr, "Error starting Caddy: %v\n", err) os.Exit(1) } fmt.Println(" ✓ Caddy started") // Verify Caddy is running fmt.Println("→ Verifying installation...") output, err := client.RunSudo("systemctl is-active caddy") if err != nil || strings.TrimSpace(output) != "active" { fmt.Fprintf(os.Stderr, "Warning: Caddy may not be running properly\n") } else { fmt.Println(" ✓ Caddy is active") } // Initialize local state if needed st, err := state.Load() if err != nil { fmt.Fprintf(os.Stderr, "Error loading state: %v\n", err) os.Exit(1) } st.GetHost(*host) // Ensure host exists in state if err := st.Save(); err != nil { fmt.Fprintf(os.Stderr, "Error saving state: %v\n", err) os.Exit(1) } fmt.Println("\n✓ VPS initialized successfully!") fmt.Println("\nNext steps:") fmt.Println(" 1. Deploy a Go app:") fmt.Printf(" deploy deploy --host %s --binary ./myapp --domain api.example.com\n", *host) fmt.Println(" 2. Deploy a static site:") fmt.Printf(" deploy deploy --host %s --static --dir ./dist --domain example.com\n", *host) } func installCaddy(client *ssh.Client) { commands := []string{ "apt-get update", "apt-get install -y debian-keyring debian-archive-keyring apt-transport-https curl", "curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg", "curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list", "apt-get update", "apt-get install -y caddy", } for _, cmd := range commands { if _, err := client.RunSudo(cmd); err != nil { fmt.Fprintf(os.Stderr, "Error running: %s\nError: %v\n", cmd, err) os.Exit(1) } } }