# How it works

> One server you own serves every project, with a folder per project, a generated unit for each app, and root helpers that each do one job.

sitesolide serves every project from one Debian server you own. Each project is a folder on that server, live at `https://<slug>.<zone>`.

```diagram
[Your laptop] sitesolide deploy
-> over SSH, or with a token
[[One server you own]]
  [Caddy] HTTPS and company sign-in
  [Your apps] one account and unit each
  [Helpers] root, one job each
  [Dashboard] shows state, holds no power
```

## One machine, on purpose

There is no staging and no failover. What breaks the server breaks every site at once, and nothing repairs itself. That constraint keeps the system small enough to understand completely, so every change is verified rather than assumed.

## A project is a folder

A project exists because `/srv/sites/<slug>` exists on the server. Caddy's wildcard block serves `<slug>.<zone>` from that folder by name. There is no database of projects, and adding one changes no shared file.

| Kind | Declares in `sitesolide.json` | Gets |
|---|---|---|
| Static site | `publicDir`, no `start` | Files Caddy serves. Nothing runs. |
| App | `start`, or `services` | A systemd unit per service and a Caddy block. 8 to 40 MB of memory. |

`deploy` generates the units and the block from the manifest every time, and validates the new block with every block in service. They live on the server alone. An app can also run [workers and scheduled jobs](background-work.md).

## Helpers with one job each

Changes on the server go through small root-owned helpers. Each one may do one job, and nothing more.

| Helper | Its one job |
|---|---|
| Steward | Judges every change against the access registry, writes secrets and restarts services. |
| Gatekeeper | Changes one site's general access, reloads Caddy, probes the site and rolls back on failure. |
| Installer | Deploys one project for a token, reading its archive as the project's own account. |
| Collector | Reads the server on a timer and leaves a snapshot for the dashboard. |
| Backup run | Stores the hourly snapshots that each project's own account hands it. |

## The dashboard holds no power

The dashboard runs under its own unprivileged account. It cannot open another project's files or reach other projects' services. What it shows comes from the collector's snapshot, and every change it asks for goes to the steward, which judges it. A compromised dashboard leaks only what its pages already showed.

## The server is the source of truth

A deployed project's general access and its secrets are what the server carries, not what the repository says. The CLI reads the server first, and refuses to contradict it. `deploy` never pushes a secret: it checks that each one exists, and points to the dashboard when one is missing.

## Limits

- **No zero-downtime deploys, no code rollback.** See [what a deploy costs](deploy.md#know-what-a-deploy-costs).
- **No failover.** When the server is down, every site is.
- **No automatic reboots.** Security updates install every day, but a new kernel waits for you to [reboot](server.md#reboot-for-kernel-updates).
- **No offsite backups by default.** Snapshots stay on the server's disk until you [configure a bucket](backups.md#copy-snapshots-to-a-bucket).

## Related

- [Security model](security.md): how each app is walled in, and what the design does not protect.
- [Deploy a project](deploy.md): put a folder live, and what each deploy checks.
- [Backups and restore](backups.md): snapshots, restore, and the copy off the server.
- [Your server](server.md): set up and look after the one machine.

Full reference: https://github.com/cthiriet/sitesolide/blob/main/docs/concepts.md
