Architecture¶
Who this page is for
Developers and anyone who wants to understand how Eight.ly works under the hood. If you just want to use Eight.ly, you can skip this entirely — the Quick Start and Web Dashboard guides have everything you need.
One Product, One Binary¶
Eight.ly OS is a single Go binary with a React frontend embedded as static files. You install it by booting the installer image, on bare metal or in a VM — see Installing Eight.ly OS. There's no separate "Standard" or "Professional" product to choose between, no .deb install, and no Docker-container edition of Eight.ly itself.
| Backend | Go (single binary, /usr/bin/eightly) |
| Frontend | React 19 + TypeScript + Vite, embedded as static files |
| Port | 8080 |
| Auth | HMAC-SHA256 signed cookies, or eos_-prefixed API keys |
| Database | SQLite (WAL mode) + JSON fallback |
| Repo | imogenlabs/eightly (private) |
Historical note
Older docs described three separately sold editions — Standard, Professional, and OS — set by an EIGHTLY_EDITION environment variable on the same binary. That variable and the capability-gating code behind it are still in the codebase (the license and update systems use it internally), but the editions themselves are retired as products: Eight.ly OS is what ships, end to end, for everyone. If you're reading a guide that still talks about choosing an edition or installing a .deb, that guide is stale.
The Go Binary¶
Single binary¶
Eight.ly OS ships as one compiled Go binary (/usr/bin/eightly) with the React frontend embedded as static files (/usr/share/eightly/web/static/). No containers needed to run Eight.ly itself — it manages Docker for your apps but doesn't run inside Docker.
Tech stack¶
| Layer | Technology |
|---|---|
| Backend | Go (single binary) |
| Frontend | React 19 + TypeScript + Vite + shadcn/ui + Tailwind CSS |
| VMs | libvirt + QEMU/KVM (via go-libvirt) |
| LXC | lxc-tools CLI |
| Docker | Docker Engine API |
| VM Console | noVNC (VNC over WebSocket) |
| Shell / LXC Console | xterm.js (WebSocket PTY) |
| Auth | HMAC-SHA256 signed cookies with RBAC |
| Database | SQLite (WAL mode, modernc.org/sqlite) + JSON dual-write |
| Streaming | Server-Sent Events (SSE) + WebSocket |
| AI | Ollama (local inference, for Nova) |
Package layout¶
cmd/eightly/
main.go — entry point, dependency injection
routes.go — HTTP route wiring
internal/
nova/ — AI assistant: catalog, engine, proxy, tools, chats, install, extract
vm/ — KVM/QEMU VM management via go-libvirt
lxc/ — LXC container management
node/ — host node management (/proc parsing, services, shell)
network/ — network interfaces, Docker networks, Traefik
storage/ — SnapRAID, MergerFS, device scanning, cache mover
calendar/ — media release calendar (Sonarr/Radarr/Lidarr) + NAS events
ports/ — port conflict detection and available port lookup
seerr/ — Overseerr/Jellyseerr proxy with masked API keys
settings/ — settings types, load/save, template processing
platform/ — RunCmd, RunDocker, RunSystem, encryption, metrics
httputil/ — response helpers, RBAC middleware
firewall/ — UFW + per-VM iptables (groups, aliases, IP sets)
acme/ — ACME/Let's Encrypt cert management
permissions/ — path-based ACL roles (Proxmox-style)
ceph/ — Ceph distributed storage (experimental)
ha/ — high availability monitoring (Rehome, experimental)
cluster/ — multi-node clustering (experimental)
... (~30 packages total)
pkg/api/
apps/ — App Store (3,200+ templates, install wizard, GPU passthrough)
auth/ — signed-cookie auth, sessions, 2FA, API keys
container/ — Docker container management
files/ — file operations (list, mkdir, upload, delete)
filesharing/ — SMB/NFS file sharing
health/ — system health, Grafana proxy
license/ — license activation, heartbeat, catalog sync
storage/ — NAS storage routes, SnapRAID config
zfs/ — ZFS pool create, import, snapshot
backup/ — EBS backup handlers
... (~15 packages total)
cli/ — eosctl and eosctl-mcp, generated from the API
web/eightly-dashboard/ — React frontend
training/ — Nova AI fine-tuning dataset + generators
Data persistence¶
Eight.ly OS uses a dual-write pattern — data is written to both SQLite and JSON files:
/var/lib/eightly/eightly.db — SQLite database (WAL mode)
/etc/eightly/settings.json — Settings
/etc/eightly/users.json — User accounts
/etc/eightly/api-keys.json — API keys (SHA256 hashed)
/var/lib/eightly/vm/ — VM disk images and configs
/opt/appdata/ — Docker app data
Reads prefer SQLite, fall back to JSON. Crash recovery via RecoverJSON() restores from .bak files on startup. All writes use AtomicWriteJSON() — write to temp file with fsync, create .bak backup, atomic rename.
Command execution¶
All process execution goes through centralized helpers in internal/platform/cmdrunner.go:
RunCmd()— general command execution with timeoutRunDocker()— Docker CLI commandsRunSudo()— privileged operationsRunSystem()— system-level commands
Direct exec.Command is only permitted for WebSocket shells and SSE streaming pipes.
Architecture standards¶
- Go files: max 1,000 lines (split by domain when exceeded)
- Frontend files: max 500 lines
- Handler/service separation — handlers parse requests and write responses, business logic lives in service functions
- No Bootstrap — checked on every pull request by
scripts/check-no-bootstrap.py, which fails on any Bootstrap dependency, import or class and names the file and line
The CLI, API, and MCP layer¶
Everything the dashboard does goes through the HTTP API described by the OpenAPI spec every box serves at /api/openapi.json, generated straight from the router (scripts/gen-openapi.py) — see API Reference.
Two more tools are generated from that same spec, so neither can drift out of sync with it:
eosctl— a command line client covering the API's command groups (containers, VMs, LXC, storage, backup, Nova, and more).eosctl-mcp— an MCP server exposing the same operations as tools an AI assistant can call directly.
Both authenticate with the same eos_-prefixed API keys the dashboard issues — see API Keys.
Template System¶
Eight.ly uses one template format from the private eightly-templates repo:
templates/
{group}/ # e.g. media, tools, ai, network
{subcategory}/ # e.g. streaming, databases, dns
{app-name}/
docker-compose.yml # Standard Docker Compose file
metadata.json # Name, description, icon, URLs, author
- 14 groups, roughly 120 subcategories, 3,200+ apps
- Every install gets templates via the license-gated catalog API at
updates.eight.ly - See App Store & Templates and How the App Catalog Works for the full pipeline
How Deployment Works¶
sequenceDiagram
autonumber
participant B as Browser
participant F as Frontend
participant A as Backend
participant T as Templates
participant D as Docker
B->>F: Click Deploy (app, mode)
F->>A: POST /api/apps/install
A->>T: Load docker-compose.yml
T-->>A: Compose file
Note over A: Transform for deploy mode:<br/>Bridge: strip Traefik labels<br/>Traefik: keep labels + proxy network<br/>Authelia: add SSO middleware
A->>A: Inject GPU config if requested
A->>D: docker compose up -d
D-->>A: Stream output
A-->>F: SSE stream (real-time)
F-->>B: Live progress log
D->>D: Container starts
A-->>F: Success Security Model¶
- HMAC-SHA256 signed cookies (HttpOnly, Secure, SameSite=Strict) for the dashboard
eos_API keys (SHA-256 hashed at rest) for scripts,eosctl, and the MCP server — a key carries no scope of its own; it acts with whichever role the creating account holds- A coarse, three-role account model (
admin/operator/viewer) gates the API, deny-by-default per subsystem — see API Reference - A separate, finer-grained path-based ACL system (Proxmox-style) with 11 built-in roles (
AdministratorthroughNoAccess) layers on top for per-path permissions - TOTP 2FA per user
- LDAP/AD/OIDC/PAM auth realms
- Agent tokens with 30-day TTL
- TLS TOFU cert pinning for agent and EBS connections
- Per-IP rate limiting on registration and login endpoints
- Storage validation guardrails on mutation endpoints (inode/hardlink safety checks around the MergerFS array, guarding against the storage mistakes covered in Storage)
See Security Model for the full security documentation.