Skip to content

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 timeout
  • RunDocker() — Docker CLI commands
  • RunSudo() — privileged operations
  • RunSystem() — 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

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 (Administrator through NoAccess) 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.