Vardo

Concepts

Understand how organizations, projects, apps, environments, and deployments work together in Vardo.

Organizations

Organizations are the top-level tenant boundary. Every resource — projects, apps, environment variables, API tokens, backup targets — belongs to an organization. Users can belong to multiple organizations and switch between them from the user menu.

Each org member has a role: owner, admin, or member.

Organizations can have:

  • A base domain for auto-generated app subdomains (e.g. myapp.yourdomain.com).
  • Shared environment variables available to all apps via ${org.VAR_NAME} references.
  • Custom domains registered at the org level.
  • Notification channels (email, webhook, Slack) for deploy and backup alerts.
  • Digest emails summarizing deployment activity on a configurable schedule.
  • Deploy keys — SSH key pairs for authenticating private Git repository clones.

Org settings

Org settings live under /settings with tabs for general info, shared variables, domains, backups, notifications, team members and invitations.

Projects

Projects group related apps together. A "WordPress" project might contain a WordPress app and a MySQL database. A "SaaS" project might include a web frontend, an API server and a Redis cache.

Projects enable:

  • Group deploys — deploy all apps in dependency order. Vardo builds a graph from dependsOn fields and cross-app variable references, then deploys in tiers.
  • Project environments — create a staging or preview environment for the whole project. Every app gets a matching environment automatically.
  • Coordinated metrics and backups — view metrics, logs and backup history across all apps in a project from one place.

Each project has tabs for apps, deployments, variables, logs, metrics, backups and instances (when mesh is enabled).

Projects are optional. Apps can exist without a project.

Apps

Apps are the core deployable unit. Each app represents a Docker service (or a set of services, in the case of Compose) that Vardo manages through its full lifecycle: build, deploy, start, stop, restart and teardown.

Source types

SourceDescription
gitCloned from a Git repository — GitHub App, manual URL, or SSH deploy key
directConfigured directly — image name, compose content, or Dockerfile

Deploy types

Vardo supports six deploy types:

TypeDescription
composeDeploys a docker-compose.yml. Multi-service compose files are decomposed into managed child apps.
dockerfileBuilds from a Dockerfile in the repository.
imagePulls and runs a Docker image directly (e.g. postgres:16).
nixpacksAuto-detects the language and generates a build configuration.
railpackBuilds with Railpacks — faster builds, first-class Rails support.
staticServes static files.

App lifecycle

Apps track their status as one of: active, stopped, error, or deploying.

Each deployment records:

  • Status: queued, running, success, failed, cancelled, or rolled_back
  • Trigger: manual, webhook, api, or rollback
  • Git SHA, duration and full log output

The app detail page defaults to the deployments tab and includes tabs for connect info, variables, networking, logs, volumes, cron, terminal, metrics and backups. The cron, terminal and backups tabs are gated by their respective feature flags.

Real-time updates

App status updates stream via Server-Sent Events (SSE) at /api/v1/organizations/{orgId}/apps/{appId}/events, with a 10-second polling fallback.

More app features

  • Auto-rollback — monitors the container after deploy. If it crashes within a configurable grace period, Vardo swaps back to the previous slot automatically.
  • Cron jobs — scheduled command execution or URL pinging inside containers, with preset schedules (every minute through weekly) and run history.
  • Resource limits — per-app CPU (cores) and memory (MB) constraints passed to Docker.
  • Exposed ports — direct TCP/UDP port exposure with automatic allocation.
  • Connection info — structured metadata showing how to connect to the service (database URLs, credentials), displayed in the Connect tab.
  • Volume management — persistent volumes with configurable disk write alert thresholds.
  • Custom domains — add, edit and delete domains per app, with cert resolver selection and health checks.
  • Transfers — move an app between organizations. Cross-app variable references are frozen to their resolved values at transfer time.

Deploy Keys

Deploy keys are SSH key pairs generated and managed by Vardo for authenticating private Git clones. The private key is encrypted at rest (AES-256-GCM) and never exposed in the UI — only the public key is shown for you to add to your Git provider.

Deploy keys are scoped to an organization and can be assigned to any app in that org.

Environments

Each app has one or more environments. A production environment is created automatically when an app is deployed and serves as the default.

Environment types:

  • production — the live environment. Always exists, can't be deleted.
  • staging — a pre-production environment for testing.
  • preview — ephemeral environments, typically created from pull requests.

Each environment gets its own:

  • Environment variables (overriding production defaults)
  • Git branch
  • Domain
  • Deployment history

When creating an environment, you choose a clone strategy: clone (copy config and env vars), clone_data (also copy volumes), empty (blank slate), or skip (don't create this app's environment in a group clone).

The environment switcher in the app detail header uses colored dots — green for production, yellow for staging, blue for preview.

Project environments

Project environments span all apps in a project — creating a matching environment for every app at once. This is how you get the full stack (database, API, frontend) running as a coordinated staging or preview instance.

When a GitHub pull request is opened against a project with auto-deploy enabled, Vardo automatically creates a preview environment for the whole project, deploys all apps and posts the preview URLs as a PR comment. Closing the PR tears everything down.

Variable Resolution

Vardo resolves ${...} template expressions at deploy time so you can wire services together without hardcoding values.

Expression types

SyntaxDescriptionExample
${VAR}Another variable in the same app${DATABASE_URL}
${project.field}Built-in app field${project.name}, ${project.domain}
${org.field}Built-in org field${org.baseDomain}
${org.VAR}Org-level shared variable${org.SHARED_SECRET}
${appName.VAR}Variable from another app in the same org${postgres.POSTGRES_PASSWORD}
${appName.field}Built-in field from another app${postgres.internalHost}

Built-in app fields

FieldDescription
nameURL-safe app name
displayNameHuman-readable app name
portContainer port
idApp ID
domainPrimary domain
urlFull HTTPS URL
hostSame as domain
internalHostDocker network hostname (same as name)
gitUrlGit repository URL
gitBranchGit branch
imageNameDocker image name

Built-in org fields

FieldDescription
nameOrganization name
idOrganization ID
baseDomainOrganization base domain

Resolution order

Variables are resolved using topological sorting to handle dependency chains correctly. Circular references are detected and produce an error. Cross-app references look up the referenced app's environment variables at resolution time.

Templates

Templates are pre-configured service definitions stored as TOML files. Each template defines defaults for a common service — image name, environment variables, volumes, ports and connection info.

When deploying a new app, templates are organized by category: databases, cache and queues, monitoring, web servers, tools and custom.

Built-in templates include: PostgreSQL, MySQL, MariaDB, MongoDB, Redis, Nginx, Ghost, WordPress, Fumadocs, Strapi, Adminer, MinIO, n8n, Uptime Kuma and Gitea.

Templates use the variable resolution engine for connection info. A PostgreSQL template's connection URL looks like:

postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${project.name}:5432/${POSTGRES_DB}

See Configuration for the full template TOML format.

Notifications

Vardo sends notifications for deploy and backup events through configurable channels scoped to an organization.

Channel types

TypeDescription
emailSend to one or more email addresses
webhookHTTP POST to a URL with optional HMAC secret signing
slackSlack incoming webhook

Each channel subscribes to specific events — deploy success, deploy failure, backup success, backup failure and more. Failed notifications retry with backoff.

Digest emails

Organizations can receive a scheduled digest email summarizing deployment activity, backup status and errors. The schedule (day of week, hour UTC) is configurable per organization.

Backups

Vardo backs up Docker volumes to external storage with per-volume backup strategies — tar for file volumes, pg_dump for PostgreSQL databases.

Backup targets

A target defines where backups are stored:

TypeDescription
s3AWS S3 or any S3-compatible provider
r2Cloudflare R2
b2Backblaze B2
sshRemote server via SSH/SCP
localLocal filesystem (can be restricted via ALLOW_LOCAL_BACKUPS)

Backup jobs

A job defines a schedule (cron expression), a set of apps to back up and a retention policy. Retention follows a Proxmox-style model: keep last N, keep N hourly, daily, weekly, monthly, yearly.

System-level jobs can back up Vardo's own PostgreSQL database.

Backup runs

Each run records: status (pending, running, success, failed, pruned), volume name, size, storage path, SHA-256 checksum and log output.

Backups can be downloaded from the dashboard or via API. Restoring a backup replaces the volume contents and triggers a redeployment.

Blue-green Deployments

Every deployment uses a blue-green strategy for zero-downtime deploys:

  1. Determine slot — Vardo reads the .active-slot file to find the current slot (blue or green). The new deployment targets the opposite slot.
  2. Prepare — The compose file and resolved .env are written to the new slot's directory.
  3. Start new slotdocker compose up starts the new containers with Traefik labels applied.
  4. Health check — Vardo waits for the new containers to pass health checks. If they fail, the new slot is torn down and the deployment is marked failed. Container logs are captured for debugging.
  5. Route traffic — Traefik routes traffic to the healthy new containers on the vardo-network Docker network.
  6. Tear down old slot — The previous slot's containers are stopped and removed.
  7. Record active slot — The .active-slot file is updated.
  8. Domain health checks — HTTP checks verify external reachability on all configured domains.
  9. Volume detection — Persistent volumes are detected from running containers and recorded on the app.

If a deployment fails, the old slot keeps serving traffic. The failed slot is cleaned up automatically.

Group deploys

When deploying all apps in a project, Vardo builds a dependency graph from dependsOn fields and cross-app variable references. Independent apps deploy in parallel within the same tier, and each tier waits for the previous one to finish.

Mesh Networking

Mesh connects multiple Vardo instances over encrypted WireGuard tunnels. With mesh enabled, you can manage apps across multiple servers from a single dashboard.

Mesh operations:

  • Clone — copy an app to another instance
  • Promote — move a production workload to another instance
  • Pull — pull an app's config and volumes from another instance

Instances communicate peer-to-peer. Each peer has a type (persistent or dev) and a status (online, offline, unreachable). Mesh data syncs via heartbeat and sync endpoints.

The mesh feature is controlled by the mesh feature flag. To disable it:

# vardo.yml
features:
  mesh: false

When mesh is enabled, an Instances tab appears in both project detail pages and admin settings.

Transfers

Transfers move an app from one organization to another within the same Vardo instance.

When an app is transferred, cross-app variable references (e.g. ${postgres.POSTGRES_PASSWORD}) that point to apps in the source org are frozen — the expression is replaced with its resolved value at transfer time to prevent broken references.

Transfer flow:

  1. Source org initiates the transfer.
  2. Destination org accepts or rejects.
  3. On acceptance, the app (config, env vars, domains) moves to the destination org.

On this page