From 4438edd1498ccd2cbb2d2b32155c4b2d1b7fb54a Mon Sep 17 00:00:00 2001 From: Leex Date: Wed, 8 Apr 2026 10:37:09 +0200 Subject: [PATCH 1/2] deploy: harden cloud-init with archon user, swap, and fixes - Create dedicated 'archon' user (sudo + docker groups, passwordless sudo, locked password) and copy SSH authorized_keys from default cloud user (with root fallback) so login works immediately. - Run docker pulls and the image build as the archon user via sudo -u. - Add 2GB swapfile to prevent OOM during docker build on small VPS (<2GB RAM). - Remove package_upgrade to speed up boot and avoid surprise kernel updates. - Drop redundant systemctl enable/start docker (get.docker.com handles it). - ufw allow 443/tcp for consistency with 22/80. - set -e before clone for fail-fast on network errors. - Update docs link to https://archon.diy/deployment/docker/. - SETUP_COMPLETE now instructs ssh archon@. - Header lists supported providers (incl. Hostinger) and notes the archon user + swap behavior. --- deploy/cloud-init.yml | 77 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 62 insertions(+), 15 deletions(-) diff --git a/deploy/cloud-init.yml b/deploy/cloud-init.yml index 9a689e98ad..d2f6359cc6 100644 --- a/deploy/cloud-init.yml +++ b/deploy/cloud-init.yml @@ -6,53 +6,97 @@ # # Paste this into your VPS provider's "User Data" field when creating a server. # Tested on: Ubuntu 22.04+, Debian 12+ +# Works with any cloud-init compatible provider (DigitalOcean, Hetzner, Linode, +# Vultr, AWS EC2, Hostinger, etc.) # # What this does: # 1. Installs Docker + Docker Compose plugin # 2. Opens firewall ports (SSH, HTTP, HTTPS) -# 3. Clones the repo to /opt/archon -# 4. Prepares .env and Caddyfile from examples -# 5. Builds the Docker image (~5 min) +# 3. Creates a 2GB swapfile (helps small VPS builds avoid OOM) +# 4. Clones the repo to /opt/archon +# 5. Prepares .env and Caddyfile from examples +# 6. Creates a dedicated 'archon' user (sudo + docker groups) +# 7. Builds the Docker image (~5 min) as the archon user # -# After the server boots (~5-8 min), SSH in and: +# Note: On VPS with <2GB RAM, the docker build step can OOM without swap. +# +# After the server boots (~5-8 min), SSH in as the archon user: +# ssh archon@your-server-ip # 1. Edit /opt/archon/.env — set your AI credentials, DOMAIN, DATABASE_URL # 2. cd /opt/archon && docker compose --profile with-db --profile cloud up -d # 3. Open https://your-domain.com # # IMPORTANT: Before starting, point your domain's DNS A record to this server's IP. +# SSH keys from the default cloud user are copied to 'archon'. # package_update: true -package_upgrade: true packages: - curl - git - ufw +users: + - default + - name: archon + gecos: Archon Service User + groups: [sudo, docker] + shell: /bin/bash + sudo: ALL=(ALL) NOPASSWD:ALL + lock_passwd: true + runcmd: + # --- Swap (helps small VPS avoid OOM during docker build) --- + - | + if [ ! -f /swapfile ]; then + fallocate -l 2G /swapfile || dd if=/dev/zero of=/swapfile bs=1M count=2048 + chmod 600 /swapfile + mkswap /swapfile + swapon /swapfile + echo '/swapfile none swap sw 0 0' >> /etc/fstab + fi + # --- Docker --- - curl -fsSL https://get.docker.com | sh - - systemctl enable docker - - systemctl start docker + - usermod -aG docker archon + + # --- Copy SSH keys from default user to archon (so login works immediately) --- + - | + DEFAULT_USER=$(getent passwd 1000 | cut -d: -f1) + if [ -n "$DEFAULT_USER" ] && [ -f /home/$DEFAULT_USER/.ssh/authorized_keys ]; then + mkdir -p /home/archon/.ssh + cp /home/$DEFAULT_USER/.ssh/authorized_keys /home/archon/.ssh/authorized_keys + chmod 700 /home/archon/.ssh + chmod 600 /home/archon/.ssh/authorized_keys + chown -R archon:archon /home/archon/.ssh + elif [ -f /root/.ssh/authorized_keys ]; then + mkdir -p /home/archon/.ssh + cp /root/.ssh/authorized_keys /home/archon/.ssh/authorized_keys + chmod 700 /home/archon/.ssh + chmod 600 /home/archon/.ssh/authorized_keys + chown -R archon:archon /home/archon/.ssh + fi # --- Firewall --- - ufw allow 22/tcp - ufw allow 80/tcp - - ufw allow 443 + - ufw allow 443/tcp - ufw --force enable - # --- Clone and configure --- + # --- Clone and configure (fail fast on errors) --- + - set -e - git clone https://github.com/coleam00/Archon.git /opt/archon - cp /opt/archon/.env.example /opt/archon/.env - cp /opt/archon/Caddyfile.example /opt/archon/Caddyfile + - chown -R archon:archon /opt/archon - # --- Pre-pull external images --- - - docker pull postgres:17-alpine - - docker pull caddy:2-alpine + # --- Pre-pull external images (as archon, via docker group) --- + - sudo -u archon docker pull postgres:17-alpine + - sudo -u archon docker pull caddy:2-alpine - # --- Build the app image --- - - cd /opt/archon && docker compose build + # --- Build the app image as archon --- + - sudo -u archon -H bash -c 'cd /opt/archon && docker compose build' # --- Signal completion --- - | @@ -61,6 +105,9 @@ runcmd: Archon server setup complete! ============================================ + Log in as the 'archon' user (not root): + ssh archon@ + Next steps: 1. Edit credentials and domain: @@ -85,7 +132,7 @@ runcmd: Logs: docker compose logs -f Health: curl https://your-domain.com/api/health - Docs: https://github.com/coleam00/Archon/blob/main/docs/docker.md + Docs: https://archon.diy/deployment/docker/ ============================================ DONE - echo "[archon] Setup complete. Edit /opt/archon/.env and run docker compose up." From 2348a53d461bd14640edfe69920916b23c472853 Mon Sep 17 00:00:00 2001 From: Leex Date: Wed, 8 Apr 2026 11:20:20 +0200 Subject: [PATCH 2/2] deploy: address PR review feedback on cloud-init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix set -e regression: merge clone/cp/chown into single shell block so fail-fast actually applies (CodeRabbit). - Drop passwordless sudo from archon user — docker group only. Removes trivial privilege escalation path (Wirasm). - Remove non-existent 'docker' group from initial users.groups list; it is added via usermod later (CodeRabbit). - Restore package_upgrade: true to patch CVEs in the base image before anything else runs (Wirasm). - Add ufw allow 443/udp for HTTP/3 QUIC — Caddy exposes 443:443/udp in docker-compose (CodeRabbit). - Update SETUP_COMPLETE and header comment to note archon user has no sudo (use default cloud user / root for maintenance). --- deploy/cloud-init.yml | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/deploy/cloud-init.yml b/deploy/cloud-init.yml index d2f6359cc6..9056665176 100644 --- a/deploy/cloud-init.yml +++ b/deploy/cloud-init.yml @@ -15,10 +15,12 @@ # 3. Creates a 2GB swapfile (helps small VPS builds avoid OOM) # 4. Clones the repo to /opt/archon # 5. Prepares .env and Caddyfile from examples -# 6. Creates a dedicated 'archon' user (sudo + docker groups) +# 6. Creates a dedicated 'archon' user (docker group only, no sudo) # 7. Builds the Docker image (~5 min) as the archon user # # Note: On VPS with <2GB RAM, the docker build step can OOM without swap. +# Note: The 'archon' user has docker access but NOT sudo. For administrative +# tasks (updates, reboots), use the default cloud user or root. # # After the server boots (~5-8 min), SSH in as the archon user: # ssh archon@your-server-ip @@ -31,6 +33,7 @@ # package_update: true +package_upgrade: true packages: - curl @@ -41,9 +44,7 @@ users: - default - name: archon gecos: Archon Service User - groups: [sudo, docker] shell: /bin/bash - sudo: ALL=(ALL) NOPASSWD:ALL lock_passwd: true runcmd: @@ -78,18 +79,20 @@ runcmd: chown -R archon:archon /home/archon/.ssh fi - # --- Firewall --- + # --- Firewall (443/udp needed for HTTP/3 QUIC via Caddy) --- - ufw allow 22/tcp - ufw allow 80/tcp - ufw allow 443/tcp + - ufw allow 443/udp - ufw --force enable - # --- Clone and configure (fail fast on errors) --- - - set -e - - git clone https://github.com/coleam00/Archon.git /opt/archon - - cp /opt/archon/.env.example /opt/archon/.env - - cp /opt/archon/Caddyfile.example /opt/archon/Caddyfile - - chown -R archon:archon /opt/archon + # --- Clone and configure (fail fast — single shell so set -e applies) --- + - | + set -e + git clone https://github.com/coleam00/Archon.git /opt/archon + cp /opt/archon/.env.example /opt/archon/.env + cp /opt/archon/Caddyfile.example /opt/archon/Caddyfile + chown -R archon:archon /opt/archon # --- Pre-pull external images (as archon, via docker group) --- - sudo -u archon docker pull postgres:17-alpine @@ -108,6 +111,10 @@ runcmd: Log in as the 'archon' user (not root): ssh archon@ + Note: the 'archon' user has docker access but no sudo. For system + maintenance (apt upgrade, reboots), log in as the default cloud user + or root. + Next steps: 1. Edit credentials and domain: