Quickstart — your first deploy
Five minutes from "I have an installed Paas" to "my app is live at a URL." This walks through the dashboard + CLI hybrid; everything done here can also be done purely via the REST API.
0. Prerequisites
- Paas is installed and you can sign in to the dashboard.
- Your local SSH public key is registered (Account → SSH keys).
- You have a small app with a
Dockerfilethat listens on a port via$PORT(default 8080).
A minimal sample app:
# Dockerfile
FROM node:22-alpine
WORKDIR /app
COPY . .
RUN echo 'console.log("hello")' > index.js && \
cat > server.js <<'EOF'
const http = require('http');
http.createServer((req, res) => {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end(`hello from ${process.env.PAAS_RELEASE}\n`);
}).listen(process.env.PORT || 8080);
EOF
CMD ["node", "server.js"]
git init
git add Dockerfile
git commit -m "first commit"
1. Create an organization
Dashboard → Orgs → fill in slug acme and display name Acme.
2. Create a project
acme → projects → fill in slug storefront. A production
environment (deploys from the main branch) is auto-created. See
Projects & environments for adding staging /
preview / etc.
3. Create an app
acme → storefront → Create app. Slug web, port 8080. The page
returns the clone URL:
git@git.example.com:acme/storefront/web.git
(Substitute your PAAS_GIT_PUBLIC_HOST and the SSH port if you changed
PAAS_GIT_SSH_PORT from 2222.)
4. Push
git remote add paas ssh://git@git.example.com:2222/acme/storefront/web.git
git push paas main
The push prints something like:
[paas] sending push: branch=main sha=a1b2c3d
[paas] queued: env=production deployment=1f8a3b21-…
If you push a branch that doesn't match any environment's BranchPattern,
you'll instead see [paas] skipped: no environment matches branch '…' —
that's normal. Add a matching environment if you want that branch to deploy.
5. Watch it deploy
Dashboard → acme → storefront → web → click the production env
tab. You'll see the deployment go from Queued → Building → Built →
Releasing → Live. The Live logs panel streams as soon as a healthy
container is running.
6. Visit it
The auto-assigned URL is http://acme.storefront-web-production.apps.example.com.
The first request after a deploy may show a brief 502 while nginx finishes its reload —
the Orchestrator only swaps the upstream after the new container is healthy.
What happens under the hood
git push ──▶ git-server hook ──▶ POST /internal/git/post-receive
│
▼
Deployment(Queued)
│
▼ (Builder polls)
git clone + docker build + docker push
│
▼
Deployment(Built) → Release(N)
│
▼ (Orchestrator reconciles)
start container; HTTP probe on / ; mark Healthy
│
▼ (ProxyController reacts)
rewrite /etc/nginx/conf.d/web-acme.apps.example.com.conf
nginx -t && nginx -s reload
│
▼
https://web-acme.apps.example.com → ✨
What's next
- Custom domain + TLS — point your own DNS at the app.
- Managed Postgres — provision a database, get a
DATABASE_URL. - Scaling — bump replicas, set CPU/memory caps.
- Deploying apps — env vars, build context, common gotchas.