gust

Documentation

gust — user guide

Everything you need to install, configure, and run gust in production. From a blank VPS to a running deployment in under five minutes.

Introduction

gust is an AI-native, self-hosted deployment engine. It runs on a single Linux server and lets you deploy Docker containers with zero-downtime, automatic HTTPS, managed databases, monitoring, and an AI assistant — all controlled from a simple CLI or a REST API.

It is built for two kinds of users:

  • Developers who want Heroku-like ergonomics on their own infrastructure, without paying for a PaaS or learning Kubernetes.
  • AI agents (Claude, GPT, custom automations) that need a safe, persistent API to manage infrastructure on behalf of humans.

Requirements

gust is designed to run on a single Linux server. The minimum recommended specs:

ComponentMinimumRecommended
CPU1 vCPU2 vCPU
RAM1 GB2 GB+
Disk10 GB40 GB SSD
OSUbuntu 22.04+Ubuntu 24.04 LTS
NetworkPorts 80, 443 openStatic IP + DNS

For the CLI, you need Node.js 18+ (npm install path) or a POSIX shell (standalone binary path). Works on macOS, Linux, and WSL.

Install the server

Point your domain's A record at your server, then run:

curl -fsSL https://gust.run/scripts/server.sh | sudo bash

The installer performs these steps:

  1. Installs Docker and Docker Compose if missing
  2. Creates the gust-network Docker network
  3. Generates a bootstrap TOKEN and JWT_SECRET
  4. Writes /opt/gust/.env and /opt/gust/docker-compose.yml
  5. Starts Traefik (ports 80/443) and the gust API (port 2020)

When the installer finishes, it prints your API key:

✓ gust is running
  URL:  https://gust.example.com
  KEY:  gust_a1b2c3d4e5f6789...

Save this key

The bootstrap API key is shown once. If you lose it, SSH to the server and run grep TOKEN /opt/gust/.env.

Install the CLI

Two options — pick whichever fits your workflow.

Option A — npm (Node.js 18+)

npm install -g gust-deploy

Also works with pnpm add -g gust-deploy, yarn global add gust-deploy, and bun add -g gust-deploy.

Option B — Standalone binary

curl -fsSL https://gust.run/scripts/cli.sh | bash

This downloads the latest release for your OS to ~/.gust/bin/gust and adds it to your PATH.

Verify

gust version
# gust v2025.3.24

Log in

With an API key:

gust login gust.example.com --key gust_a1b2c3d4e5f6...

Or with email (OTP login, for team members):

gust login gust.example.com --email you@company.com
# Check your inbox for a 6-digit code.

Credentials are cached in ~/.gust/config.json. Check the connection:

gust status
# ✓ connected to https://gust.example.com as owner

Your first deploy

Let's ship nginx so you can verify everything is wired up end-to-end:

gust deploy nginx:latest --name hello --domain hello.example.com

gust will:

  1. Pull nginx:latest on the server
  2. Create a container on gust-network
  3. Wait for the health check to pass
  4. Route traffic via Traefik
  5. Provision a Let's Encrypt certificate

When it finishes, visit https://hello.example.com in your browser. Check app status any time with gust list.

Deploying apps

The gust deploy command is the workhorse. It accepts a Docker image reference (with or without a tag) and a set of flags.

# Simplest
gust deploy nginx:latest

# Custom name + domain
gust deploy ghcr.io/acme/api:v1.2 --name api --domain api.example.com

# Environment variables
gust deploy myapp --tag v2.0 --env DB_HOST=db.local --env API_KEY=secret

# Preview environment (auto-cleaned after TTL)
gust deploy myapp --preview feature-x --ttl 3d

# Multi-service Compose stack
gust deploy --compose docker-compose.yml --service web --name mystack

Private registries

Log in once, then deploy as usual:

gust registry login ghcr.io --username you --password $GHCR_TOKEN
gust deploy ghcr.io/acme/private:latest

Zero-downtime deploys

Every deploy creates a new container alongside the old one. Traffic only cuts over once the new container passes its health check. If the health check fails, gust automatically rolls back and reports the error.

Databases

gust can provision and manage Postgres, MySQL, Redis, and MongoDB instances. Each database runs in its own container with a persistent volume.

gust db create postgres --name mydb
gust db create redis --name cache
gust db info mydb                    # connection string + status
gust db link mydb myapp              # injects DATABASE_URL
gust db logs mydb
gust db remove mydb --force          # also deletes volume

After linking, restart the app so it picks up the new DATABASE_URL:

gust restart myapp

Domains & routing

gust supports multiple domains per app and path-based routing for putting several services behind one hostname.

# Domain management
gust domain add myapp api.example.com
gust domain set-primary myapp api.example.com
gust domain check api.example.com        # verify DNS
gust domain remove myapp api.example.com

# Path-based routing
gust route add frontend example.com/
gust route add api example.com/api --strip
gust route list api

DNS first

Set up DNS before adding a domain so Let's Encrypt can provision the certificate on the first try. Use gust domain check to verify propagation.

Environment variables

gust env set myapp DATABASE_URL=postgres://... SECRET=abc
gust env list myapp
gust env remove myapp SECRET

Env changes don't take effect until you restart the app: gust restart myapp.

Logs & metrics

gust logs myapp                  # stream logs
gust logs myapp --tail 500
gust metrics myapp               # live CPU / memory / network
gust history myapp               # deployment history

Health watcher

Enable background health monitoring to detect crashes and trigger alerts:

gust watch enable myapp --interval 15s --unhealthy-threshold 3
gust watch status myapp
gust watch disable myapp

Notifications

Route events to Slack, Telegram, or any webhook URL:

# Slack
gust notify add slack --url https://hooks.slack.com/services/... \
  --events deploy,health

# Telegram
gust notify add telegram --token <bot-token> --chat <chat-id> --events all

# Generic webhook
gust notify add webhook --url https://example.com/hook --events deploy

gust notify list
gust notify test <id>
gust notify mute <id> --duration 2h

Events: deploy, health, crash, cert, all.

Security

gust ships with everything you need to lock down production:

# IP whitelist
gust whitelist add admin-panel 10.0.0.0/24

# Rate limiting
gust ratelimit set myapp --rps 100 --burst 200

# Container policies
gust policy set myapp --no-root --memory-limit 512m --cpu-limit 1.0 --read-only

# Security headers (HSTS, frame deny, etc.)
gust middleware add myapp headers --hsts --frame-deny --content-type-nosniff

# Basic auth
gust middleware add myapp basicauth --users "admin:$apr1$..."

# Maintenance mode
gust maintenance on myapp

Certificates & TLS

By default gust provisions certificates through Let's Encrypt. You can upload custom certificates (wildcard or corporate) and tune TLS settings per app.

gust cert status                        # list all certs + expiry
gust cert upload example.com --cert fullchain.pem --key privkey.pem
gust cert remove example.com            # revert to Let's Encrypt

gust tls force myapp                    # force HTTPS
gust tls min-version myapp tls1.3

WebSockets

gust ws enable myapp --timeout 300s
gust ws status myapp
gust ws disable myapp

Enabling WebSockets turns on sticky sessions so clients stay on the same replica for the duration of the connection.

Lifecycle

gust rollback myapp
gust restart myapp                  # apply config changes
gust stop myapp
gust start myapp
gust scale myapp 3
gust remove myapp
gust exec myapp -- node migrate.js

Access management

gust supports two auth methods: email + OTP for humans and API keys for CI/CD and AI agents.

# Email users
gust access add alice@company.com --role admin
gust access list
gust access remove alice@company.com

# API keys
gust access create-key --name ci-deploy --email ci@company.com --role member
gust access list-keys
gust access revoke-key ci-deploy
RolePermissions
ownerFull control. Set at bootstrap. One per server.
adminFull control over apps, users, keys, server settings.
memberDeploy + read. Cannot manage users or server settings.

Webhooks

Wire image pushes straight into production with HMAC-signed webhooks:

gust webhook url myapp
# URL:    https://gust.example.com/webhooks/myapp
# Secret: a9f3c2e1...

Configure the URL + secret in Docker Hub or GitHub Container Registry. Every push triggers a zero-downtime redeploy. Requests are verified with HMAC-SHA256 to prevent spoofing.

Preview environments

Spin up a throwaway deploy off a feature branch, with automatic TTL cleanup:

gust deploy myapp --preview feature-x --ttl 3d
gust list                                # previews appear with a label
gust logs myapp-preview-feature-x
gust remove myapp-preview-feature-x

Operations

gust sync                            # reconcile DB with running containers
gust sync --dry-run
gust server info                     # CPU, memory, Docker stats
gust server prune                    # clean dangling images
gust config export --output backup.json
gust config import backup.json
gust audit-log --app myapp

AI assistant

Every gust server ships with a built-in AI assistant. Run gust ai to drop into an interactive session and manage your server in plain English.

$ gust ai
Gust AI — type a message to manage your server (ctrl+c to exit)

> deploy nginx:latest as my-site and add domain example.com
  [deploy_app]
  [add_domain]
  Done! Your app "my-site" is live at https://example.com

> create a postgres db called userdb and link it to api
  [create_database]
  [link_database]
  Done. DATABASE_URL set. Restart api: gust restart api

The assistant refuses destructive actions (removing apps/databases) and prints the exact CLI command for you to run instead.

Configure a provider in /opt/gust/.env:

AI_PROVIDER=anthropic           # or "openai"
ANTHROPIC_API_KEY=sk-ant-...
# OPENAI_API_KEY=sk-...

External AI agents

Any AI agent that can make HTTP calls can drive gust. Create a dedicated API key, hand it to the agent, and it has the same powers as a human operator.

gust access create-key --name my-agent --email agent@company.com --role admin
# gust_a1b2c3d4e5f6...

Example usage in Python:

import requests

GUST = "https://gust.example.com"
KEY  = "gust_a1b2c3d4e5f6..."
H    = {"Authorization": f"Bearer {KEY}"}

# Deploy
requests.post(f"{GUST}/deploy", headers=H, json={
    "image": "myorg/api:latest",
    "name":  "api",
})

# Create a database
requests.post(f"{GUST}/databases", headers=H, json={
    "name": "mydb",
    "type": "postgres",
})

CI/CD integration

Create a dedicated API key, store it as a secret in your CI system, then call gust deploy on merge:

# .github/workflows/deploy.yml
name: Deploy
on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm install -g gust-deploy
      - run: gust login ${{ secrets.GUST_HOST }} --key ${{ secrets.GUST_KEY }}
      - run: gust deploy ghcr.io/${{ github.repository }}:${{ github.sha }} --name api

REST API

Every CLI command is backed by a REST endpoint. Authenticate with a bearer token header:

Authorization: Bearer <api-key-or-jwt>

Core endpoints

MethodPathDescription
GET/appsList apps
POST/deployDeploy a new app
GET/apps/:nameGet app details
POST/apps/:name/rollbackRollback
POST/apps/:name/scaleScale replicas
PATCH/apps/:name/envSet env vars
GET/apps/:name/logsStream logs (SSE)
DELETE/apps/:nameRemove app
POST/databasesCreate database
POST/databases/:name/linkLink to app
GET/server/infoCPU/mem/Docker stats
POST/aiAI assistant endpoint

See the full API reference for every route (certs, notifications, volumes, policies, webhooks).

Configuration

Server environment (/opt/gust/.env)

VariableRequiredDescription
TOKENYesBootstrap API key for owner login
JWT_SECRETYesSecret for signing JWT tokens
DOMAINYesServer domain (enables auto HTTPS)
EMAILYesLet's Encrypt email
RESEND_API_KEYNoResend API key for email login
SMTP_HOSTNoSMTP host (Resend fallback)
AI_PROVIDERNoanthropic (default) or openai
ANTHROPIC_API_KEYNoAnthropic key for gust ai
OPENAI_API_KEYNoOpenAI key (if AI_PROVIDER=openai)

CLI environment

VariableDescription
GUST_SERVEROverride server URL
GUST_TOKENOverride auth token / API key
NO_COLORDisable colored output

Architecture

gust is intentionally small. Three moving parts plus Docker do all the work:

  • Traefik handles ingress, HTTPS, and routing via Docker labels
  • gust server manages deploys, health checks, state, and the API
  • gust CLI talks to the server over HTTP
  • Docker runs all containers on the same machine
Internet → Traefik (443) → App containers (gust-network)
                         → gust API (2020)
                         → Database containers

State lives in SQLite at /var/lib/gust/state.db. No external dependencies — back it up with gust config export.

Upgrading

gust upgrade           # upgrade the CLI
gust upgrade --server  # upgrade the server
gust upgrade --all     # both

Or, if the CLI was installed via npm:

npm update -g gust-deploy

Troubleshooting

command not found: gust

After an npm install, ensure $(npm config get prefix)/bin is on your PATH. For the standalone install, restart your shell so ~/.gust/bin is picked up.

error: connection refused

Check the server is reachable (curl -I https://your-server). SSH in and run docker logs gust for server-side errors.

Deploy hangs on "Waiting for health check"

Your app isn't responding on its listening port. Either set --port to match the container, add a HEALTHCHECK to your Dockerfile, or check gust logs <app>.

Let's Encrypt fails to issue a certificate

Ensure the domain's A record points at the server, ports 80/443 are open, and DNS has propagated. Use gust domain check <domain> to verify.

AI assistant returns "no provider configured"

Set ANTHROPIC_API_KEY or OPENAI_API_KEY in /opt/gust/.env and restart: docker restart gust.

Lost the bootstrap API key?

SSH to the server and run grep TOKEN /opt/gust/.env.

Need more help?

Open an issue on GitHub or reach out to the community.