# dotnews-paas panel A very small self-hosted deployment dashboard ("basic Vercel") for the dotnews PaaS. Node 22 + Fastify 5 + EJS + better-sqlite3, no client framework. Runs on `127.0.0.1:3900` as user `deploy` under PM2, behind Caddy (TLS). The panel never touches Caddy/Varnish/PM2/releases itself — all server state is written by the `paas` CLI, which the panel shells out to. The shared SQLite DB (`sql/schema.sql`, applied idempotently on every start) holds projects and deployment history; `paas deploy` updates the deployment row itself when the panel passes `DEPLOY_ID`/`PAAS_SOURCE`/`PAAS_COMMIT` in the environment. ## Features - Password login (single admin, scrypt hash, signed session cookie, login rate limit) - Dashboard with per-project latest deployment, PM2 state, domains, and a live "deploying" banner (polls `/api/status` every 3 s) - Project creation (`paas create`), env editor (`shared/.env`), deploy / rollback / restart / remove, runtime logs (`pm2 logs --nostream`) - Push-to-deploy webhooks for GitHub (HMAC), GitLab (token), Gitea (HMAC) and a generic URL-secret fallback (Bitbucket, curl) - Serial in-process deploy queue: clone/fetch → build (`bash -lc`, app env + `CI=true`) → `paas deploy`; full log per deployment with live SSE streaming - Vercel-style project cards: site favicon, primary domain, last commit message, short repo/branch, relative "deployed X ago" time - Homepage snapshot on the project page, refreshed automatically after each successful deploy (headless chromium) ## Environment variables | Variable | Default | Notes | | --------------------- | ----------------------------------- | ----- | | `PANEL_PORT` | `3900` | Listens on 127.0.0.1 only. | | `PAAS_DB` | `/srv/paas/paas.db` | Shared SQLite DB. | | `PAAS_BIN` | `/usr/local/bin/paas` | The paas CLI. | | `BUILD_DIR` | `/srv/paas/builds` | Git checkouts / build workspace. | | `LOG_DIR` | `/srv/paas/logs` | Deployment logs (`deploy--.log`). | | `SESSION_SECRET` | — (required) | e.g. `openssl rand -hex 32`. | | `ADMIN_PASSWORD_HASH` | — (required) | `scrypt::`, see below. | | `DEPLOY_KEY_PUB` | `/home/deploy/.ssh/id_ed25519.pub` | Shown in the UI for private repos. | | `PANEL_BASE_URL` | (empty) | e.g. `https://deploy.younex.de`; used to render webhook URLs. | | `APPS_DIR` | `/srv/apps` | App homes (`/shared/.env`). | | `PAAS_SCHEMA` | `../sql/schema.sql` (repo-relative) | Override if the panel runs outside the repo checkout. | | `SNAPSHOT_DIR` | `/srv/paas/snapshots` | Homepage screenshots (`.png`). | | `CHROMIUM_BIN` | `chromium` | Headless browser for snapshots (see below). | ## Setup ```sh cd /srv/paas/panel npm ci || npm install # generate the admin password hash (prompts with hidden input): node bin/hash-password.js # or: node bin/hash-password.js 'my-password' # fill SESSION_SECRET / ADMIN_PASSWORD_HASH in ecosystem.snippet.cjs, then: pm2 start ecosystem.snippet.cjs pm2 save ``` Caddy site (TLS + reverse proxy): ``` deploy.younex.de { reverse_proxy 127.0.0.1:3900 } ``` ## Webhooks Each project gets `PANEL_BASE_URL/hooks//`. - **GitHub** — content type `application/json`, webhook *Secret* = the project secret (verified via `X-Hub-Signature-256`). - **GitLab** — put the secret into *Secret token* (`X-Gitlab-Token`). - **Gitea** — set the webhook secret (`X-Gitea-Signature` HMAC). - **Generic / Bitbucket** — the secret in the URL is sufficient; keep it private. Only pushes to the project's configured branch deploy; everything else returns `200 {ignored:true}`. Branch deletions are ignored. ## Homepage snapshots The project page shows a thumbnail screenshot of the currently deployed homepage. Requires a chromium binary on the server: ```sh apt install chromium # or set CHROMIUM_BIN to another chromium/chrome binary ``` Snapshots are taken with `chromium --headless=new` against `https:///` (resolved to 127.0.0.1 via `--host-resolver-rules`, so the request hits the local Caddy directly) and stored as `SNAPSHOT_DIR/.png`. They refresh automatically after every successful deploy, and lazily when a project page is opened with a snapshot older than the latest live deployment. Only one chromium runs at a time; failures are logged and never break a deploy. If chromium is missing, everything else works — the project page just shows "snapshot pending". ## Notes - On start the panel marks any non-terminal deployments as `failed` (`step: panel restarted`) — the in-process queue does not survive restarts. - Env edits take effect on the next deploy; the "Restart app" button runs `pm2 restart --update-env` for immediate effect. - Removing a project runs `paas remove`, deletes its DB rows and its build dir. - Deployment logs accumulate in `LOG_DIR`; prune old ones with a cron if needed.