My App

Get started

Go from a fresh Linux server to your first Upstand deployment.

Upstand is a self-hosted control plane for deploying applications, Docker Compose stacks, and databases to Docker Swarm. The first installation runs on one manager node; add workers after the control plane is healthy.

Before you start

Prepare these four things:

  1. A fresh Linux VM with at least 2 vCPU, 4 GB RAM, and 30 GB free disk. Ubuntu 22.04+ or Debian 12+ is the supported starting point.
  2. A DNS name for the dashboard and API, such as app.example.com and api.example.com, both pointing at the manager's public IP. This is recommended for production but optional for the first run: when the installer runs on a public IPv4 manager it can use temporary app.<ip>.nip.io and api.<ip>.nip.io origins automatically.
  3. Inbound TCP 80 and 443 open to the internet. For a multi-node cluster, also allow TCP 2377, TCP/UDP 7946, and UDP 4789 between cluster nodes only.
  4. Root or passwordless-sudo SSH access to the manager.

Do not expose PostgreSQL, Redis, or the Upstand API directly. The installer keeps control-plane services private and Caddy exposes HTTPS entry points.

Install

Run this on the manager. Replace the example hosts before pasting it.

curl -fsSL https://raw.githubusercontent.com/mhbdev/upstand/master/install.sh | sudo bash

If you already have domains, export BETTER_AUTH_URL, CORS_ORIGIN, and NEXT_PUBLIC_SERVER_URL before running the command. The installer is non-interactive by default; when origins are omitted it derives temporary HTTPS nip.io origins from the public IPv4 address. To answer origin prompts explicitly, pass --interactive. Replace temporary origins in /etc/upstand/.env and rerun the installer after DNS is ready.

The first run installs Docker when required, initializes Swarm, creates an attachable upstand-network, pulls immutable release images, generates Docker secrets under /etc/upstand/secrets/, and waits for Postgres, Redis, API, dashboard, and docs health checks.

Open https://app.example.com/login. The first person to open a new installation creates its owner account. Store that account securely: later visitors can sign in but cannot create a second bootstrap owner.

Verify

docker stack services upstand
curl -fsS https://api.example.com/health/ready

Every service should report 1/1; the health response must report database, Redis, workers, and Caddy as ready.

Next: self-hosting, remote servers, or deployments.

Local development

The repository has one local topology: docker-compose.local.yml. It provides PostgreSQL, Redis, the hot-reloading API, the dashboard, and the documentation site with bind mounts. Start it with:

bun run docker:local:up
bun run db:push

The production topology is intentionally separate: docker-compose.prod.yml is a Docker Swarm stack consumed by install.sh. There is no third default Compose file.

On this page