Octa Engineering Notes Christian Elías Request for Comments: OCTA-16 octa.page Category: Informational June 2026 floo: a minimal deploy agent for self-hosted VPS Abstract floo runs an HTTP deploy agent on the server with YAML-defined project steps, scoped tokens stored as SHA-256 hashes, and real-time log streaming via SSE. systemd as the process supervisor, no Docker, no managed platforms. Status of This Memo This memo documents notes notes for the Internet community. It does not specify an Internet standard of any kind. Distribution of this memo is unlimited. The canonical version lives at https://octa.page/doc/floo-deploy-agent/ and the machine-readable source at https://octa.page/doc/floo-deploy-agent.md Every VPS deployment ends up as the same ritual: SSH in, "git pull", "npm install", "pm2 restart". Automating it properly means either exposing SSH credentials to CI or paying for a platform that wraps a container runtime you don't need. "floo" runs an HTTP agent on the server. You configure projects and their steps in a YAML file. You issue tokens — one per project, scoped, shown once, stored hashed. From your machine or a CI pipeline, you run "floo myapp" and the deploy logs stream back in real time via SSE. projects: avelor.es: cwd: /var/www/html/avelor.es steps: - git fetch origin master - git reset --hard origin/master - npm ci - pm2 restart avelor --update-env floo avelor.es → deploying avelor.es 4 steps [1/4] git fetch origin master ✓ [2/4] git reset --hard origin/master ✓ ... 1. Architecture decisions Tokens hashed at rest. SHA-256, shown once at issuance. The server stores no raw token — a dump of the token file is useless to an attacker. Per-project token scoping. A token for "avelor.es" returns 403 against any other project name. A compromised token can't enumerate projects or deploy anything else. SSE for log streaming. No WebSocket, no polling. The response is a "text/event-stream" that stays open while steps execute. "floo" the client reads it and prints each line as it arrives. systemd as the process supervisor. "floo agent install" writes and enables a systemd unit. No wrapper scripts, no custom daemon logic, no PID file juggling. "systemctl restart floo" is the ops interface. 2. What I ruled out o Webhook-only approaches — no streaming, no live feedback during a deploy. o Docker-based solutions — the sites running on this VPS are PHP + Node apps. A container runtime is overhead that doesn't pay for itself. o Managed platforms — Render, Railway, Fly — each has constraints on build environment or charges for what's effectively a small Node process and a git pull. 3. Implementation ~700 lines of Node.js across six modules. The agent is a plain "http.createServer". Steps run as "sh -c " subprocesses with stdout/stderr piped back line by line. The client is a fetch loop over the SSE response. Config is YAML via "js-yaml", tokens stored as JSON. Release pipeline builds platform binaries via Node SEA (Single Executable Applications) and publishes to npm and a Homebrew tap on each tag. npm install -g @avelor/floo v0.2.1. Repo: github.com/avelor-es/floo [1] 4. References [1] https://github.com/avelor-es/floo Christian Elías Informational [Page 1]