# Gebos IoT telemetry stack on bare-metal NixOS. This repo is a monorepo containing all code, NixOS modules, host configurations, and CI/CD pipelines for the project. Everything is one `flake.nix`. ## Architecture Three hosts (see issue #21 for the full design discussion): | Host | Role | Public hostname | | ------------- | ----------------------------------------- | ---------------------- | | `mqtt-ingest` | HiveMQ CE + Go MQTT→Postgres ingester | `ingest.ge-bos.de` | | `db-host` | Postgres 17 + TimescaleDB (telemetry+auth)| internal only | | `app-host` | Caddy + Kong + Supabase (compose) + SPA | `app.ge-bos.de`, `api.ge-bos.de` | Public REST surface is PostgREST + SQL `/rpc/` functions, fronted by Kong, TLS-terminated by Caddy. Supabase Studio is bound to `127.0.0.1` on `app-host` — reach it with `ssh -L 3000:127.0.0.1:3000 app-host`. ## Repo layout ``` flake.nix frontend/ # Vite + React SPA ingester/ # Go MQTT → Postgres nix/ modules/ # NixOS modules (one per service) hosts/ # nixosConfigurations: mqtt-ingest, db-host, app-host supabase/ # vendored Supabase docker-compose, db init SQL dev/ # process-compose for local development deploy.nix # deploy-rs node map .gitea/workflows/ # CI + CD ``` ## Local development ``` nix run .#dev ``` Brings the full stack up on one machine via process-compose-flake (Postgres, Supabase compose, Kong, Caddy, ingester, Vite dev server). NixOS required. ## Deployment `deploy-rs` from a Gitea Actions runner on push to `main`. Closures are built once, copied to each host, activated with auto-rollback. Order: `db-host` → `app-host` → `mqtt-ingest`. ``` nix run github:serokell/deploy-rs -- .#db-host # one host nix run github:serokell/deploy-rs -- . # all hosts ``` ## Secrets Out-of-band file at `/etc/gebos/secrets.env` on each host, mode `0400`, loaded by systemd `EnvironmentFile=`. Not in the repo, not in the Nix store. Rotation is manual (ssh + edit + restart unit).