diff --git a/deploy/README.md b/deploy/README.md new file mode 100644 index 0000000..3d57344 --- /dev/null +++ b/deploy/README.md @@ -0,0 +1,70 @@ +# Deploy — Host VM setup + +Scripts for setting up a fresh Linux VM to host opencode-devbox. + +## Files + +- **`cloud-init.yml`** — cloud-init user-data template for automated VM provisioning on OpenStack, Proxmox, or any cloud with cloud-init support +- **`setup-host.sh`** — interactive post-install script for VMs that weren't provisioned with cloud-init + +## Supported distributions + +- **Debian 13 (Trixie)** — recommended (matches opencode-devbox base image) +- **Ubuntu 24.04 LTS** — also works + +Other distributions will need manual adaptation. + +## Quick start + +### Option 1: Cloud-init (automated) + +Customize `cloud-init.yml` — replace the SSH public key and optionally the hostname/timezone. Then use it during VM creation: + +- **Proxmox**: attach as cloud-init user-data +- **OpenStack**: `openstack server create --user-data cloud-init.yml ...` +- **AWS/DigitalOcean/etc**: paste into the "user data" field + +The VM boots with Docker installed, firewall configured, and your SSH key authorized. Log in as the `devbox` user. + +### Option 2: Post-install script (manual) + +On a fresh Debian/Ubuntu VM: + +```bash +curl -fsSL https://gitea.jordbo.se/joakimp/opencode-devbox/raw/branch/main/deploy/setup-host.sh | bash +``` + +Or clone and run: + +```bash +git clone https://gitea.jordbo.se/joakimp/opencode-devbox +cd opencode-devbox/deploy +./setup-host.sh +``` + +## What gets installed + +- Docker Engine (from Docker's official apt repo, not distro's `docker.io`) +- Docker Compose plugin (v2) +- `tmux`, `mosh`, `git` +- `ufw` firewall with SSH (22) and mosh (UDP 60000-61000) allowed +- IPv4 DNS preference (works around Docker Hub IPv6 connectivity issues) + +## VM sizing recommendations + +| Use case | vCPU | RAM | Disk | +|---|---|---|---| +| Minimum | 2 | 4 GB | 20 GB | +| Recommended | 4 | 8 GB | 40 GB | +| Heavy use (Rust/Python builds, multi-project) | 8 | 16 GB | 80 GB | + +## After VM setup + +```bash +mkdir -p ~/opencode-devbox && cd ~/opencode-devbox +curl -sL https://gitea.jordbo.se/joakimp/opencode-devbox/raw/branch/main/docker-compose.yml -o docker-compose.yml +curl -sL https://gitea.jordbo.se/joakimp/opencode-devbox/raw/branch/main/.env.example -o .env +vim .env # configure provider and keys +docker compose up -d +docker compose exec -u developer devbox opencode +``` diff --git a/deploy/cloud-init.yml b/deploy/cloud-init.yml new file mode 100644 index 0000000..c35c0bc --- /dev/null +++ b/deploy/cloud-init.yml @@ -0,0 +1,81 @@ +#cloud-config +# cloud-init template for opencode-devbox host VM +# Tested on Debian 13 (Trixie) and Ubuntu 24.04 +# +# Usage: +# - Proxmox: attach this file as cloud-init user-data in VM config +# - OpenStack: pass as --user-data when creating the instance +# - Cloud providers: paste into "user data" field +# +# Customize the marked sections before use. + +# ── Hostname ───────────────────────────────────────────────────────── +hostname: devbox +manage_etc_hosts: true + +# ── User ───────────────────────────────────────────────────────────── +users: + - name: devbox + groups: sudo, docker + shell: /bin/bash + sudo: ALL=(ALL) NOPASSWD:ALL + ssh_authorized_keys: + # CUSTOMIZE: replace with your public SSH key + - ssh-ed25519 AAAA... your-key-here + +# ── Locale and timezone ────────────────────────────────────────────── +locale: en_US.UTF-8 +timezone: Europe/Stockholm + +# ── Package installation ───────────────────────────────────────────── +package_update: true +package_upgrade: true +packages: + - ca-certificates + - curl + - gnupg + - git + - tmux + - mosh + - ufw + +# ── Commands to run at first boot ──────────────────────────────────── +runcmd: + # Install Docker from official repository + - install -m 0755 -d /etc/apt/keyrings + - curl -fsSL https://download.docker.com/linux/$(. /etc/os-release && echo "$ID")/gpg -o /etc/apt/keyrings/docker.asc + - chmod a+r /etc/apt/keyrings/docker.asc + - echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/$(. /etc/os-release && echo \"$ID\") $(. /etc/os-release && echo \"$VERSION_CODENAME\") stable" > /etc/apt/sources.list.d/docker.list + - apt-get update + - apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin + - usermod -aG docker devbox + + # Firewall — allow SSH, mosh, and optionally HTTPS if running web-accessible services + - ufw default deny incoming + - ufw default allow outgoing + - ufw allow ssh + - ufw allow 60000:61000/udp + - ufw --force enable + + # Disable IPv6 preference for Docker (avoids intermittent Docker Hub connectivity issues) + - echo 'precedence ::ffff:0:0/96 100' >> /etc/gai.conf + + # Create projects directory for the user + - mkdir -p /home/devbox/projects + - chown devbox:devbox /home/devbox/projects + +# ── Final message ─────────────────────────────────────────────────── +final_message: | + opencode-devbox host VM ready. + + Next steps: + 1. SSH in: ssh devbox@ + 2. Clone your opencode-devbox compose config, or: + mkdir -p ~/opencode-devbox && cd ~/opencode-devbox + curl -sL https://gitea.jordbo.se/joakimp/opencode-devbox/raw/branch/main/docker-compose.yml -o docker-compose.yml + curl -sL https://gitea.jordbo.se/joakimp/opencode-devbox/raw/branch/main/.env.example -o .env + 3. Edit .env with your provider and keys + 4. docker compose up -d + 5. docker compose exec -u developer devbox opencode + + Cloud-init run completed in $UPTIME seconds. diff --git a/deploy/setup-host.sh b/deploy/setup-host.sh new file mode 100755 index 0000000..d6ea4df --- /dev/null +++ b/deploy/setup-host.sh @@ -0,0 +1,135 @@ +#!/bin/bash +# setup-host.sh — Post-install script for opencode-devbox host VM +# +# Run this on a fresh Debian 13 or Ubuntu 24.04 VM to set up everything +# needed to run opencode-devbox containers. +# +# Usage: +# curl -fsSL https://gitea.jordbo.se/joakimp/opencode-devbox/raw/branch/main/deploy/setup-host.sh | bash +# +# Or clone and run: +# git clone https://gitea.jordbo.se/joakimp/opencode-devbox +# cd opencode-devbox/deploy +# ./setup-host.sh + +set -euo pipefail + +# ── Colors ────────────────────────────────────────────────────────── +BOLD="\033[1m"; GREEN="\033[32m"; YELLOW="\033[33m"; RED="\033[31m"; RESET="\033[0m" +info() { echo -e "${BOLD}==>${RESET} $*"; } +ok() { echo -e "${GREEN}${BOLD}✓${RESET} $*"; } +warn() { echo -e "${YELLOW}${BOLD}!${RESET} $*"; } +err() { echo -e "${RED}${BOLD}✗${RESET} $*" >&2; } + +# ── Detect distro ────────────────────────────────────────────────── +if [[ ! -f /etc/os-release ]]; then + err "Cannot detect Linux distribution — /etc/os-release missing" + exit 1 +fi + +. /etc/os-release + +case "$ID" in + debian|ubuntu) + info "Detected $PRETTY_NAME" + ;; + *) + err "Unsupported distribution: $ID — this script only supports Debian and Ubuntu" + exit 1 + ;; +esac + +# ── Require sudo ──────────────────────────────────────────────────── +if [[ $EUID -eq 0 ]]; then + err "Do not run as root — use a regular user with sudo" + exit 1 +fi + +if ! sudo -n true 2>/dev/null; then + warn "This script needs sudo access. You may be prompted for your password." +fi + +# ── Update packages ───────────────────────────────────────────────── +info "Updating package index..." +sudo apt-get update -qq + +info "Installing base packages..." +sudo apt-get install -y --no-install-recommends \ + ca-certificates curl gnupg git tmux mosh ufw + +# ── Docker ────────────────────────────────────────────────────────── +if command -v docker &>/dev/null; then + ok "Docker already installed ($(docker --version))" +else + info "Installing Docker from official repository..." + sudo install -m 0755 -d /etc/apt/keyrings + sudo curl -fsSL "https://download.docker.com/linux/${ID}/gpg" -o /etc/apt/keyrings/docker.asc + sudo chmod a+r /etc/apt/keyrings/docker.asc + + echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/${ID} ${VERSION_CODENAME} stable" | \ + sudo tee /etc/apt/sources.list.d/docker.list > /dev/null + + sudo apt-get update -qq + sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin + + ok "Docker installed: $(docker --version)" +fi + +# ── Add user to docker group ──────────────────────────────────────── +if groups | grep -q docker; then + ok "User already in docker group" +else + info "Adding $USER to docker group..." + sudo usermod -aG docker "$USER" + warn "You must log out and back in for docker group to take effect" + warn "Or run: newgrp docker" +fi + +# ── Firewall ──────────────────────────────────────────────────────── +info "Configuring firewall (ufw)..." +sudo ufw default deny incoming >/dev/null +sudo ufw default allow outgoing >/dev/null +sudo ufw allow ssh >/dev/null +sudo ufw allow 60000:61000/udp comment 'mosh' >/dev/null +if ! sudo ufw status | grep -q "Status: active"; then + sudo ufw --force enable +fi +ok "Firewall active — SSH and mosh allowed" + +# ── IPv4 preference for Docker Hub ────────────────────────────────── +if ! grep -q 'precedence ::ffff:0:0/96' /etc/gai.conf 2>/dev/null; then + info "Setting IPv4 preference in /etc/gai.conf..." + echo 'precedence ::ffff:0:0/96 100' | sudo tee -a /etc/gai.conf > /dev/null + ok "IPv4 preferred for DNS resolution" +fi + +# ── Create projects directory ─────────────────────────────────────── +if [[ ! -d "$HOME/projects" ]]; then + mkdir -p "$HOME/projects" + ok "Created ~/projects" +fi + +# ── Done ──────────────────────────────────────────────────────────── +echo "" +ok "Host setup complete" +echo "" +cat <@ + + 2. Set up opencode-devbox: + mkdir -p ~/opencode-devbox && cd ~/opencode-devbox + curl -sL https://gitea.jordbo.se/joakimp/opencode-devbox/raw/branch/main/docker-compose.yml -o docker-compose.yml + curl -sL https://gitea.jordbo.se/joakimp/opencode-devbox/raw/branch/main/.env.example -o .env + + 3. Edit .env with your provider and API keys: + vim .env + + 4. Start and connect: + docker compose up -d + docker compose exec -u developer devbox opencode + +EOF