Self-hosting Altair
This guide walks through running Altair on your own hardware. By the end you will have the server, web client, and database running on a single machine, ready to connect a mobile client.
Altair is designed to run on modest hardware. A Raspberry Pi 4 with 4GB of RAM is enough for one or two users. A Pi 5 or an 8GB VPS is more comfortable for a household of 3–5.
Hardware requirements
Minimum (1–2 users)
- 4GB RAM (Raspberry Pi 4, or a $5/month VPS)
- 4-core ARM64 or x86_64 CPU
- 32GB of storage, plus external storage for attachments
- Docker and Docker Compose v2
Recommended (3–5 users)
- 8GB RAM (Raspberry Pi 5, a NAS, or a $15/month VPS)
- 64GB+ of storage
The attachment store can live on external storage without any performance penalty — that’s what it’s designed for.
Prerequisites
You’ll need:
- Docker and Docker Compose v2. On Debian/Ubuntu,
sudo apt install docker.io docker-compose-v2and add your user to thedockergroup. - mise — manages the Bun, Rust, and Java toolchains for development. Not strictly required for a pure deployment, but strongly recommended if you plan to build from source.
- sqlx CLI — for running database migrations. Install with
cargo install sqlx-cli --no-default-features --features postgres.
Clone the repository
git clone https://github.com/getaltair/altair.git
cd altair Configure secrets
Altair ships with a .env.example file that documents every environment variable the stack needs. Copy it and fill in your own values:
cp infra/compose/.env.example infra/compose/.env Open infra/compose/.env and set:
POSTGRES_PASSWORD— a strong password for the Postgres user.JWT_PRIVATE_KEY— the signing key for authentication tokens. Generate a PEM RSA key withopenssl genrsa 2048 | base64 -w0.RUSTFS_ACCESS_KEYandRUSTFS_SECRET_KEY— credentials for the RustFS storage container.S3_ACCESS_KEYandS3_SECRET_KEY— credentials the Altair server uses to connect to RustFS. These must match theRUSTFS_*values above.DATABASE_URL— update to match your Postgres credentials.
Keep this file out of git.
.envcontains secrets. The default.gitignorealready excludes it, but double-check before pushing.
Install toolchains (optional, for building from source)
If you plan to build the server locally instead of using the published image:
mise install # Bun, Rust stable, Java 17 (temurin)
cargo install sqlx-cli --no-default-features --features postgres Start infrastructure
cd infra/compose
docker compose up -d This brings up:
- Postgres — the source of truth for all data
- PowerSync — the sync service for client data
- RustFS — an S3-compatible object store for attachments
The Altair server binary is not included in the compose stack. Start it separately as described in the Start the clients section below.
Verify everything is healthy:
docker compose ps Every service should report healthy or running.
Run database migrations
From the repository root, with DATABASE_URL matching the values in infra/compose/.env:
DATABASE_URL=postgres://altair_user:yourpassword@localhost:5432/altair_db
sqlx migrate run --source infra/migrations Migrations are idempotent — running twice is safe and fast. If a migration fails, the database is left in the pre-migration state and the error is printed.
Apply seed data (optional)
Useful for a first run, especially if you want to poke around before committing any real data:
psql $DATABASE_URL -f infra/scripts/seed.sql Skip this in production.
Start the clients
In development mode, you typically run each client in its own terminal.
Server (for local builds; skip if using the Docker image)
cd apps/server
DATABASE_URL=postgres://altair_user:yourpassword@localhost:5432/altair_db cargo run The API listens on port 8000 by default.
Web client
cd apps/web
bun install
bun dev The web client listens on port 5173 and proxies /api to the server on 8000.
Android client
Open apps/android/ in Android Studio and run on an emulator or a connected device. The mobile client connects to your server over the network, so make sure the device can reach the server’s address.
Create the first user
The first account created on a fresh Altair install is automatically granted admin rights. Open the web client at http://localhost:5173, register an account, and you’re in.
After that, new accounts are regular users by default. You can promote other users from the admin interface once you’re logged in.
Plan your admin account before you expose the server to the network. The “first user becomes admin” rule is intentional and documented in ADR-013, but it means that until you’ve created that account, anyone who can reach the signup endpoint can claim admin.
Backups
Altair’s source of truth is Postgres plus the RustFS attachment store. A reliable backup plan covers both:
- Database — a nightly
pg_dumpwritten to a location outside the host. Any standard Postgres backup strategy works; the database is an ordinary Postgres instance. - Attachments — back up the RustFS data directory on whatever schedule matches the risk you’re willing to accept for lost uploads. Attachments are immutable once written, so incremental backups are efficient.
A full restore is a database pg_restore followed by copying the attachment directory back into place. The server and clients do not keep authoritative state anywhere else.
Troubleshooting
The server refuses to start
Check that Postgres is reachable with the DATABASE_URL you provided:
psql $DATABASE_URL -c 'select 1' If that fails, the server will fail the same way. Fix the connection first.
Migrations fail with “relation already exists”
You’re running migrations against a database that already has tables. If that’s intentional (e.g., you restored from a backup), skip the migration step. If the database is supposed to be fresh, drop it and recreate it before trying again.
Web client says “network error”
The web client proxies /api to the server on port 8000. If the server isn’t running, or is running on a different port, the proxy request fails. Check docker compose ps and the server logs.
Android client can’t reach the server
The emulator uses 10.0.2.2 to reach the host machine’s localhost. A physical device needs the host’s LAN IP address. In both cases, make sure no firewall is blocking the server’s port.
Next steps
Altair is running. Good.
- Read the user guides to learn how the three domains work day-to-day.
- Read the contributing guide if you plan to modify Altair.
- Watch the GitHub repository for updates.