Architecture

This part shows the system context of Fediversity and the containers of one installation of a hosting provider. It also shows the components of each deployment, with the services that each component requests and provides.

System context

flowchart TB
  operator["<b>Operator</b><br/>[Person]<br/>Has a deployment with applications"]
  user["<b>Application user</b><br/>[Person]<br/>Uses an application of an operator"]
  provider["<b>Hosting provider</b><br/>[Person]<br/>Runs the infrastructure and manages the accounts"]
  maintainer["<b>Maintainer</b><br/>[Person]<br/>Changes and releases the code"]

  fediversity["<b>Fediversity</b><br/>[Software system]<br/>Installs, configures and updates applications, manages users, moves deployments between hosting providers"]

  registrar["<b>Domain registrar</b><br/>[External system]<br/>OpenProvider, INWX or Porkbun"]
  dns["<b>DNS service</b><br/>[External system]<br/>Authoritative DNS that is not in the deployment, for example deSEC or PowerDNS"]
  acme["<b>ACME certificate authority</b><br/>[External system]<br/>Issues TLS certificates"]
  relay["<b>Mail relay</b><br/>[External system]<br/>SMTP submission service of a third party"]
  upstream["<b>Upstream sources</b><br/>[External system]<br/>nixpkgs and the other pinned sources"]
  other["<b>Other hosting provider</b><br/>[Software system]<br/>A different installation of Fediversity"]

  operator -->|"configures and deploys, HTTPS"| fediversity
  user -->|"uses the applications, HTTPS"| fediversity
  provider -->|"configures, deploys and monitors"| fediversity
  maintainer -->|"releases code and pins"| fediversity
  fediversity -->|"registers and transfers domains"| registrar
  fediversity -->|"publishes DNS records"| dns
  fediversity -->|"requests certificates"| acme
  fediversity -->|"sends mail"| relay
  fediversity -->|"gets packages and modules"| upstream
  fediversity -->|"exports and imports a deployment"| other

  classDef external stroke-dasharray: 5 5
  class registrar,dns,acme,relay,upstream,other external

Each external system is a selection of the hosting provider, not a fixed part:

  • Registrars: core/effects/tf/registrars.nix has one entry for each registrar, and the steps that each registrar can do.
  • DNS: the dns resource has a provider for a BIND node in the deployment (core/resources/dns/self-hosted.nix) and a provider for a service that the hosting provider already has (core/resources/dns/external.nix). The core/effects/octodns effect publishes the records. Choose where the DNS zones are gives the selection.
  • Certificates: the ssl resource has an ACME provider, an OpenBao PKI provider and a self-signed provider (core/resources/ssl/).
  • Mail: the smtp resource has a provider that runs a mail server in the deployment and a provider for an external relay (core/resources/smtp/).
  • Upstream sources: npins/sources.json pins nixpkgs and each other source. The SBOM page tells how to find the software of a node.

The threat model gives the trust boundaries between these parties, and data protection gives the parties that get personal data.

Containers

The diagram shows the parts of one installation of a hosting provider. The architecture page of the panel has the container and component views of panel, and the site of the API has those of api.

flowchart TB
  browser["<b>Browser of the operator</b><br/>[Person and browser]"]

  subgraph frontend["Front end"]
    panel["<b>panel</b><br/>[Container: Django]<br/>Accounts, ownership of deployments, configuration form"]
    panelDb[("<b>Panel database</b><br/>[Container: PostgreSQL or SQLite]")]
  end

  subgraph apiSide["API"]
    api["<b>api</b><br/>[Container: FastAPI]<br/>Validates, queues builds, runs deployments"]
    apiDb[("<b>API state store</b><br/>[Container: PostgreSQL or SQLite]")]
    centrifugo["<b>Centrifugo</b><br/>[Container]<br/>Sends progress events"]
    jobs["<b>Job runner</b><br/>[Container: subprocess or Windmill]<br/>Runs a build or a deployment"]
  end

  subgraph coreSide["core"]
    programs["<b>Deployment programs</b><br/>[Container: Nix and OpenTofu]<br/>Change a configuration into machines, records and secrets"]
    schema["<b>Schema and catalog</b><br/>[Container: Nix]<br/>JSON Schema of the options, list of applications"]
  end

  subgraph providerSide["Deployment of the hosting provider"]
    services["<b>Shared services</b><br/>[Containers]<br/>See the diagrams below"]
    incus["<b>Incus hypervisor</b><br/>[Container]<br/>Runs the machines of the deployments"]
  end

  subgraph operatorSide["Deployment of an operator"]
    apps["<b>Applications and their services</b><br/>[Containers]<br/>See the diagrams below"]
  end

  browser -->|"HTTPS"| panel
  browser -->|"HTTPS, bearer token"| api
  centrifugo -->|"WebSocket"| browser
  panel --> panelDb
  api -->|"authorization callback, HTTPS"| panel
  api --> apiDb
  api -->|"publishes events"| centrifugo
  api -->|"reads"| schema
  api -->|"starts a job"| jobs
  jobs -->|"runs"| programs
  programs -->|"creates and changes machines"| incus
  programs -->|"reads and writes state, secrets and addresses"| services
  incus -->|"runs"| apps
  apps -->|"use"| services

Notes for the diagram:

  • api runs a deployment program as a nix subprocess, directly or in a Windmill job (api/src/fediversity_api/_runner.py, api/src/fediversity_api/deployment.py).
  • api and panel are also components of the data model (api/nix/component/, panel/nix/component/), thus the deployment programs of core can deploy them the same as each other service.
  • Configuration data flow shows how a configuration becomes a deployment in core.
  • Flake attributes lists the deployment programs.

Components of a deployment of an operator

The build makes the two diagrams and the two tables below from the code. They show the components of the operator group and of the hosting-provider group of core/setups/groups, each with its default settings. A node shows the resources that the component provides (wiring.provides in core/components/wiringProperties.nix). An arrow goes from a component to the component that answers its request, and its label gives the resources. A request goes to a component of the same group. If the group has no such component, the request goes to the component of the hosting-provider group.

Two requests have a name that is different from the name of the backend that answers them: a generateFiles request goes to varsBackend, and a garage request goes to objectStore. A request without an arrow has no service component that provides it. Examples are nixos-module and firewall, which change the machine itself, and ssl, which has three providers. Hosting resources describes each resource.

flowchart LR
  subgraph applications["Applications that the operator selects"]
    applications_mastodon["<b>mastodon<br/>peertube<br/>pixelfed</b>"]
  end
  subgraph own["Service components of the operator group"]
    own_authelia["<b>authelia</b><br/>provides: oidc"]
    own_grafana["<b>grafana</b>"]
    own_lldap["<b>lldap</b><br/>provides: ldap"]
    own_smtp["<b>smtp</b><br/>provides: smtp"]
    own_valkey["<b>valkey</b><br/>provides: redis"]
  end
  subgraph central["Service components of the hosting-provider group"]
    central_garage["<b>garage</b><br/>provides: objectStore"]
    central_openbao["<b>openbao</b><br/>provides: varsBackend, pki"]
    central_postgresql["<b>postgresql</b><br/>provides: postgresql"]
    central_spire["<b>spire</b><br/>provides: spiffe"]
  end
  applications_mastodon -->|"garage"| central_garage
  applications_mastodon -->|"generateFiles"| central_openbao
  applications_mastodon -->|"postgresql"| central_postgresql
  applications_mastodon -->|"spiffe"| central_spire
  applications_mastodon -->|"oidc"| own_authelia
  applications_mastodon -->|"ldap"| own_lldap
  applications_mastodon -->|"smtp"| own_smtp
  applications_mastodon -->|"redis"| own_valkey
  own_authelia -->|"garage"| central_garage
  own_authelia -->|"generateFiles"| central_openbao
  own_authelia -->|"postgresql"| central_postgresql
  own_authelia -->|"spiffe"| central_spire
  own_authelia -->|"redis"| own_valkey
  own_grafana -->|"generateFiles"| central_openbao
  own_grafana -->|"spiffe"| central_spire
  own_grafana -->|"oidc"| own_authelia
  own_lldap -->|"garage"| central_garage
  own_lldap -->|"generateFiles"| central_openbao
  own_lldap -->|"postgresql"| central_postgresql
  own_lldap -->|"spiffe"| central_spire
  own_lldap -->|"oidc"| own_authelia
  own_smtp -->|"spiffe"| central_spire
  own_valkey -->|"spiffe"| central_spire
  own_valkey -->|"oidc"| own_authelia
Component Kind Provides Requests
authelia service oidc garage, postgresql, generateFiles, redis, nixos-module, spiffe, firewall
grafana service -- nixos-module, oidc, spiffe, ssl, generateFiles, firewall
lldap service ldap garage, postgresql, oidc, nixos-module, spiffe, generateFiles
mastodon application -- nixos-module, garage, redis, postgresql, oidc, ldap, smtp, generateFiles, pod-roles, spiffe, ssl, firewall
peertube application -- nixos-module, firewall, generateFiles, garage, redis, postgresql, oidc, ldap, smtp, spiffe, ssl
pixelfed application -- nixos-module, generateFiles, garage, redis, postgresql, oidc, ldap, smtp, spiffe, ssl, firewall
smtp service smtp spiffe
valkey service redis nixos-module, oidc, spiffe, redis

Components of the deployment of the hosting provider

flowchart LR
  subgraph own["Service components of the hosting-provider group"]
    own_authelia["<b>authelia</b><br/>provides: oidc"]
    own_bind["<b>bind</b>"]
    own_garage["<b>garage</b><br/>provides: objectStore"]
    own_incus["<b>incus</b><br/>provides: instances"]
    own_lldap["<b>lldap</b><br/>provides: ldap"]
    own_netbox["<b>netbox</b><br/>provides: netbox"]
    own_openbao["<b>openbao</b><br/>provides: varsBackend, pki"]
    own_otel_collector["<b>otel-collector</b><br/>provides: otel"]
    own_overview["<b>overview</b><br/>provides: uiIndex"]
    own_postgresql["<b>postgresql</b><br/>provides: postgresql"]
    own_smtp["<b>smtp</b><br/>provides: smtp"]
    own_spire["<b>spire</b><br/>provides: spiffe"]
    own_telemetry["<b>telemetry</b><br/>provides: otelBackend"]
    own_terraform_backend["<b>terraform-backend</b><br/>provides: tfState"]
    own_valkey["<b>valkey</b><br/>provides: redis"]
    own_windmill["<b>windmill</b>"]
  end
  own_authelia -->|"garage"| own_garage
  own_authelia -->|"generateFiles"| own_openbao
  own_authelia -->|"postgresql"| own_postgresql
  own_authelia -->|"spiffe"| own_spire
  own_authelia -->|"redis"| own_valkey
  own_bind -->|"garage"| own_garage
  own_bind -->|"generateFiles"| own_openbao
  own_bind -->|"spiffe"| own_spire
  own_garage -->|"oidc"| own_authelia
  own_garage -->|"spiffe"| own_spire
  own_incus -->|"oidc"| own_authelia
  own_incus -->|"generateFiles"| own_openbao
  own_incus -->|"spiffe"| own_spire
  own_lldap -->|"oidc"| own_authelia
  own_lldap -->|"garage"| own_garage
  own_lldap -->|"generateFiles"| own_openbao
  own_lldap -->|"postgresql"| own_postgresql
  own_lldap -->|"spiffe"| own_spire
  own_netbox -->|"oidc"| own_authelia
  own_netbox -->|"garage"| own_garage
  own_netbox -->|"generateFiles"| own_openbao
  own_netbox -->|"otel"| own_otel_collector
  own_netbox -->|"postgresql"| own_postgresql
  own_netbox -->|"smtp"| own_smtp
  own_netbox -->|"spiffe"| own_spire
  own_openbao -->|"oidc"| own_authelia
  own_openbao -->|"garage"| own_garage
  own_openbao -->|"spiffe"| own_spire
  own_otel_collector -->|"generateFiles"| own_openbao
  own_otel_collector -->|"spiffe"| own_spire
  own_overview -->|"spiffe"| own_spire
  own_postgresql -->|"oidc"| own_authelia
  own_postgresql -->|"garage"| own_garage
  own_postgresql -->|"generateFiles"| own_openbao
  own_postgresql -->|"spiffe"| own_spire
  own_smtp -->|"spiffe"| own_spire
  own_telemetry -->|"oidc"| own_authelia
  own_telemetry -->|"garage"| own_garage
  own_telemetry -->|"generateFiles"| own_openbao
  own_telemetry -->|"smtp"| own_smtp
  own_telemetry -->|"spiffe"| own_spire
  own_terraform_backend -->|"garage"| own_garage
  own_terraform_backend -->|"generateFiles"| own_openbao
  own_terraform_backend -->|"spiffe"| own_spire
  own_valkey -->|"oidc"| own_authelia
  own_valkey -->|"spiffe"| own_spire
  own_windmill -->|"oidc"| own_authelia
  own_windmill -->|"garage"| own_garage
  own_windmill -->|"netbox"| own_netbox
  own_windmill -->|"generateFiles"| own_openbao
  own_windmill -->|"otel"| own_otel_collector
  own_windmill -->|"postgresql"| own_postgresql
  own_windmill -->|"smtp"| own_smtp
  own_windmill -->|"spiffe"| own_spire
Component Kind Provides Requests
authelia service oidc garage, postgresql, generateFiles, redis, nixos-module, spiffe, firewall
bind service -- garage, nixos-module, spiffe, generateFiles
garage service objectStore nixos-module, oidc, spiffe, firewall
incus service instances nixos-module, generateFiles, oidc, spiffe, ssl
lldap service ldap garage, postgresql, oidc, nixos-module, spiffe, generateFiles
netbox service netbox nixos-module, garage, postgresql, oidc, smtp, otel, generateFiles, spiffe, ssl
openbao service varsBackend, pki nixos-module, garage, oidc, spiffe, ssl
otel-collector service otel nixos-module, spiffe, generateFiles
overview service uiIndex nixos-module, spiffe, ssl, firewall
postgresql service postgresql nixos-module, oidc, garage, spiffe, generateFiles
smtp service smtp spiffe
spire service spiffe nixos-module
telemetry service otelBackend generateFiles, nixos-module, garage, spiffe, oidc, smtp, ssl
terraform-backend service tfState nixos-module, generateFiles, spiffe, garage, ssl
valkey service redis nixos-module, oidc, spiffe, redis
windmill service -- generateFiles, nixos-module, dns, netbox, otel, spiffe, ssl, garage, postgresql, smtp, oidc

api and panel are not in this table, because their component definitions are outside core.