J justdeploy
Self-hosted · bring your own VPS

Install JustDeploy on your server.

A start-to-finish guide for putting JustDeploy on a fresh Ubuntu box and shipping your first app. One command installs the CLI; justdeploy setup installs and wires up Caddy, Docker and Railpack for you. Everything runs on one machine you own — no accounts, no control plane.

Start installing ↓ or the two-line version
~5 minutes· Ubuntu 22.04 / 24.04· one curl command· auto-installs Caddy · Docker · Railpack

What you're setting up

JustDeploy itself is a zero-dependency Node program. The heavy lifting is done by Caddy (TLS + reverse proxy), Docker, and Railpack (container builds for Next.js and any framework). Here's the whole box:

your domain(s) ──DNS──► your VPS │ ┌──────────────────────────────────────────────────────┐ │ Caddy (root) ── TLS + proxy · admin API :2019 │ │ ├── static apps → /srv/<name>/current/… │ │ ├── proxy apps → 127.0.0.1:<port> (Node) │ │ ├── container apps → Docker (Railpack image) │ │ └── dashboard → 127.0.0.1:4999 (optional UI) │ │ │ │ justdeploy CLI ── the engine: writes state.db, │ │ │ drives Caddy, runs your apps │ │ └── state → /var/lib/justdeploy/state.db │ │ │ │ Docker ── Postgres, plus BuildKit for Railpack │ └──────────────────────────────────────────────────────┘
i

Everything below runs on the server, as root. On a sudo user, prefix each command with sudo. You'll need a VPS with root SSH access, a domain whose DNS you control, and ports 80 and 443 open.

01

Point your DNS at the server

Do this first so Caddy can fetch a TLS certificate the moment an app exists. For each hostname you'll deploy, add an A record to your VPS's public IP — a wildcard *.example.com lets every app get its own subdomain automatically:

RecordTypeValue
*.example.comA<your-server-ip>
panel.example.comA<your-server-ip>
!

On Cloudflare, set these to DNS only (grey cloud), not proxied — Caddy handles TLS itself. A wildcard record means you never touch DNS again per app.

02

Install JustDeploy

One command on a fresh Ubuntu box. It installs Node (the one thing JustDeploy needs to run itself), clones the repo, links the justdeploy CLI, then hands off to justdeploy setup — which installs and wires up everything else. Re-running is safe; each step checks first.

root@vps — one command
curl -fsSL https://raw.githubusercontent.com/codellyson/justdeploy/master/install.sh | bash
i

Piping a script to bash as root? Reasonable to read it first — it's short and on GitHub. Prefer to do it by hand? The manual path is below.

Manual alternative. JustDeploy uses Node's built-in SQLite, so it needs Node ≥ 22.5. Install that, clone, and link — then Step 3 (setup) does Caddy, Docker and Railpack.

manual install
# Node 22 (NodeSource)
apt-get update && apt-get install -y ca-certificates curl gnupg git
curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
apt-get install -y nodejs

# JustDeploy — pure Node stdlib, no npm deps for the engine
git clone https://github.com/codellyson/justdeploy /opt/justdeploy
cd /opt/justdeploy && npm link

State is created on first use at /var/lib/justdeploy/state.db; apps live under /srv/<name>/. Override with JUSTDEPLOY_HOME and JUSTDEPLOY_SRV if needed.

03

Ready the host auto

This is the part JustDeploy does for you. setup detects what's missing and installs Caddy (TLS + reverse proxy, admin API on localhost:2019), Docker, and Railpack + a BuildKit daemon for container builds, then makes sure the Caddy service and admin API are live. The one-command installer above already ran it; run it yourself after a manual install:

provision the host
justdeploy setup                # installs Caddy + Docker + Railpack, starts + verifies
justdeploy setup --no-docker    # skip Docker (no Postgres, no container builds)

It's idempotent — anything already present is skipped, so it's safe to re-run. It runs as root (it installs system packages) and only supports Debian/Ubuntu; on anything else it prints the manual steps instead of guessing. When it finishes you'll see a green checklist:

justdeploy setup — output
 Caddy already installed — skipping.
 enabling + starting the Caddy service…
 installing Railpack (container build tool)…

   Node 22.11.0
   Caddy installed
   Caddy service running
   Caddy admin API (http://localhost:2019)
   Docker
   Railpack (container builds)
   BuildKit daemon

Host ready. Deploy your first app:
  justdeploy add https://github.com/you/site.git
i

Caddy installs as a root systemd service with the admin API enabled by default — exactly what JustDeploy needs (root to bind :80/:443 and manage the DB firewall). JustDeploy owns Caddy's live config through that API and rebuilds it from state.db, so you never touch /etc/caddy/Caddyfile.

04

Deploy your first app

Point JustDeploy at a git repo — that's it. It detects the type from the repo's package.json and infers the domain, so a bare add just works:

deploy
# type detected (Next/Adonis/Vite/CRA/static), domain inferred as .
justdeploy add https://github.com/you/site.git

# …or pin either explicitly
justdeploy add https://github.com/you/api.git --type adonis --domain api.example.com

Static apps (React/Vite/static) are served straight from Caddy; Next.js and the catch-all app type build into a container with Railpack (it detects the package manager and runtime — pnpm, Node version, and so on — automatically). add clones, builds, wires up Caddy (which fetches a Let's Encrypt cert), and starts serving. Manage it:

day-to-day
justdeploy ls               # what's deployed, ports, pids
justdeploy logs app -f      # tail the build/run log
justdeploy deploy app       # redeploy (pull → build → swap)
justdeploy rollback app     # instantly revert to the previous release
justdeploy gc               # reclaim disk: trim old container images

Supported --type values: vite, react, static, adonis, nextjs, app, postgres.

05

Web dashboard optional

JustDeploy ships a control panel and deploys its own dashboard like any other app. One command builds the React UI, installs a systemd service, and adds the TLS route:

install the panel
justdeploy dashboard install --domain panel.example.com

It prints an admin password — save it. The panel runs as the justdeploy-dashboard systemd service on 127.0.0.1:4999, served over HTTPS by Caddy. On first visit, a setup wizard walks you through host readiness, base domain, GitHub, and your first deploy. Reset the password any time with justdeploy dashboard password <new>.

06

Private repos optional

Public repos clone without auth. To deploy private repos, give JustDeploy a GitHub personal access token (classic, repo scope — create one at github.com/settings/tokens):

connect github
justdeploy github <your-token>     # stores it; private repos will now clone
justdeploy github                  # show connection status
justdeploy github --clear          # disconnect

In the dashboard you can paste the same token in the new-project flow to browse and pick private repos directly.

07

Git-push auto-deploy optional

Turn on a signed webhook so pushing to a repo's default branch redeploys the matching app automatically:

enable webhook
justdeploy webhook

It prints the Payload URL and secret to paste into GitHub → repo Settings → Webhooks (content type application/json, "Just the push event"). Rotate the secret with justdeploy webhook --rotate.

i

The webhook is received by the dashboard service, so this needs the dashboard installed (Step 5) to have a public URL.

08

Off-box backups recommended

state.db and each app's data/ dir are the only irreplaceable state on the box — so back them up elsewhere. JustDeploy uploads to any S3-compatible bucket (AWS S3 or Cloudflare R2), no extra dependencies:

backups
justdeploy backup config --endpoint https://<acct>.r2.cloudflarestorage.com \
  --bucket my-backups --access-key <k> --secret-key <s> --region auto

justdeploy backup                    # snapshot + upload (state.db + data + pg_dump)
justdeploy backup --schedule daily   # optional: install a systemd timer
justdeploy restore <file> --yes      # bring it all back
!

The backup archive is chmod 600 — it contains secrets (env vars, admin hash, webhook secret). Keep it somewhere private.

Verify the install

One command reports everything — it installs nothing, just checks:

justdeploy doctor
justdeploy doctor

   Node 22.11.0
   Caddy installed
   Caddy service running
   Caddy admin API (http://localhost:2019)
   Docker
   Railpack (container builds)
   BuildKit daemon

All green? Open your app's domain in a browser — it should load over HTTPS with a valid certificate. Any red line tells you what to fix; re-run justdeploy setup to install what's missing.

i

Firewall (ufw)? Allow OpenSSH, 80/tcp, and 443/tcp. Docker's published ports bypass ufw by design — JustDeploy binds Postgres to 127.0.0.1 only, and enforces a source-IP allowlist in the DOCKER-USER chain when you deliberately make a database public. You don't manage those rules by hand.

!

Small VPS? Container builds of heavy apps can exhaust memory on boxes under ~2 GB RAM. Add a swap file — fallocate -l 4G /swapfile && chmod 600 /swapfile && mkswap /swapfile && swapon /swapfile — and add it to /etc/fstab.

?

Troubleshooting

SymptomCause & fix
cannot reach Caddy adminCaddy isn't running or the admin API is off. systemctl status caddy; make sure no custom Caddyfile disabled the admin endpoint.
Cert error / domain won't resolveDNS A record isn't pointing at the server yet, or is proxied (Cloudflare orange cloud). Set it to DNS-only and wait for propagation.
node:sqlite errors on startNode older than 22.5. Check node --version and reinstall from Step 2.
Container build fails / OOMHeavy build ran out of RAM. Add a swap file (see Verify), or declare the Node version your app needs via .nvmrc / engines.
Private repo fails to cloneNo GitHub token, or it lacks repo scope. Re-run justdeploy github <token>.
Deploy failsThe failure prints a plain-English reason and the fix — read it in justdeploy logs <app> or the dashboard's deploy log.

Uninstall

Reverses setup. By default it removes everything — apps, databases, Caddy (package + config), state, and the checkout — after printing the plan and prompting y/N. Flags only hold things back:

uninstall
justdeploy uninstall                 # full removal (prompts to confirm)
justdeploy uninstall --keep-data     # keep state.db, app files, and db volumes
justdeploy uninstall --keep-caddy    # leave Caddy installed, just drop the routes
justdeploy uninstall --yes           # skip the prompt (scripts / non-interactive)

It always shows exactly what it will do and waits for y before touching anything, so there's no way to nuke the box by fat-fingering one command. Docker is always left in place — it's a shared tool. Piped/non-interactive runs (no terminal) need --yes instead of the prompt.

!

The default takes your databases with it. If there's anything you might want back, run justdeploy backup first — or add --keep-data.

The whole thing, condensed

Zero to deployed,
in two lines.

fresh Ubuntu + DNS pointed
# 1. install everything (Node → CLI → Caddy + Docker + Railpack)
curl -fsSL https://raw.githubusercontent.com/codellyson/justdeploy/master/install.sh | bash

# 2. ship an app
justdeploy add https://github.com/you/site.git