Open the app
Operations

VPS foundation (live)

What is actually deployed today: self-hosted Convex, the SSR frontend, FastAPI, Redis, monitoring and Portainer — in Docker behind the existing Traefik, isolated and portable.

Phase 1 “Foundation” is live on the Hostinger VPS: self-hosted Convex, the SSR frontend, a FastAPI service, Redis, a Prometheus/Grafana/Loki monitoring stack and Portainer — every component a container, behind the existing Traefik, isolated from the other projects on the box and portable to another host.

Topology

Internet
   |  HTTPS (Let's Encrypt - mytlschallenge)
   v
Traefik  (root-traefik-1, shared, network: root_default)
   |
   |- clawlas.com ........... frontend (SSR :3000)
   |- convex.clawlas.com .... convex-backend API (:3210)
   |- convex-site.clawlas.com convex-backend HTTP actions (:3211) - Better Auth
   |- convex-dashboard.* .... convex-dashboard (basic-auth)
   |- grafana.* ............. grafana
   '- portainer.* ........... portainer

internal networks (no host ports, isolated from other projects):
  clawlas_application   frontend <-> api
  clawlas_data          convex-backend - api - redis - backup
  clawlas_monitoring    prometheus - grafana - loki - promtail - node-exporter - cadvisor
  clawlas_execution     (reserved for future execution workers)
One Docker Compose project (clawlas) behind the existing Traefik. Only public-facing services join the root_default network; everything else lives on internal-only clawlas networks.

Access URLs

SurfaceURLHow to sign in
Web appclawlas.comEmail + password (Sign up / Sign in)
Convex dashboardconvex-dashboard.clawlas.comTraefik basic-auth, then the deployment URL (convex.clawlas.com) + admin key
Grafanagrafana.clawlas.comGrafana login (admin) — needs its DNS A record
Portainerportainer.clawlas.comPortainer login — needs its DNS A record
Convex API / siteconvex.clawlas.com · convex-site.clawlas.comProgrammatic — no UI (used by the app + the CLI)
Credentials are not in the docs
Passwords and the admin key live in the Bitwarden secure note and deploy/compose/.env on the VPS — never committed here.

Services

ServiceRoleNetworkPublic host
convex-backendSelf-hosted Convex (SQLite)root_default · dataconvex(-site).clawlas.com
convex-dashboardConvex admin UIroot_defaultconvex-dashboard.clawlas.com
frontendTanStack Start SSRroot_default · applicationclawlas.com
apiFastAPI (health/ready scaffold)application · data
redisValkey cache / event transportdata
grafanaDashboardsmonitoring · root_defaultgrafana.clawlas.com
prometheusMetricsmonitoring
node-exporter / cadvisorHost + container metricsmonitoring
loki / promtailLogs + shippingmonitoring
portainerDocker management UImonitoring · root_defaultportainer.clawlas.com
backuprestic snapshots (profile-gated)data

Not in this phase

No trading logic, workers, collectors or execution services yet — those arrive in later phases. The clawlas_execution network is created now but unused.

Container reference

Every container, its job and its key specs (drawn from deploy/compose/docker-compose.yml). All run restart: unless-stopped with no-new-privileges; resource limits are env-tunable; no service publishes a host port.

ghcr.io/get-convex/convex-backend (digest)

convex-backend

Self-hosted Convex backend: reactive DB, queries/mutations/actions, the Better Auth component and HTTP-action routes (SQLite).

Why: Owns the app data and auth on the VPS — no per-request Cloud bill, fully portable.

Specs: Ports 3210 (API) + 3211 (HTTP actions) · networks public + data · volume convex_data · 1 CPU / 1 GB · healthcheck /version

ghcr.io/get-convex/convex-dashboard (digest)

convex-dashboard

Convex admin UI (data browser, functions, logs, env). A browser app reaching the backend via the public URL plus the admin key.

Why: Operate and inspect self-hosted Convex (browse data, run functions, edit env) without the Cloud console.

Specs: Port 6791 · network public · depends on convex-backend · 0.5 CPU / 512 MB · Traefik basic-auth

clawlas-frontend:latest (built)

frontend

TanStack Start SSR web app and the /api/auth/* proxy to Convex, served by the Node host server.mjs.

Why: Serves the app from the VPS behind the same proxy, not a separate hosting platform.

Specs: Port 3000 · networks public + application · built from apps/web/Dockerfile · 0.5 CPU / 512 MB · non-root

valkey/valkey:8-alpine

redis

Valkey: in-memory cache today, the Redis-Streams event transport for later phases.

Why: A fast cache now, and the async event boundary the worker fleet will need — kept stable from day one.

Specs: Port 6379 (internal) · network data · volume redis_data · password-protected · 256 MB · healthcheck ping

clawlas-api:latest (built)

api

Internal FastAPI scaffold: /health (liveness) and /ready (pings Redis). No business logic yet.

Why: Establishes the Python/TypeScript boundary early; the future interface between Convex/web and the trading and AI workers.

Specs: Port 8000 (internal) · networks application + data · depends on redis · 0.5 CPU / 512 MB

prom/prometheus:v3.1.0

prometheus

Metrics time-series DB; scrapes node-exporter, cadvisor and itself.

Why: Measure resource use on a shared VPS so the stack can be tuned and never starves the other projects.

Specs: Port 9090 · network monitoring · volume prometheus_data · 15-day retention · 384 MB

prom/node-exporter:v1.8.2

node-exporter

Host metrics: CPU, memory, disk, network and load for the VPS.

Why: See host-level pressure (CPU, memory, disk) to size and alert.

Specs: Port 9100 · network monitoring · pid host, mounts / read-only · 128 MB

gcr.io/cadvisor/cadvisor:v0.49.1

cadvisor

Per-container CPU/memory/network/disk metrics.

Why: Attribute usage per container, to verify the resource isolation actually holds.

Specs: Port 8080 · network monitoring · privileged, read-only host mounts · 256 MB

grafana/loki:3.3.2

loki

Log aggregation store (single-binary, filesystem backend).

Why: Centralize logs for debugging without SSH-ing into each container.

Specs: Port 3100 · network monitoring · volume loki_data · 7-day retention · 256 MB

grafana/promtail:3.3.2

promtail

Tails container JSON logs and ships them to Loki.

Why: Gets every container log into Loki automatically.

Specs: Port 9080 · network monitoring · mounts container logs read-only · 128 MB

grafana/grafana:11.4.0

grafana

Dashboards and log exploration over Prometheus + Loki (auto-provisioned datasources).

Why: One place to watch metrics and logs — the day-to-day operability surface.

Specs: Port 3000 · networks monitoring + public · volume grafana_data · 256 MB · own login

portainer/portainer-ce:2.21.5

portainer

Docker management UI: containers, logs, volumes, stacks. Coexists with Traefik, no Swarm.

Why: Manage the stack from a UI without SSH; chosen over Dokploy because it coexists with the existing Traefik (no Swarm).

Specs: Port 9000 · networks monitoring + public · docker.sock + portainer_data · 256 MB · own login

offen/docker-volume-backup:v2.43.0

backup

Scheduled encrypted restic snapshots of every clawlas_* volume, off-host. Profile-gated.

Why: The off-host snapshot is the disaster-recovery and lift-and-shift unit — the portability guarantee.

Specs: Profile backup · network data · all volumes read-only · daily 03:00, 7-day retention · 256 MB

Networks and isolation

The whole stack is one Compose project named clawlas, so every container, volume and network is prefixed clawlas_* — no collision with the other projects on the shared VPS. Only public-facing services join the external root_default network; everything else sits on internal: true networks with no route to the internet and no published host ports. Each service has CPU and memory limits so Clawlas can never starve its neighbours.

  • project name: clawlas
  • named volumes (clawlas_*)
  • internal-only networks
  • per-service cpu/mem limits
  • no published host ports
  • Traefik-only ingress

Convex and the three origins

Convex is self-hosted (SQLite) and reached over three distinct public origins that are not derivable from one another — the browser and Better Auth need all three:

OriginPurpose
convex.clawlas.comAPI / cloud origin (:3210) — VITE_CONVEX_URL
convex-site.clawlas.comHTTP actions (:3211) — Better Auth routes, the /api/auth/* proxy target
clawlas.comthe app URL — Better Auth baseURL (Convex-side SITE_URL secret)

Better Auth runs as a Convex component; the frontend proxies /api/auth/* to the convex-site origin. Secrets (BETTER_AUTH_SECRET, SITE_URL) live on the Convex instance, never in an env file.

Frontend

The TanStack Start build emits a Web fetch handler but nothing that listens, so a small Node host — apps/web/server.mjs (@hono/node-server) — serves the static client assets and falls through to SSR. The image is multi-stage with a self-contained production node_modules (pnpm deploy) and runs non-root. Public VITE_* values are baked into the client at build time and also read from process.env at runtime for SSR.

Monitoring

Prometheus scrapes host metrics (node-exporter) and per-container usage (cadvisor); Promtail ships container logs to Loki; Grafana reads both via auto-provisioned datasources. The whole stack is on the isolated clawlas_monitoring network.

Backups and portability

  1. 1
    Encrypted off-host snapshots
    The backup service (restic, behind the `backup` compose profile) snapshots every clawlas_* volume to an off-host repository on a daily schedule.
  2. 2
    Lift-and-shift
    Moving to a new VPS = git clone + restore secrets from the Bitwarden note + deploy/scripts/restore.sh (repopulate volumes) + docker compose up -d + repoint DNS.
  3. 3
    Secrets stay out of snapshots
    The .env (root-600) never leaves the box and is not in the snapshot — the Bitwarden secure note is the secrets backup.
See the runbook
The deploy order, secrets, verification commands and the manual hardening checklist live in deploy/README.md; the architecture rationale is in docs/VPS_ARCHITECTURE.md.