From 13c2f9cffa624fdf498f3b61fab9d809b92e026e Mon Sep 17 00:00:00 2001 From: bndw Date: Sun, 28 Dec 2025 09:21:08 -0800 Subject: init --- README.md | 221 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 221 insertions(+) create mode 100644 README.md (limited to 'README.md') diff --git a/README.md b/README.md new file mode 100644 index 0000000..8125bc9 --- /dev/null +++ b/README.md @@ -0,0 +1,221 @@ +# Deploy - VPS Deployment CLI + +Simple CLI tool for deploying Go apps and static sites to a VPS with automatic HTTPS via Caddy. + +## Features + +- Single command deployment from your laptop +- Automatic HTTPS via Caddy + Let's Encrypt +- Automatic port allocation (no manual tracking) +- Environment variable management +- Systemd process management with auto-restart +- Support for multiple apps/sites on one VPS +- State stored locally (VPS is stateless and easily recreatable) +- Zero dependencies on VPS (just installs Caddy) + +## Installation + +```bash +# Build the CLI +go build -o ~/bin/deploy ./cmd/deploy + +# Or install to GOPATH +go install ./cmd/deploy +``` + +## Quick Start + +### 1. Initialize Your VPS (One-time) + +```bash +# Initialize a fresh VPS +deploy init --host user@your-vps-ip +``` + +This will: +- Install Caddy +- Configure Caddy for automatic HTTPS +- Create necessary directories +- Set up the VPS for deployments + +### 2. Deploy a Go App + +```bash +# Build your app for Linux +GOOS=linux GOARCH=amd64 go build -o myapp + +# Deploy it +deploy deploy --host user@vps-ip --binary ./myapp --domain api.example.com + +# With environment variables +deploy deploy --host user@vps-ip --binary ./myapp --domain api.example.com \ + --env DB_HOST=localhost \ + --env API_KEY=secret + +# Or from an env file +deploy deploy --host user@vps-ip --binary ./myapp --domain api.example.com \ + --env-file .env.production +``` + +### 3. Deploy a Static Site + +```bash +# Build your site +npm run build + +# Deploy it +deploy deploy --host user@vps-ip --static --dir ./dist --domain example.com +``` + +## App Requirements + +Your Go app must: +1. Listen on HTTP (not HTTPS - Caddy handles that) +2. Accept port via `--port` flag or `PORT` environment variable +3. Bind to `localhost` or `127.0.0.1` only + +Example: + +```go +package main + +import ( + "flag" + "fmt" + "net/http" + "os" +) + +func main() { + port := flag.String("port", os.Getenv("PORT"), "port to listen on") + flag.Parse() + + if *port == "" { + *port = "8080" // fallback for local dev + } + + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte("Hello World")) + }) + + addr := "127.0.0.1:" + *port + fmt.Printf("Listening on %s\n", addr) + http.ListenAndServe(addr, nil) +} +``` + +## Commands + +### Initialize VPS +```bash +deploy init --host user@vps-ip +``` + +### Deploy App/Site +```bash +# Go app +deploy deploy --host user@vps-ip --binary ./myapp --domain api.example.com + +# Static site +deploy deploy --host user@vps-ip --static --dir ./dist --domain example.com + +# Custom name (defaults to binary/directory name) +deploy deploy --host user@vps-ip --name myapi --binary ./myapp --domain api.example.com +``` + +### List Deployments +```bash +deploy list --host user@vps-ip +``` + +### Manage Deployments +```bash +# View logs +deploy logs myapp --host user@vps-ip + +# View status +deploy status myapp --host user@vps-ip + +# Restart app +deploy restart myapp --host user@vps-ip + +# Remove deployment +deploy remove myapp --host user@vps-ip +``` + +### Environment Variables +```bash +# View current env vars (secrets are masked) +deploy env myapi --host user@vps-ip + +# Set env vars +deploy env myapi --host user@vps-ip --set DB_HOST=localhost --set API_KEY=secret + +# Load from file +deploy env myapi --host user@vps-ip --file .env.production + +# Unset env var +deploy env myapi --host user@vps-ip --unset API_KEY +``` + +## Configuration + +Create `~/.config/deploy/config` to avoid typing `--host` every time: + +``` +host: user@your-vps-ip +``` + +Then you can omit the `--host` flag: + +```bash +deploy list +deploy deploy --binary ./myapp --domain api.example.com +``` + +## How It Works + +1. **State on Laptop**: All deployment state lives at `~/.config/deploy/state.json` on your laptop +2. **SSH Orchestration**: The CLI uses SSH to run commands on your VPS +3. **File Transfer**: Binaries transferred via SCP, static sites via rsync +4. **Caddy for HTTPS**: Caddy automatically handles HTTPS certificates +5. **Systemd for Processes**: Apps run as systemd services with auto-restart +6. **Dumb VPS**: The VPS is stateless - you can recreate it by redeploying from local state + +## File Structure + +### On Laptop +``` +~/.config/deploy/state.json # All deployment state +~/.config/deploy/config # Optional: default host +``` + +### On VPS +``` +/usr/local/bin/myapp # Go binary +/var/lib/myapp/ # Working directory +/etc/systemd/system/myapp.service # Systemd unit +/etc/caddy/sites-enabled/myapp.caddy # Caddy config +/etc/deploy/env/myapp.env # Environment variables + +/var/www/mysite/ # Static site files +/etc/caddy/sites-enabled/mysite.caddy # Caddy config +``` + +## Security + +- Each Go app runs as dedicated system user +- Systemd security hardening enabled (NoNewPrivileges, PrivateTmp) +- Static sites served as www-data +- Caddy automatically manages TLS certificates +- Environment files stored with 0600 permissions +- Secrets masked when displaying environment variables + +## Supported OS + +- Ubuntu 20.04+ +- Debian 11+ + +## License + +MIT -- cgit v1.2.3