self-hosted deployments

Push code.
poof!
It's live.

A lightweight deployment daemon that goes from git push to a running container, automatically. One command to configure. Zero ops after that.

curl -fsSL https://poof.rac.so/install | sh

Up in minutes.

Poof! is convention-driven: sensible defaults get you from zero to deployed in minutes, with every detail overridable when you need it.

on your server
Install Poof!

One command sets up everything: Caddy, Docker image, config, and starts the server. Only requires Docker.

✓ done with the server. Forever.
from your machine
Install the CLI & connect
Set the server URL, auth token, base domain, and GitHub credentials — all with poof config set.
Register your project
Sets up routing, injects deploy secrets into your repo, and commits the GitHub Actions workflow.
Push your code

Every push to main builds and deploys myapp.mydomain.com automatically.

That's it.

on your server # One command — sets up Caddy, builds image, starts Poof!
curl -fsSL https://poof.rac.so/install | sh -s server
    ✓ Caddy is running
    ✓ Poof! is running
    API token: a1b2c3d4...

from your machine # Install the CLI
curl -fsSL https://poof.rac.so/install | sh -s client

# Connect to your server
poof config set server https://poof.mydomain.com
poof config set token a1b2c3d4...
poof config set domain mydomain.com
poof config set github-user your-gh-user
poof config set github-token ghp_...

# Register your project
poof add myapp
        ✓ Project registered · myapp.mydomain.com
        ✓ Secret POOF_TOKEN set on github
        ✓ Workflow committed to .github/workflows/

# Ship it!
git push
        ✦ https://myapp.mydomain.com is live
No GitHub Actions? No GitHub at all? Using multiple domains?

Use any domains and subdomains you need for your projects. Set aliases and redirects in seconds.

Set up your own CI to build and push Docker images to any registry you want. Deploy by calling Poof's API.

Poof! got you covered, and it allows you to update anything at any time.

# Register with a custom domain and redirect an alias
poof add otherapp --domain my-other-domain.com
poof redirect add www.my-other-domain.com my-other-domain.com

# Build & push with any CI tool
docker build -t myimage:v1 .
docker push myimage:v1

# Trigger deploy via API
curl -X POST https://poof.mydomain.com/otherapp/deploy \
-H "Authorization: Bearer $POOF_TOKEN" \
-d '{"image":"myimage:v1"}'
        ✦ https://my-other-domain.com is live

Common operations.

A quick reference for what Poof! can do. Run poof help or read the full docs.

routing
Custom domain
Set any domain or subdomain per project, or configure a default domain on the server to auto-assign subdomains. Configurable at registration or anytime after.
# default: auto-assigned subdomain
poof add myapp
  ✓ myapp → myapp.mydomain.com

# custom domain (no subdomain)
poof add otherapp --domain another-domain.xyz

# update anytime
poof configure myapp --domain myapp2.mydomain.com
routing
Domain redirects
Redirect any domain to another: www aliases, legacy domains, or migration paths. Caddy handles the 301 and TLS automatically.
poof redirect add www.mydomain.com mydomain.com
poof redirect add old-name.com mydomain.com

poof redirect list
  1 www.mydomain.com → mydomain.com
routing
Multiple services, one repo
Register multiple projects from a single repository. Each folder gets its own project, domain, and CI workflow. Each workflow triggers only on changes to its folder.
poof add api --folder backend --port 3000
poof add web --folder frontend --port 8080

  ✓ api → api.mydomain.com
  ✓ web → web.mydomain.com
containerization
Static sites
Serve static files straight from your repo with Caddy — no container needed. Add --spa for single-page apps, --build if a Dockerfile produces the files.
# plain static site
poof add mysite --static

# SPA with client-side routing
poof add myapp --static --spa

# Angular/React built via Dockerfile → served as SPA
poof add myapp --static --spa --build
containerization
Environment variables
Inject secrets and config into containers. Keys are listed but values are never exposed. Deploy to apply changes.
poof env set myapp DATABASE_URL=postgres://...
poof env set myapp KEY=val1 SECRET=val2

poof env get myapp
  DATABASE_URL,SECRET,KEY
containerization
Persistent volumes
Mount a path into your container. Let Poof! manage the host directory, or point to one you control. Changes apply on next deploy.
# managed (Poof! owns it)
poof volume add myapp /data

# explicit host path
poof volume add myapp /mnt/uploads:/app/uploads
poof deploy myapp
ops
Clone environments
Spin up a test or staging environment by cloning an existing project. The clone deploys from a branch matching the suffix. Optionally copy env vars in one go.
poof clone myapp test
  ✓ cloned "myapp" → "myapp-test" (branch: test)
   domain: myapp-test.mydomain.com

# clone with env vars
poof clone myapp staging --env --all
ops
Rollback
Something broke after a deploy? Poof! keeps a deployment history and can restore the previous image in seconds.
poof rollback myapp
  ✓ rolled back to ghcr.io/org/myapp:prev
  ✦ https://myapp.mydomain.com is live

# or deploy a specific image
poof deploy myapp --image ghcr.io/org/myapp:v2
ops
Declarative config
Instead of running individual commands, you can define all projects in a poof.ini file and reconcile with one command. Great for reproducible infrastructure and staging environments.
# poof.ini
[api]
domain = api.mydomain.com
port = 3000

poof apply --dry-run
poof apply
ops
Logs, status & updates
Inspect running projects, tail logs, and keep both the CLI and the server up to date, all from your machine.
poof status myapp
poof logs myapp -n 50
poof list

poof update local
poof update server