Binaries, without Docker

This route publishes the backend and the frontend as ordinary files and runs them with the service manager you already use. It gives you the most control and the least automation.

The least paved of the three routes

The repository ships no installer for this layout: the container image is what the project builds, tests and deploys. Everything below is derived from what that image actually does, but you are assembling the pieces yourself. If you simply want a working instance, Docker is fewer moving parts.

Prerequisites

  • .NET SDK 10.0 on the machine that builds, and the ASP.NET Core 10.0 runtime on the machine that runs the backend. The repository pins SDK 10.0.202 in global.json.
  • PostgreSQL, with an empty database and an owner account.
  • A reverse proxy holding your TLS certificate, and two host names.
  • The four secrets from the shared prerequisites.

Publish the two applications

From a checkout of the repository. The backend is a normal ASP.NET Core application; the frontend is Blazor WebAssembly, so its output is a folder of static files rather than a process.

dotnet publish src/Aetheus.Back/Aetheus.Back.csproj \
    -c Release -o /opt/aetheus/back

dotnet publish src/Aetheus.Front/Aetheus.Front.csproj \
    -c Release -o /opt/aetheus/front-publish \
    -p:StaticWebAssetsPublishFingerprint=false

The files to serve are in /opt/aetheus/front-publish/wwwroot, not in the publish folder itself. That wwwroot directory is what your web server or reverse proxy will expose on the app host.

Point the frontend at your API

The frontend is downloaded and executed by the visitor's browser, so it cannot read server-side environment variables. Its API address is baked into a JSON file it fetches at startup: wwwroot/appsettings.json. Edit it after publishing, replacing the API base URL with your own:

{
  "ApiBaseUrl": "https://api.example.com"
}

Redo this after every upgrade

Publishing overwrites wwwroot/appsettings.json. Either script the edit as part of your deployment, or keep a copy and restore it. The container image automates exactly this step, from the API_BASE_URL environment variable.

Configure the backend

The backend reads standard .NET configuration, so every setting can be supplied as an environment variable using the double-underscore convention. The minimum set:

ASPNETCORE_ENVIRONMENT=Production
ASPNETCORE_URLS=http://127.0.0.1:5080

ConnectionStrings__Default=Host=127.0.0.1;Port=5432;Database=aetheus;Username=aetheus;Password=CHANGE_ME

Auth__JwtKey=CHANGE_ME
Auth__EncryptionKey=CHANGE_ME
Auth__EncryptionSalt=CHANGE_ME
Auth__AdminPassword=CHANGE_ME

# Public URL of this API, as the browser and the agents will reach it.
Aetheus__PublicApiBaseUrl=https://api.example.com
# The app host, allowed as a CORS origin. Without it the frontend loads and every call fails.
Cors__Origins__0=https://app.example.com

# Persistent state. Back these four directories up.
DataProtection__KeyPath=/var/lib/aetheus/dp-keys
GitLight__RepositoriesPath=/var/lib/aetheus/git-repos
ArtifactStorage__BasePath=/var/lib/aetheus/artifacts
PackageRegistry__BasePath=/var/lib/aetheus/packages

Bind to 127.0.0.1, not to 0.0.0.0: the reverse proxy is the only thing that should reach the backend, and listening on all interfaces would expose the API in cleartext.

Run it on Linux with systemd

Create /etc/aetheus/back.env with the settings above, one KEY=value per line, then /etc/systemd/system/aetheus-back.service:

[Unit]
Description=Aetheus backend
After=network-online.target postgresql.service
Wants=network-online.target

[Service]
Type=simple
User=aetheus
Group=aetheus
WorkingDirectory=/opt/aetheus/back
EnvironmentFile=/etc/aetheus/back.env
ExecStart=/usr/bin/dotnet /opt/aetheus/back/Aetheus.Back.dll
Restart=on-failure
RestartSec=5

# The state directories the service owns.
StateDirectory=aetheus
ProtectSystem=full
ProtectHome=true
NoNewPrivileges=true

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now aetheus-back
curl -sf http://127.0.0.1:5080/health/ready

The backend applies its database migrations at startup, so the first successful start is also what creates the schema. /health/ready answering 200 means the process is up and the database is reachable.

Run it on Windows as a service

Publish to C:\Aetheus\back, then register a service. Windows services do not read an env-file, so set the configuration as machine-level environment variables or put it in appsettings.Production.json next to the DLL.

sc.exe create AetheusBack ^
   binPath= "\"C:\Program Files\dotnet\dotnet.exe\" \"C:\Aetheus\back\Aetheus.Back.dll\"" ^
   start= auto ^
   DisplayName= "Aetheus backend"

sc.exe start AetheusBack

Hosting the backend under IIS instead

If the machine already runs IIS, hosting the backend as an IIS application with the ASP.NET Core Module is usually less friction than a bare service, because IIS then handles start-up, recycling and logging. See the IIS page, which carries an untested badge.

Serve the frontend files

The frontend is static: any web server can serve wwwroot. Two rules matter, and both are in the Apache, IIS and nginx pages:

  • unknown paths must fall back to index.html, because routing happens in the browser;
  • index.html and everything under _framework/ must not be cached, or a browser will keep booting the previous version after an upgrade.

Install the agents

Agents are installed from the app, not from this checkout. In the web UI, open a project, add a server, and follow the wizard: it produces the agent archive and a one-time registration token.

On the target machine, extract the archive and run the installer that ships inside it:

# Linux
sudo sh /opt/aetheus-agent/install-agent-linux.sh
# Windows, from an elevated PowerShell
& 'C:\Program Files\AetheusAgent\install-agent-windows.ps1'

Both installers prompt for the API URL, the registration token and a display name, write the configuration, register the service and health-check it. The agent only makes outbound HTTPS calls, so it needs no inbound firewall rule.

Upgrading

  1. Stop the backend service.

  2. Publish the new version over /opt/aetheus/back and the new frontend over its wwwroot.

  3. Restore wwwroot/appsettings.json with your ApiBaseUrl.

  4. Start the backend. Migrations run at startup; watch the log until /health/ready answers 200.

Back up the database and the four state directories before every upgrade. A schema migration is not reversible by restarting the old binary.