al push) and manual deployment. This page explains what happens under the hood.
For a step-by-step walkthrough, see Deploying to a VPS.
Two Deployment Methods
SSH push deploy (al push) — recommended
Manages your project on a remote server via SSH. No container registry, no vendor lock-in.
Manual deployment
Install Action Llama directly on the server and runal start --expose --headless. Simpler but requires SSH’ing into the server to manage.
What al env prov Does
The provisioning wizard (al env prov <name>) creates a new VPS and configures it as an environment. It supports three modes:
- Connect to existing server — collects SSH details, verifies Docker, sets up firewall
- Provision new Vultr VPS — full automated wizard
- Provision new Hetzner VPS — full automated wizard
Provisioning flow (Vultr/Hetzner)
- API key — prompts for the provider API key (saved to credentials if missing)
- Plan selection — searchable list of available server plans
- Region selection — filtered to regions where the plan is available
- OS selection — x64 Linux images (auto-selects Ubuntu 24.04 if 1GB+ RAM)
- SSH key — use existing
vps_sshcredential, pick from provider keys, or generate new - Firewall — creates firewall group (SSH port 22, web ports 80/443 or 3000)
- Instance creation — launches the VPS with a cloud-init script that installs Docker and Node.js
- Readiness check — polls until the VPS is active, SSH-ready, and Docker/Node.js are installed (10-minute timeout)
- Cloudflare HTTPS (optional) — see below
- Environment file — saves all connection details to
~/.action-llama/environments/<name>.toml
Cloudflare HTTPS (optional)
If you choose HTTPS during provisioning:- Prompts for Cloudflare API token (requires
Zone:DNS:EditandZone:SSL and Certificates:Editpermissions) - Lists your Cloudflare zones and collects a subdomain
- Upserts a DNS A record (proxied) pointing to the VPS IP
- Generates a Cloudflare Origin CA certificate (or reuses an existing one)
- Installs nginx as a reverse proxy with TLS termination
- Configures nginx to proxy to the gateway on localhost
- Sets Cloudflare SSL mode to Full (Strict)
- Verifies the health check endpoint through the full chain
What al push Does
A full push (al push -E <name>) runs three phases:
Phase A: Bootstrap and sync
- Bootstrap check — verifies Node.js and Docker are installed on the remote server
- SSH hardening — disables password auth, restricts root login, installs fail2ban
- File sync — rsyncs project files to the remote
basePath - Credential sync — pushes credentials over SSH to
~/.action-llama/credentials/on the server
Phase B: Configure
- Conditional npm install — computes SHA-256 hash of
package.json+package-lock.json, compares with remote hash, only runsnpm installif changed - nginx setup — if Cloudflare HTTPS was configured, installs the origin cert and nginx config
- Write
.env.toml— writes the environment binding with gateway config - Symlink credentials — creates credential symlinks as needed
- Install systemd unit — writes and enables the systemd service
Phase C: Restart and verify
- Restart service —
systemctl restart action-llama - Health check — polls the
/healthendpoint with exponential backoff, tails the systemd journal for diagnostics if it fails
Hot-reload: single agent push
al push <agent> -E <name> pushes only that agent’s files and credentials. The running scheduler detects the change via file watcher and hot-reloads the agent — no full restart needed.
Systemd Service
The systemd unit file runs the scheduler in headless mode:Environment File [server] Fields
| Field | Type | Default | Description |
|---|---|---|---|
host | string | (required) | Server IP or hostname |
user | string | "root" | SSH username |
port | number | 22 | SSH port |
keyPath | string | (ssh-agent) | Path to SSH private key |
basePath | string | "/opt/action-llama" | Remote project directory |
expose | boolean | true | Bind gateway to 0.0.0.0 (all interfaces) |
Teardown
al env deprov <name> tears down an environment:
- Stops all running containers on the server
- Cleans up remote credentials
- Deletes DNS records (if Cloudflare was configured)
- Optionally deletes the VPS instance (if it was provisioned via
al env prov)
Security
- SSH key-only auth — password authentication is disabled during
al pushbootstrap - fail2ban — installed automatically to protect against brute-force SSH attacks
- No passphrase on SSH keys — VPS deployment SSH keys should not have passphrases because agents need unattended access. The
vps_sshcredential is separate from your personal SSH key. - Credential isolation — each agent container receives only the credentials listed in its
SKILL.mdfrontmatter expose = falsefor reverse proxy — when using Caddy or nginx in front of the gateway, setexpose = falseto prevent the gateway port from being directly reachable
Troubleshooting
SSH connection failures
Gateway not accessible externally
- Ensure
expose = truein[server]config (or--exposeflag for manual deployment) - Check firewall: ports 80/443 (if using reverse proxy) or 8080 (direct)
- Verify TLS certificate is valid if using Caddy/nginx
Docker issues on the server
Webhook delivery failures after deploy
- Check reverse proxy configuration
- Verify TLS certificate is valid
- Test webhook URL accessibility from external services
- Check
al env logs productionfor gateway errors
Out of disk space
- Clean up old Docker images:
docker system prune -a - Rotate logs: configure systemd journal limits
- Monitor disk usage:
df -h