Architecture
An Aetheus installation is three processes and one database, plus one agent per managed server. Knowing which is which is what makes the installation pages readable.
The processes
| Component | What it is | Listens on |
|---|---|---|
| Backend | ASP.NET Core application. Owns the database, the REST API, authentication, pipeline scheduling, artefact storage and the internal Git server. | HTTP, loopback in production |
| Frontend | Blazor WebAssembly application, compiled to static files. It runs entirely in the visitor's browser and calls the backend API over HTTPS. | Static files, served by any web server |
| Database | PostgreSQL. The single source of truth for everything except artefact blobs and Git repositories. | 5432, private network |
| Agent | .NET process on each managed server. Polls the backend, reports inventory and heartbeats, executes pipeline steps. | Nothing. Outbound HTTPS only. |
How traffic flows
Two public host names are involved, and they must be distinct:
- the app host serves the frontend's static files;
- the API host serves the backend.
The browser downloads the frontend from the app host, then makes cross-origin calls to the API host. Two consequences drive most first-install problems:
- the frontend must be told the API's public URL, through
ApiBaseUrl; - the backend must accept the app host as a CORS origin, through
Cors__Origins__0.
Get either wrong and the app loads but every request fails. Both are covered on each installation page.
Agents talk to the API host and nothing else. They never receive inbound connections, which is why an agent works on a machine with no public address.
TLS and the reverse proxy
Neither the backend nor the frontend terminates TLS. In every supported layout a reverse proxy holds the certificate and forwards cleartext HTTP to loopback. Binding the application ports to 127.0.0.1 rather than 0.0.0.0 is deliberate: on a shared host, publishing them on all interfaces would expose the API in cleartext and bypass the proxy's logs and headers.
The API host additionally needs WebSocket upgrade to be proxied, otherwise live run output and dashboard updates silently stop refreshing.
Where state lives
Four things survive a restart and must be part of your backup:
| State | Default location | Losing it means |
|---|---|---|
| PostgreSQL data | Database volume or your own cluster | Everything is gone. |
| Git repositories | /app/data/git-repos | Internally hosted repositories are gone, including pipeline definitions. |
| Artefacts | /app/data/artifacts | Past builds can no longer be redeployed or rolled back to. |
| Data-protection keys | /app/data/dp-keys | Existing sessions and protected payloads become undecryptable. |
Encryption keys, the JWT signing key and the initial admin password come from configuration rather than from the database. They are inputs to the install, not something the product generates for you on every start.
Schema migrations
The backend applies its Entity Framework migrations at startup. A fresh database is therefore created by simply starting the backend against an empty PostgreSQL database; there is no separate migration command to run first.
In the container image, migrations are executed by the entrypoint rather than by the application itself, so that exactly one process performs them. That is what Database__SkipMigrations=true combined with AETHEUS_RUN_MIGRATIONS=true expresses in the Compose file.
Health endpoints
/health/live- the process is up. Anonymous and cheap; this is what a container healthcheck should use./health/ready- the process is up and the database is reachable. This is the one to use before sending traffic to a freshly started instance.