Documentation
Deploy, configure and scale on DeployCloud
Everything you need to take an app from a Git repository to a live, health-checked HTTPS URL on infrastructure you own.
On this page
Introduction
DeployCloud is a managed platform-as-a-service — your own managed cloud, fully hosted, with nothing to provision or maintain. You point it at a Git repository and it clones the code, builds an image (from your Dockerfile, or automatically when there isn’t one), and releases it behind a managed reverse proxy.
A new release only takes traffic once it passes a health check, so every deploy is zero-downtime and a broken build can never take your site down. Each app is served on its own subdomain with automatic HTTPS — and DeployCloud runs, scales and patches the underlying infrastructure so you never touch a server.
Getting started
Create an app. In the dashboard choose New App, give it a name and paste the URL of the Git repository you want to deploy, then pick the branch to track (defaults to main). That’s the whole setup — there’s nothing to install in your repo.
Deploy it. Trigger the first build from the dashboard’s Deploy button, from the CLI, or by POSTing to the app’s deploy hook — handy from CI:
curl -X POST https://deploycloud.example.com/api/hooks/deploy/<deploy-token>DeployCloud clones the branch, builds the image, runs any release step, and rolls the new version in behind the proxy once it’s healthy.
It goes live. Your app is served at <your-app>.<your-domain> with a Let’s Encrypt certificate issued automatically — for example myapp.deploycloud.example.com. Custom domains become active after their DNS TXT ownership challenge verifies; then deploy once to publish the route.
How builds work
DeployCloud builds your repository one of two ways, and it decides for you based on what’s in the build root:
- Dockerfile present. If your repo has a
Dockerfile, it’s built exactly as written — you have full control over the image. - No Dockerfile. Otherwise the language is auto-detected and an image is produced for you with Nixpacks — no configuration required. Node, Python, Go, Ruby, PHP, Rust, Java and more are supported out of the box.
$PORT environment variable, not a hardcoded one. DeployCloud injects PORT and health-checks exactly that port — binding elsewhere means the health check never passes and the deploy rolls back.Procfile & processes
Most real apps are more than one process: a web server, a background worker, and a migration step that has to run before the new code goes live. A Procfile at your build root declares all three, one process per line, in the same format across every language:
web: node server.js
release: npx prisma migrate deploy
worker: node worker.jsDeployCloud recognises exactly three behaviours, keyed off the process name:
web— the one routed, health-checked process that gets a URL. It’s what your replica count scales, and it must listen on$PORT. A repo with no Procfile still gets a singlewebprocess from the image’sCMD.release— a one-shot command run to completion before traffic shifts, against the freshly built image with real env vars. This is where database migrations go. A non-zero exit aborts the deploy — the previous release keeps serving, so a broken migration can’t take you down. Its output streams into the deploy logs.- Any other name (
worker,clock,scheduler…) — a long-running background worker. It shares the image and env ofwebbut is not routed and not health-checked, and is restarted if it crashes.
The format is identical everywhere; only the commands change:
Python / Django
web: gunicorn app.wsgi
release: python manage.py migrate
worker: celery -A app workerRuby / Rails
web: bundle exec puma
release: bundle exec rake db:migrate
worker: bundle exec sidekiqweb is scheduled across the fleet. For a migration you want to run by hand, use a one-off command: deploycloud run <app> "npx prisma migrate deploy".Environment variables
Set environment variables per app from Settings, or from the CLI and REST API. They’re encrypted at rest with AES-256-GCM and injected into your containers at deploy time — the platform stores only ciphertext, and listing shows keys, never values.
Changes apply on the next deploy. The environment is baked in when containers start, so after adding or changing a variable, redeploy to pick it up. Add-on credentials (below) are injected the same way, so DATABASE_URL and friends are always present.
$ deploycloud env myapp LOG_LEVEL=debug
Set LOG_LEVEL on myapp — redeploy to apply.Add-ons
Provision a backing service in one click and DeployCloud generates its credentials and injects the connection details straight into your app’s environment. Three add-ons are built in:
- Postgres — a dedicated database, exposed as
DATABASE_URL. - Redis — an in-memory cache / queue, exposed as
REDIS_URL. - MinIO — S3-compatible object storage, exposed as
S3_ENDPOINT,S3_ACCESS_KEYandS3_SECRET_KEY.
Each add-on runs on the platform’s private network and is reachable directly from your app. Like any other configuration change, provisioning an add-on takes effect on the next deploy — so redeploy to apply.
Persistent volumes
By default an app’s filesystem is disposable: every deploy starts a fresh container from a fresh image, so anything written to disk at runtime is gone. A persistent volume is a named disk mounted into your containers at a path you choose that survives deploys — reach for one when your app owns files that must outlive a release:
- a SQLite database file,
- user uploads (images, attachments) written to the local filesystem,
- an on-disk cache or index you don’t want to rebuild every release.
Add one under Settings → Persistent volumes. Give it a name (a short lowercase identifier, e.g. data) and an absolute mount path (e.g. /data); core system directories are rejected. Then point your app at it — for a SQLite app, mount data at /data and set DATABASE_URL=file:/data/app.db. The same volume is mounted into both your web and worker containers, and changes apply on the next deploy.
Or from the CLI, so a stateful app can be shipped end to end from a script or an agent:
$ deploycloud volumes add myapp data /data
ok volume data at /data — mounted on the next deploy
$ deploycloud volumes ls myapp
data /dataThe same surface is on the REST API (GET/POST/DELETE /api/v1/apps/<slug>/volumes) and the MCP server (list_volumes, add_volume, remove_volume).
web replica on the host — fine for read-mostly data, but for write-heavy state (like SQLite under concurrent writes) run a single replica or use the Postgres add-on instead. Deleting a volume destroys its data with no undo.Preview deployments
Turn on branch previews in an app’s settings and every branch you push gets its own live environment — built with the same pipeline as production, on its own subdomain:
<app>-pv-<branch>.<your-domain>A preview runs in isolated containers with a single replica, so it can never touch production — your main deployment keeps serving, untouched. Share the URL on the pull request, click around the real app, then merge with confidence. When you delete the branch, its preview is torn down automatically — as is any preview that goes a week without a new push, and every preview of an app when you turn previews off. Push again and it comes right back. Previews are driven by the same GitHub webhook you set up for auto-deploys (below).
Scaling
Scale the web process horizontally by setting its replica count — from the dashboard, deploycloud scale <app> <n>, or the API. Scaling reuses the current release image (no rebuild) and rolls the change out with health checks. Traefik load-balances requests across all healthy replicas, so more replicas means more throughput with no changes to your app.
Need more throughput than a single instance can handle? Your app scales out across DeployCloud’s fleet automatically — replicas are scheduled across many nodes behind a single load-balanced ingress, with no infrastructure for you to add or manage. Turn on autoscaling and replicas track CPU up and down as traffic changes.
Deploy from GitHub
Wire up a GitHub webhook and a push to your tracked branch builds and releases automatically. The webhook is signed (HMAC-SHA256), so the signature is the authentication — no token ever appears in the URL. Ask the platform for the exact values to paste:
$ deploycloud github-webhook myapp
Payload URL: https://deploycloud.example.com/api/hooks/github/42
Content type: application/json
Secret: dc_whs_…
Events: push
Branch: mainThe same values are on the app’s Settings → Deploys page and behind GET /api/v1/apps/<slug>/github-webhook. In your repository, open Settings → Webhooks → Add webhook and fill in:
- Payload URL —
https://<your-platform-host>/api/hooks/github/<appId>, where<appId>is the numeric id in the app’s dashboard URL. - Content type —
application/json(form-encoded payloads sign differently). - Secret — the app’s webhook secret from the command above. It is not the deploy token in the CI hook URL; pasting that one gets you
401 bad signature. - Events — “Just the push event”.
Save, and GitHub sends a ping — a green check with {"ok":"pong"} means the URL and secret are correct. Only pushes to the branch the app tracks enqueue a deploy; pushes to other branches, tags and branch deletions are acknowledged and ignored so the hook stays healthy. Enable branch previews (see above) and those other-branch pushes instead build a preview environment.
CLI
The command-line tool is a single zero-dependency Node script (Node 20+) that talks to the REST API with a bearer token. It covers the daily loop — deploy, watch, tail logs, manage env, scale, and run one-off commands — without leaving your terminal.
deploycloud binary. Until it’s renamed, run deploycloud wherever these docs write deploycloud — e.g. deploycloud deploy myapp --watch.Log in by pointing the CLI at your platform and pasting an API token (created in the dashboard under Tokens, shown once). The token is verified before it’s saved:
$ deploycloud login https://deploycloud.example.com
API token (dashboard → Tokens): ••••••••
ok logged in — 3 apps visibleThen the everyday commands:
# list apps with status, scale and URL
$ deploycloud apps
# deploy and stream build logs; exits on success/failure
$ deploycloud deploy myapp --watch
# tail the runtime logs
$ deploycloud logs myapp --tail 100
# manage environment variables
$ deploycloud env myapp
$ deploycloud env myapp LOG_LEVEL=debug
$ deploycloud env myapp --unset LOG_LEVEL
# scale the web process
$ deploycloud scale myapp 3
# run a one-off command in the live release env
$ deploycloud run myapp npx prisma migrate deploydeploy --watch polls until the deployment reaches running (exit 0) or failed (exit 1), which makes it drop-in for CI. run is synchronous and exits with the wrapped command’s own exit code, so it composes in scripts too.
REST API
Everything the CLI does is a plain REST API you can script directly. Every request is authenticated with a bearer token — create one in the dashboard under Tokens (shown once) and send it in the Authorization header:
Authorization: Bearer <token>Apps are addressed by slug. The full surface:
For example, to trigger a deploy and then set an environment variable:
# queue a deploy of the tracked branch -> { "deploymentId": 42, "queued": "ok" }
curl -X POST https://deploycloud.example.com/api/v1/apps/myapp/deploy \
-H "Authorization: Bearer $DEPLOYCLOUD_TOKEN"
# set an environment variable (encrypted at rest)
curl -X PUT https://deploycloud.example.com/api/v1/apps/myapp/env \
-H "Authorization: Bearer $DEPLOYCLOUD_TOKEN" \
-H "Content-Type: application/json" \
-d '{"key":"LOG_LEVEL","value":"debug"}'MCP server
Let an AI assistant operate DeployCloud for you. The MCP server exposes the platform over the Model Context Protocol, so a client like Claude can list apps, deploy and watch a release, tail logs, set env vars, scale, run one-off commands, and manage add-ons, domains and cron jobs — the same surface as the CLI and REST API. Like the CLI it’s a single zero-dependency Node script that authenticates with a bearer token, so a token is all it needs.
Point your client at it. Create an API token in the dashboard under Tokens (shown once), then add a server entry — for Claude Desktop, in claude_desktop_config.json:
{
"mcpServers": {
"deploycloud": {
"command": "deploycloud-mcp",
"env": {
"DEPLOYCLOUD_URL": "https://deploycloud.example.com",
"DEPLOYCLOUD_TOKEN": "dc_your_token_here"
}
}
}
}Any MCP client works the same way — in Claude Code it’s one command: claude mcp add deploycloud -e DEPLOYCLOUD_URL=… -e DEPLOYCLOUD_TOKEN=… -- deploycloud-mcp. Already logged in with the CLI? The server falls back to your deploycloud login config, so you can drop the env block entirely. Restart the client and it discovers all thirty-four tools, one per API v1 operation:
- Inspect —
list_apps,get_app,list_deployments,get_deployment,get_logs,list_env,get_metrics,list_domains,list_addons,list_volumes,list_crons,list_alerts,get_github_webhook. - Deploy & release —
deploy_app,upload_bundle,rollback_app,restart_app,scale_app,run_command. - Configure —
set_env/unset_env,set_maintenance,set_previews,add_domain/verify_domain/remove_domain,add_addon/remove_addon,add_volume/remove_volume,add_cron/remove_cron. - Lifecycle —
create_appanddelete_app.
Deploys are asynchronous: deploy_app returns a deployment id, and the agent polls get_deployment until it reaches running or failed — the full build log streams back with every poll. run_command is synchronous and returns the command’s exit code and output.
Security
DeployCloud is fully managed, so the infrastructure your app runs on — the hosts, the container runtime, the proxy and the database — is operated, hardened and patched for you. Here is what that means for your apps and data:
- Secrets encrypted at rest. App environment variables and add-on credentials are encrypted with AES-256-GCM. They are decrypted only to inject into your app at runtime, and are never shown in build logs, deploy output or the dashboard once saved.
- Automatic TLS everywhere. Every app subdomain and custom domain gets a Let’s Encrypt certificate, issued and renewed automatically — HTTPS is on by default with no configuration.
- Isolated per app. Each app runs in its own containers with its own environment, add-ons and volumes. Your account’s apps, API tokens and data are scoped to your account.
- Managed backups. Schedule automatic Postgres backups with retention, download any dump, and restore one with a single click. A restore replaces the database — the schema is dropped and rebuilt from the dump, so anything written since it was taken is gone. A backup that fails is reported, never recorded as if it had worked.
© 2026 DeployCloud · Managed hosting · deploy any language
← Back to home