Skip to content

Technical Architecture

Detailed Schema

  Browser
      |
      | HTTPS
      v
+-----+------+       +------------------+
|  Frontend  |       |     Backend      |
|   React    +------>|    Hono API      |
|  (Nginx)   | /api  |   SQLite (WAL)   |
+------------+       +--------+---------+
                              |
                    HTTP POST | /caddy/reload
                    HTTP GET  | /logs
                   (Bearer)   |
                              v
                  +-----------+---------+
                  |       Agent         |
                  |      Hono API       |
                  +----+----------+-----+
                       |          |
            POST /load |          | read file
                       v          v
                  +----+----+ +---+--------+
                  |  Caddy  | | access.log |
                  |  Admin  | |  (JSON)    |
                  |   API   | +------------+
                  +---------+

Tech Stack

LayerTechnology
FrontendReact 19, TanStack Router, TanStack Query, Tailwind CSS
BackendHono.js, Better Auth, Drizzle ORM
DatabaseSQLite (better-sqlite3, WAL mode)
AgentHono.js (lightweight service, no DB)
RuntimeNode.js 22+
Package managerpnpm 9.15 (monorepo workspaces)
ContainerizationDocker multi-stage, Nginx (frontend)

Data Model

users

ColumnTypeDescription
idTEXT PKUnique identifier
nameTEXTUser name
emailTEXT UNIQUEEmail address
roleTEXTadmin or user
bannedBOOLEANBanned account
createdAtTIMESTAMPCreation date

vhosts

ColumnTypeDescription
idINTEGER PKAuto-increment
domainTEXT UNIQUEDomain name
configTEXTCaddyfile configuration
enabledBOOLEANVhost active or not
upstreamTEXTUpstream URL (optional)
createdAtTIMESTAMPCreation date
updatedAtTIMESTAMPLast modification

changelog

ColumnTypeDescription
idINTEGER PKAuto-increment
userIdTEXT FKReference to users.id
actionTEXTcreate, update, delete, toggle
domainTEXTAffected domain
diffTEXTJSON old/new config
createdAtTIMESTAMPModification date

Hub / Agent Communication

Communication uses HTTP with Authorization: Bearer <AGENT_TOKEN> header:

OperationMethodEndpointDescription
ReloadPOST/caddy/reloadSends the complete Caddyfile
LogsGET/logsReads access logs
Health checkGET/healthNo authentication required

Caddyfile Generation

  1. Retrieve active vhosts (enabled = true)
  2. Build the global block (ACME email, Caddy logs)
  3. Concatenate blocks: domain { config }
  4. Send to Caddy admin API (POST /load)
  5. On failure: rollback the database modification

Example generated Caddyfile:

nginx
{
  email admin@example.com
  log {
    output file /var/log/caddy/caddy.log
    format json
  }
}

app.example.com {
  reverse_proxy http://backend:8080
  log {
    output file /var/log/caddy/access.log {
      roll_size 100mb
      roll_keep 5
    }
    format json
  }
}