Deploy code to a Superjolt VM from GitHub Actions.
The action calls Superjolt's HTTP API directly — no SSH key, no agent install on the runner, no container build. It uploads files (single inline or directory via presigned URL) and runs a shell command on the VM, propagating stdout/stderr/exit code back to the workflow log.
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: getsuperjolt/deploy-action@v1
with:
token: ${{ secrets.SUPERJOLT_TOKEN }}
vm: web
upload: ./dist
command: |
cd /root/app && npm ci --omit=dev && pm2 reload all || pm2 start npm -- start- Open the Superjolt dashboard → Settings → API keys → Create.
- Copy the
sj_live_…token (it's only shown once). - In GitHub → repo Settings → Secrets and variables → Actions → New repository secret:
- Name:
SUPERJOLT_TOKEN - Value: paste the token
- Name:
Token creation is dashboard-only by design — a leaked bearer can't mint shadow tokens (see HI-31 in the Superjolt API).
| name | required | default | description |
|---|---|---|---|
token |
✅ | — | sj_live_… API token. Store as a GitHub Secret. |
vm |
✅ | — | VM name or id. Names resolve via /v1/vms/resolve; ambiguity → 404. |
project |
first project | Project name or id. Omit if the tenant has one project. | |
upload |
— | Local path to ship. File → inline base64 (≤16 MiB). Directory → tar + presigned PUT. | |
upload_to |
/root/app |
Absolute remote path. | |
command |
— | Shell command run after upload completes. | |
workdir |
upload_to or /root |
Working directory for command. |
|
api_url |
https://api.superjolt.com |
Override for self-hosted / dev. |
vm_id— the resolvedvm-…id, useful for chaining steps.
Pin to a semver release for stability — and follow GitHub's post-tj-actions guidance by pinning to a commit SHA in high-security orgs.
uses: getsuperjolt/deploy-action@v1.1.0 # immutable semver
# or
uses: getsuperjolt/deploy-action@<full-sha> # most secure
# or
uses: getsuperjolt/deploy-action@v1 # moving major (convenient, not recommended for prod)v1.1.0+ supports long-running deploys via async exec — the action polls Superjolt's API every 2s and streams stdout/stderr to the workflow log as it accumulates. v1.0.x users will see a 524 on commands that take longer than ~100s (the Cloudflare edge timeout) because the old action made a single synchronous curl. If you're on v1.0.x and seeing 524s on npm install or similar, bump to v1.1.0.
v1.1.1 adds an automatic fallback to sync /v1/exec when the platform host hasn't been upgraded to the async-capable machine-agent yet (returns 503/501/404 on /exec/async). On the fallback path the 100s edge cap re-applies — the action prints a ::warning:: so it's obvious which path you're on — but short commands work either way. Also surfaces vm-init's .error field on non-zero exit so failures like spawn ENOENT or Command timed out after 900000ms show up in the workflow log instead of just exit code -1.
Every API call from this action sends User-Agent: superjolt-action/<version> (+https://github.com/getsuperjolt/deploy-action). Superjolt's audit service detects that header and stamps metadata.source = 'github-actions' on every audit row, so the dashboard activity feed renders a "via GitHub Actions" badge.
If you'd rather use appleboy/ssh-action / rsync-deployments / docker compose pull over SSH, register your public key in Settings → API keys → SSH keys, then call the Superjolt MCP enable_ssh tool (or POST /v1/vms/:id/enable-ssh) on the target VM. sshd installs, your key lands in authorized_keys, and the VM exposes a public TCP port at vm-<id>.superjolt.host:<port>. See the SSH docs.