We've finally reached our first beta. Please ensure you are using our DNS server.

User Guide

A practical walkthrough of Town OS — from writing a USB drive to reporting bugs. Whether you're a first-time user or a developer building packages, this guide covers everything you need to get started.

Quick Start

Get Town OS running on a spare computer in minutes. All you need is a USB-C drive (4 GB or larger) and a Linux or macOS machine to write it from.

1. Write the USB Drive

Run the installer script on any machine with curl, bzip2, and dd installed. It downloads the latest Town OS image and writes it directly to a USB drive.

curl -sSLO https://town-os.github.io/install.sh && bash install.sh

The script will scan for connected USB devices, show you a list with device names and sizes, and ask you to pick one. After you confirm, it streams the compressed image and writes it to the drive in a single pass. The whole process takes a few minutes depending on your internet connection.

DATA DESTRUCTION WARNING

Town OS will format and use all detected local storage devices (NVMe, SATA, SAS, SD cards). Booting Town OS on a machine will permanently destroy all existing data on every internal drive.

Only boot Town OS on a dedicated machine with no data you want to keep, or use the VM instructions to try it safely first.

2. Boot from USB

Plug the USB drive into the target computer and boot from it. You may need to press a key during startup to reach the boot menu — common keys are F12, F2, Esc, or Del, depending on your hardware.

3. First Boot: Use Sledgehammer

If the target machine has been used before for something else, select the sledgehammer boot option from the boot menu on your first boot. Sledgehammer wipes all detected storage devices and ensures Town OS starts with a completely clean slate. This avoids problems caused by leftover partition tables, filesystems, or RAID metadata from a previous operating system.

After sledgehammer finishes, the machine reboots automatically and Town OS performs a fresh storage setup. See Sledgehammer Boot Option for full details.

4. What Happens on Boot

Town OS loads entirely into RAM from the USB drive, then launches ttyforce, an interactive TUI installer that guides you through setup directly on the machine's console.

  • Network configuration — ttyforce detects available interfaces. If a wired connection with link is present, it advances automatically. Otherwise it presents WiFi network selection with signal strength, security info, and WPA2/WPA3 password entry.
  • Disk provisioning — ttyforce groups detected disks by type and size, then automatically selects the appropriate RAID level: single drive for 1 disk, RAID1 (mirror) for 2, or RAID5 (striped with parity) for 3 or more. All storage uses btrfs.
  • SSH key import — you can enter GitHub usernames to import public SSH keys for secure remote access.

After provisioning completes, the system reboots and ttyforce switches to getty mode — a live status display showing service health, system metrics, and journal output on the console. From here you can log in, reconfigure networking, or trigger a sledgehammer wipe.

5. Create Your Account and Start Using It

From any device on the same network, open a browser and go to http://town-os.local. If that doesn't work, check your router's DHCP client list for a device named "town-os" and use its IP address directly. You will be prompted to create an administrator account. Once logged in, you can install packages, manage storage, and configure services from the dashboard.

6. Point Your Router's DNS at Town OS

Town OS ships with rolodex, a DNS server that resolves package hostnames and forwards everything else upstream. To make every device on your network use it automatically, give the Town OS machine a static IP (or DHCP reservation) and set your router's Primary DNS Server to that address. See Setting Up DNS on Your Router for per-brand instructions and verification steps.

Creating the USB Drive

The Town OS USB image is built from the install repository. The build process produces a bootable image with a squashfs root filesystem and a GPT partition layout.

Prerequisites

You'll need a Linux system with the following tools installed:

  • make — the build is driven entirely by Makefiles
  • arch-install-scripts — for pacstrap bootstrapping
  • squashfs-tools — for creating the compressed root filesystem
  • parted and e2fsprogs, dosfstools — for partitioning and filesystem creation
  • podman — for enabling systemd units inside the chroot
  • An Arch Linux host system (required for pacstrap)
  • A USB drive (4 GB or larger recommended)

Cloning and Building

git clone https://gitea.com/town-os/install.git
cd install
make image

Running make or make image builds the complete USB image. The process downloads the base system, installs Town OS components, compresses everything into a squashfs filesystem, and assembles the final disk image with a GPT partition table.

Partitioning and Squashfs

The resulting image uses a GPT layout with:

  • A BIOS boot partition (1 MiB) for legacy BIOS booting
  • An EFI system partition (64 MiB, FAT32) for UEFI booting
  • A data partition (ext4) containing the squashfs root filesystem and GRUB

At boot time, Town OS mounts the squashfs as a read-only lower layer, with a tmpfs overlay on top. This means the OS runs entirely in RAM — the USB drive itself is only read at boot. All runtime changes happen in memory and are discarded on reboot, giving you a clean slate every time.

Writing the Image

Once the image is built, write it to your USB drive using dd:

# Find your USB device (e.g. /dev/sdb)
lsblk

# Write the image (replace /dev/sdX with your device)
sudo dd if=town-os.img of=/dev/sdX bs=4M status=progress conv=fsync

Double-check the target device — dd will overwrite whatever you point it at without confirmation.

Boot Process
USB Drive
GPT Partition Table
EFI System squashfs Root
boot
Running System
tmpfs overlay read-write
squashfs read-only
RAM
OS runs entirely in memory

Sledgehammer Boot Option

The Town OS USB drive includes a sledgehammer boot option that wipes all detected storage devices and resets the system to a clean state. This is useful when you want to start fresh — for example, after testing, before redeploying to new hardware, or when storage has become corrupted.

What It Does

When you select the sledgehammer option at boot, Town OS will:

  • Detect all local storage devices (NVMe, SATA/SAS, SD cards) — the same detection used during normal boot
  • Wipe the partition tables and filesystems on every detected device
  • Reboot the system, which then performs a fresh storage setup as if it were the first boot

Sledgehammer destroys all data on all detected storage devices. The USB drive itself is not affected — only the internal disks. Make sure you have backups of anything you need before using this option.

How to Use It

  1. Plug the Town OS USB drive into the target machine and boot from it
  2. At the boot menu, select the sledgehammer entry instead of the default boot option
  3. The system will wipe all detected storage and reboot automatically
  4. On the next boot, Town OS will set up storage from scratch using your town-os.yaml configuration

When to Use It

  • Factory reset — return the system to a clean state as if it were freshly deployed
  • Storage backend change — switching from btrfs to ZFS (or vice versa) requires clearing existing storage first
  • Corrupted storage — if the filesystem is damaged beyond repair, sledgehammer gives you a clean starting point
  • Redeployment — repurposing hardware for a different Town OS configuration
Sledgehammer Reset Flow
Boot Menu
Select sledgehammer
sledgehammer
wipe
Clear Storage
All detected disks wiped
NVMe SATA SD
reboot
Fresh Setup
Storage configured from scratch
town-os.yaml

Setting Up DNS on Your Router

Town OS includes rolodex, a DNS server that manages authoritative zones for your packages and forwards upstream queries. To use it as your network's DNS server, you need to tell your router to hand out the Town OS machine's IP address as the DNS server for your network. This way every device on your network automatically uses rolodex for DNS — no per-device configuration needed.

Find Your Town OS IP Address

You'll need the local IP address of your Town OS machine. You can find it by:

  • Logging in to the dashboard at http://town-os.local after first-boot setup and selecting the internal IP shown on the dashboard — this is the address to use as your DNS server
  • Running make vm-ip if you're using a VM
  • Checking your router's DHCP client list for a device named "town-os"
Town OS dashboard showing External IP and Internal IP with copy buttons

For DNS to work reliably, your Town OS machine should have a static IP address or a DHCP reservation on your router. If the IP changes, DNS will break for your whole network.

Assign a Static IP or DHCP Reservation

Most routers let you reserve an IP address for a specific device based on its MAC address. This is usually found under LAN Settings, DHCP, or Address Reservation. Find the Town OS machine in the client list and reserve its current IP.

If your router doesn't support DHCP reservations, you can configure a static IP on the Town OS machine itself by adding it to town-os.yaml.

Change the DNS Server in Your Router

The exact steps vary by router brand, but the general process is the same:

  1. Log in to your router's admin interface (usually 192.168.1.1 or 192.168.0.1)
  2. Find the DHCP Settings, LAN Settings, or DNS Settings section
  3. Change the Primary DNS Server to your Town OS machine's IP address
  4. Optionally set a Secondary DNS Server as a fallback (e.g. 1.1.1.1 or 8.8.8.8) — this will be used if Town OS is unreachable
  5. Save and apply the settings

After saving, devices on your network will pick up the new DNS server the next time they renew their DHCP lease. You can force this by disconnecting and reconnecting to the network, or by rebooting the device.

Common Router Interfaces

Router BrandWhere to Find DNS Settings
ASUSLAN → DHCP Server → DNS Server
TP-LinkDHCP → DHCP Settings → Primary DNS
NetgearInternet → Domain Name Server (DNS) Address
LinksysConnectivity → Local Network → DHCP Server → Static DNS
UniFiSettings → Networks → (your network) → DHCP Name Server
pfSense / OPNsenseServices → DHCP Server → DNS Servers
OpenWrtNetwork → Interfaces → LAN → DHCP Server → Advanced → DHCP-Options: 6,<town-os-ip>

Verify It Works

After your device picks up the new DNS settings, verify that rolodex is handling your DNS queries:

# Check which DNS server your machine is using
nslookup example.com

# Or query Town OS directly
dig @<town-os-ip> example.com

# Query a package domain (if you have packages installed)
dig @<town-os-ip> mypackage.home

If example.com resolves correctly, rolodex is working and handling DNS for your network.

DNS Flow
Device
Phone, laptop, etc.
DNS query
DHCP
Router
Hands out Town OS as DNS
DNS = Town OS IP
forward
Town OS
rolodex DNS server
Authoritative zones Upstream forwarding

Building VMs from USB Images

The install repository includes scripts for launching Town OS in virtual machines, which is useful for testing and development without a physical USB drive.

QEMU

make qemu

Launches a QEMU VM with KVM acceleration, 4 IDE drives for storage testing, and bridge networking. The VM boots from the USB image and behaves identically to a physical installation.

VirtualBox

make virtualbox

Creates a VirtualBox VM with bridged networking and converts the raw disk image to VDI format. Bridged mode lets the VM appear as a regular device on your network.

Auto-Detection

make run

Automatically detects your hypervisor — prefers QEMU if available, falls back to VirtualBox.

Environment Variables

VariableDefaultDescription
IMAGE_SIZE8GSize of the USB image
VM_DISK_SIZE20GSize of each virtual disk
VM_MEMORY4096VM memory in MB
VM_BRIDGEbr0Host bridge interface for networking

Serial Console

# Attach to the VM serial console
make serial

# Or manually via socat
socat -,rawer,escape=0x1d unix-connect:/tmp/town-os-serial.sock

# Detach with Ctrl-]

Finding the VM

# Get the VM's IP address
make vm-ip

# Or connect via mDNS
ssh root@town-os.local
VM Networking
Host Machine
br0 bridge interface
QEMU / VirtualBox
bridge
Town OS VM
Full Town OS stack
eth0
network
Local Network
LAN devices can reach VM
mDNS: town-os.local

RAID Installation

Disk provisioning is handled interactively by ttyforce during the first boot. All storage uses btrfs.

Automatic RAID Selection

ttyforce detects available disks, groups them by transport type (NVMe, SATA, etc.) and similar size, then automatically selects the RAID level based on disk count:

  • 1 disk — single mode (no redundancy)
  • 2 disks — RAID 1 (btrfs mirror)
  • 3+ disks — RAID 5 (btrfs striped with parity)

The default mount point is /town-os. ttyforce creates @etc and @var subvolumes for overlayfs-compatible persistence.

Disk Detection

ttyforce automatically detects available storage devices. It identifies NVMe drives, SATA/SAS drives, and SD cards, while excluding the boot USB device and any removable media. The detection logic ensures that Town OS never touches the drive it booted from.

Overlay Filesystem

Regardless of storage backend, Town OS uses overlay mounts for /var and /etc persistence. The lower layer comes from the squashfs root, while the upper layer lives on the RAID/ZFS storage. This means system configuration and service data survive reboots while the base OS remains immutable.

Storage Architecture
NVMe
Fast SSD
SATA / SAS
HDD or SSD
SD Card
Removable
detection
btrfs single
1 disk
btrfs RAID 1
2 disks (mirror)
btrfs RAID 5
3+ disks (parity)
Subvolumes
Per-package storage
pkg-a pkg-b
Overlay Mounts
Persistent system dirs
/var /etc

Using the User Interface

Town OS provides a clean web-based dashboard for managing your server. After booting, open a browser and navigate to your Town OS machine's IP address or http://town-os.local.

First Boot: Creating Your Account

On first boot, you'll be prompted to create an administrator account. Choose a username and password — this account has full control over the system.

Create account screen

Dashboard

The dashboard shows an overview of your system — installed packages displayed as service cards with status indicators, quick actions, and system health at a glance.

Dashboard overview

Browsing and Installing Packages

The Packages view lets you search available packages, view details, and install them with guided prompts. Each package's questions are presented as a form — fill in hostnames, ports, and other configuration, then click install.

Package browser
Package installation prompts
Installation details

Managing Services

Installed services can be started, stopped, and restarted from the Services view. Status indicators show whether each service is running, stopped, or in an error state.

Service management

Viewing Logs

The Logs view provides live journal output with filtering and grep capabilities. You can filter by service, priority level, and search for specific text.

Log viewer

Storage Management

View and manage btrfs subvolumes, configure per-package quotas, and monitor disk usage across your storage pool.

Storage management

Monitoring

Town OS includes built-in monitoring with Prometheus and Node Exporter for tracking system metrics, service health, and resource usage over time. A lightweight built-in dashboard is the default, with an optional Grafana upgrade available.

Monitoring dashboards

Settings and Audit Log

The Settings page lets you configure system-wide options. The Audit Log tracks every administrative action — installs, uninstalls, service state changes, and configuration modifications — so you always know what changed and when.

Settings
Audit log

Building a Package

Town OS packages are YAML files that describe how to run a containerized service. For the full specification, see the Packaging Format reference. This section covers the practical workflow.

Repository Structure

A package repository is a git repository with a packages/ directory. Each package gets a subdirectory containing versioned YAML definitions:

my-packages/
  packages/
    my-app/
      1.0.yaml
      2.0.yaml

Writing a Package Definition

A minimal package needs only an image field. A typical package includes a description, networking, volumes, and user-facing questions:

image: myapp:latest
description: My custom application
supplies: ["http"]
network:
  external:
    "@port@": "8080"
volumes:
  data:
    mountpoint: /app/data
    quota: 5gb
questions:
  port:
    query: "What external port should this app use?"
    type: port
    default: "9000"
notes:
  URL:
    value: "http://@LOCAL_EXTERNAL_HOST@:@port@"
    type: url

Template System

Use @variable@ syntax to reference question answers and built-in variables (@LOCAL_EXTERNAL_HOST@, @LOCAL_INTERNAL_HOST@). Templates work in environment variables, port mappings, quotas, and note values.

Testing Locally

Use the dev environment to test your package. Place your repository on disk, add it through the UI or repositories.json, and install your package. The dev environment provides the full Town OS stack for testing.

Adding a Repository

Add your package repository to Town OS through the UI (Packages → Repositories → Add Repository) or by editing repositories.json directly:

[
  ["default", "https://github.com/town-os/default-packages"],
  ["my-packages", "https://github.com/myuser/my-packages"]
]
Package Lifecycle
YAML Definition
image, volumes, questions
1.0.yaml
install
Config Prompts
User answers questions
hostname port
deploy
Running Container
Service active with volumes
@variable@ → value

Things You Can Self-Host

Town OS is built to run anything that ships as a container image. Here are some ideas to get you started — many of these are available in the default package repository, and any container image can be packaged with a simple YAML definition.

Media & Entertainment

  • Plex / Jellyfin — stream your movie and TV library to any device
  • Navidrome — personal music streaming server
  • Calibre-web — manage and read your ebook collection

Code & Collaboration

  • Gitea / Forgejo — lightweight self-hosted Git
  • GitLab — full DevOps platform
  • Nextcloud — files, calendar, contacts, and more
  • Wiki.js / BookStack — documentation and knowledge bases

Communication

  • Jitsi Meet — private video conferencing
  • Matrix / Synapse — federated encrypted chat
  • Mattermost / Rocket.Chat — team messaging

Game Servers

  • Valheim, Minecraft, Terraria, Satisfactory dedicated servers
  • Proton/Steam support via GloriousEggroll containers
  • Any game server that ships as a Linux binary or container

Home Automation

  • Home Assistant — smart home control hub
  • Node-RED — visual automation workflows
  • Mosquitto — MQTT broker for IoT devices

Privacy & Security

  • Pi-hole / AdGuard — network-wide ad blocking
  • WireGuard / OpenVPN — VPN servers for remote access
  • Vaultwarden — self-hosted password manager

Productivity

  • Paperless-ngx — document management and OCR
  • Immich — self-hosted photo and video management
  • Planka / Wekan — kanban boards and project management

Development Environment and Test Suite

The Town OS development environment runs the full stack locally using Podman containers. This is the fastest way to test changes, develop packages, and run the test suite.

Prerequisites

  • Linux — required for btrfs and Podman rootful containers
  • Podman — container runtime (rootful mode, with sudo)
  • Go 1.25+ — for the backend API server
  • Bun — for the frontend build and dev server
  • btrfs-progs — for storage management
  • QEMU — qemu-system-x86_64 and qemu-img for VM package support
  • libsystemd — development headers for systemd integration
  • golangci-lint — for Go linting
  • Python 3 — for build and test scripts

Starting the Dev Environment

git clone https://gitea.com/town-os/town-os.git
cd town-os
make dev

This starts the full development stack with hot-reloading. Once it's ready, open the URL printed in the terminal to access the Town OS dashboard.

Dev Environment Commands

CommandDescription
make devStart the full dev environment
make dev-stopStop all dev containers
make dev-logsTail logs from dev containers
make dev-cleanRemove dev containers and volumes

Running Tests

CommandDescription
make testRun unit tests
make test-integrationRun integration tests (requires privileged Podman)
make test-ui-integrationRun UI integration tests
make test-fullRun all tests (unit + integration + UI)
make auto-testWatch for changes and re-run tests automatically

Integration Tests

Integration tests run inside a privileged Podman container that provides a real btrfs filesystem, systemd, and Podman-in-Podman. This ensures tests exercise the same code paths as a production installation. The test container is ephemeral — it's created fresh for each test run and cleaned up afterward.

Dev Workflow
Editor
Edit code
Go + Bun
save
auto-test
Tests run on save
make auto-test
reload
Browser
Live preview
localhost:5173
↻ iterate — Backend :5309 · Frontend :5173

Reporting Bugs

Found something broken? Good bug reports help fix issues faster. Here's how to gather the information needed and file an effective report.

Gathering Logs with the API

Town OS exposes journal logs through its REST API. You can use Claude Code to connect to the API and generate a summary of recent errors:

# Fetch error-priority journal entries from Town OS
curl -s http://town-os.local:5309/api/systemd/logs/tail?priority=err | jq .

Or use Claude Code to summarize errors interactively:

# Example Claude Code prompt:
"Connect to the Town OS API at http://town-os.local:5309
 and fetch the last 100 error-priority journal entries from
 /api/systemd/logs/tail. Summarize the errors, group them
 by service, and suggest likely causes."

Filing an Issue

File issues on the Town OS Gitea instance at gitea.com/town-os/town-os/issues.

What to Include

  • Journal summary — error log output or a Claude Code summary of recent errors
  • Reproduction steps — what you did to trigger the problem, step by step
  • Town OS version — the build date or commit hash from the boot screen
  • Storage backend — btrfs, btrfs-mdadm, or ZFS, and how many disks
  • Environment — physical hardware, QEMU, or VirtualBox; RAM and disk sizes
Bug Reporting Flow
Detect Issue
Something broke
⚠ error
curl API
Gather Logs
Fetch journal entries
:5309/api/systemd/logs
summarize
Summarize
Group by service
Claude Code
file
File on Gitea
Create issue with details
✓ reported