Skip to content

Architecture

Strawly runs as a set of Docker containers, one set per instance, started by Docker Compose. This page describes how the pieces fit together.

Services

Caddy (instance proxy)

  • Purpose: Serves the web interface and the API on one address and one port (STRAWLY_HTTP_PORT). Requests to /api go to the backend, everything else to the frontend.
  • Why one address: The browser talks to a single origin, so there is no cross-origin setup, and the login cookie works the same in every mode.

Frontend

  • Framework: Next.js
  • Purpose: Web interface. It talks only to the backend API, never to modules or the database.
  • Configuration: Reads its settings when it starts, not when the image is built, so the same image works in every deployment.

Backend

  • Framework: Express.js, with PostgreSQL through Prisma
  • Purpose: The API. It handles sign-in and permissions, stores settings, serves the data modules collect, and proxies module requests that need the module itself.
  • Schema ownership: The backend owns the database schema. Only its migrations container changes it. Modules never run migrations.

PostgreSQL

  • Purpose: One database per instance, shared by the backend and the modules.
  • Exposure: Reachable only inside the instance's Docker network.
  • Data separation: Each module writes its own prefixed tables, for example az_* in the azure schema.

Migrations and seeder (one-shot containers)

  • migrations runs prisma migrate deploy, then exits. It runs on every start, so an upgrade updates the database before the new backend starts.
  • seeder creates the default roles and, on a new database, the first admin account. It can run any number of times.

Modules (optional)

Each module is its own service, enabled with a compose profile. The Azure Optimizations module runs two containers from one image: the API (optimizations-azure) and the collector scheduler (optimizations-azure-worker). See Modules Overview.

Edge proxy (domain mode)

One Caddy server per machine, shared by every instance that uses a domain. It owns ports 80 and 443, gets a Let's Encrypt certificate for each domain, and forwards each domain to that instance's proxy. See Multiple Instances.

Data flow

Browser ──HTTPS──> Edge proxy (domain mode only)
                     │
                     ▼
                   Instance proxy (Caddy, one port)
                     ├── /api/*  ──> Backend ──> PostgreSQL <── Module
                     └── /*      ──> Frontend                    │
                                                                 ▼
                                                         Azure APIs

The frontend never talks to modules directly. Modules write their findings to the database, and the backend serves them.

Startup order

  1. postgres starts and reports healthy.
  2. migrations updates the schema and exits.
  3. seeder creates roles and the first admin, and exits.
  4. backend starts.
  5. frontend, caddy and the modules start once the backend is healthy.

Module registration

When a module starts, and every minute after, it registers with the backend. It sends its version, the core versions it supports, the database schema it was built for, and its default settings.

  • On a new instance, registration creates the module's settings, so the module appears in Strawly without any setup step. Later registrations never overwrite settings you changed.
  • Version check. The backend replies whether the module fits the running core and database. A module that does not fit pauses its collectors and reports incompatible in its health check, and the backend refuses requests to it with a message naming both versions.

Versioning

The frontend and backend share one version, the core version. Modules have their own versions and declare the core versions they support. See Updating.

Images are built when a version is tagged in the source repository, for linux/amd64 and linux/arm64, and published as:

Image Tags
git.strawly.app/strawly/strawly-backend 1.5.0, 1.5, 1, latest
git.strawly.app/strawly/strawly-frontend the same as the backend
git.strawly.app/strawly/strawly-optimizations-azure its own versions

Pre-releases such as 1.6.0-rc.1 are published only under their own tag. Each image carries its version, source commit and, for modules, the supported core range as image labels.

Repositories

Repository Contains
Strawly/backend The API
Strawly/frontend The web interface
Strawly/optimizations-azure The Azure module
Strawly/shared Code and the database schema shared by the backend and modules
Strawly/deployment Compose files, the strawly command, the installer and versions.json

Secrets

Secrets are passed to the containers as environment variables when they start and are never built into images. The installer generates them into the instance's .env. See Environment Variables.