Concepts

Town OS is built around a set of core ideas. Understanding these concepts will help you make sense of how everything fits together — from defining a package to managing a running service.

Packages

A package is a self-contained YAML definition of a service, pulled from a git repository. Each package specifies its networking port mappings, storage volumes, environment variables, and interactive questions — everything needed to run the service. Packages can run as containers (the default), QEMU-based virtual machines, or Windows applications via Valve's Proton compatibility layer. File templates (Go text/template files) can be rendered into volumes at install time for dynamic configuration. Packages declare supplies tags (like http, database, cache) to describe their capabilities. The default repository ships with curated packages covering git hosting, video conferencing, media streaming, team messaging, and databases — with more being added regularly.

Questions

When you install a package, Town OS may present interactive prompts called questions. Your responses fill @variable@ template placeholders throughout the package definition — setting hostnames, ports, credentials, and other options. Each question has a typed validator (hostname, port, bytes, volume, archive, duration, secret, boolean, oauth, or free-form text) and an optional default value, so configuration errors are caught before the service ever starts. The type also picks the control you are shown — a boolean is a checkbox, a secret is a masked field, and an oauth question is a Connect button that signs you in to the vendor and keeps the token it hands back. Several types auto-generate values when left empty: ports are assigned randomly in the 10000–60000 range, hostnames are generated as package-name-4hex, and secrets produce a 64-character hex string. A question marked optional may simply be left blank — an SMTP relay you do not have is left unset rather than filled in with a guess.

Services

Once a package is installed, it becomes a service — a running container managed by a systemd unit. Town OS gives you start, stop, and restart control, live log streaming via Server-Sent Events, cursor-based journal pagination, and the ability to enable or disable services. Services are isolated from each other and from the host system.

Networking

Town OS includes rolodex, a DNS server that manages authoritative zones for your packages and forwards upstream queries. Each package declares its own port mappings — external ports exposed to the host and internal ports available only between containers. Port values support @variable@ templates so users can choose ports at install time. Packages that declare dependencies share a network, allowing containers in the same dependency tree to communicate directly. Parent packages can reference dependencies using @dep_KEY_host@ and @dep_KEY_port_N@ template variables in their environment, or via runtime environment variables (TOWNOS_DEP_{KEY}_HOST and TOWNOS_DEP_{KEY}_PORT_{port}). UPnP forwarding is handled automatically.

Networks

A network is a named WireGuard overlay paired with a DNS TLD. Packages install into a network, peers join it, and the TLD decides who can resolve what. The home network always exists, cannot be removed, and is DNS-only — it has no tunnel, and peer enrollment on it is refused, because every account already belongs to it and membership alone should not be a way onto a tunnel. Other networks get a WireGuard interface and a subnet derived from the box's own identity, so a device that joins two Town OS boxes never sees a collision. Disabling a network takes down only the transport: remote access stops, while local DNS and the containers keep running.

Ingress

One shared front door. A single Caddy instance holds :443 and :80 for the whole box and selects which service you reach purely by SNI and Host — there are no per-service listeners and no bind directives, so a LAN client and an overlay peer hit the same socket, get the same certificate, and are proxied to the same container. A package's name is one string used four ways at once: the A record, the certificate's SAN, the TLSA owner, and the ingress vhost.

TLS and the local CA

Town OS runs its own certificate authority and issues leaves for the names your packages claim, so services are reachable over HTTPS without a public certificate or a browser warning. The CA certificate is downloadable from /tls/ca.crt — trusting it once is what makes every local name work. Certificates are renewed in the background rather than at boot, and a TLD change reissues the names that depend on it.

Object Storage

Town OS ships object storage through gfeh. A partition is one btrfs subvolume with its own daemon and its own set of users, and there is exactly one per network — so a user, a permission, or a published link in one network means nothing in another. Each partition serves four views: S3, plain HTTP, a drive-style browser, and IPFS. Users are principals arranged in a tree; access is a grant, always clamped to the ceiling of the principal it is given to; and a published link is an exposure that can be withdrawn later. No partition publishes a host port — the ingress reaches each one by container name.

Storage

All data is stored on btrfs subvolumes with per-package isolation. Each volume has a mountpoint inside the container, a configurable quota (e.g. 512mb, 2gb), and optional uid/gid ownership. Volumes can be pre-populated from container images using the archives feature, or seeded by cloning a git repository into an empty volume at install time. Users can also create their own standalone volumes. VM disk images are cached in a dedicated subvolume so subsequent installs reuse them. Btrfs snapshots are supported for point-in-time backups. Data persists across package reinstalls and upgrades — your files are never lost when you update a service.

Repositories

Packages are organized into repositories — git repos containing a packages/ directory with versioned YAML definitions. Every Town OS installation includes the default repository, but anyone can create and share custom repositories. Repositories are ordered — later entries override earlier ones when package names collide. A featured.json file can highlight selected packages in the UI.

Templates & Notes

The @variable@ template system connects user responses from questions to environment variables, port mappings, volume quotas, and more. Built-in variables like @LOCAL_EXTERNAL_HOST@ and @LOCAL_INTERNAL_HOST@ are always available. After installation, notes display key metadata like connection URLs, credentials, or contact information — with optional type validation for url, phone, and email.

Pages

Town OS can host static websites. Each page has three possible source types: upload a tar archive, extract files from a container image, or clone a git repository. Every page gets its own domain and is served through Caddy. Archive pages can be updated by re-uploading; git and container image pages can be rebuilt on demand.

Monitoring

A built-in observability stack runs out of the box with no configuration required. Prometheus collects metrics and Node Exporter reports host statistics (CPU, memory, disk, network). Two monitoring backends are available: a lightweight built-in UI (default) or Grafana with auto-provisioned dashboards. The entire stack runs as system services and restarts automatically on failure.

Internationalization

All user-facing strings are routed through a message catalog keyed by BCP 47 locale codes. 21 common languages are presented in their native scripts, with 87+ country-specific codes available. Only English (en-US) is fully translated today — the infrastructure is ready for community translations.

Accounts & Sessions

Town OS supports administrator and normal user accounts. Passwords require a minimum of 8 characters. Authentication uses JWT tokens with a 7-day inactivity expiration. Sessions are ephemeral — signing keys are regenerated on every reboot, which clears all active sessions automatically.

Audit Logging

Every administrative action is recorded with the account name, action, request path, detail, success flag, and timestamp. Read-only endpoints are excluded. The audit log supports pagination, filtering by account, and full-text search.

Settings

System-wide configuration is managed through key-value settings in the UI. Configurable values include the default volume quota (50 GB), max archive upload size (1 GB), archive unpack timeout (600s), locale, Proton runner image, and the DNS top-level domain.

Package Upgrades

Town OS automatically detects when newer package versions are available in your configured repositories. A badge on the dashboard shows the number of pending upgrades. You can dismiss versions you do not want — dismissals are tracked by a SHA256 hash so they reappear only when the upgrade set changes.

System Services

Infrastructure containers — monitoring, DNS, and the web UI — are managed separately from user-installed packages. They use a distinct systemd prefix (town-os-system--), always restart on failure, and cannot be disabled by users.