Websites deploy / provision agent (runs on websites VM: /opt/websites-agent)
Endpoints (X-Deploy-Token):
POST /deploy { slug, wait?: true } — git pull + build + pm2 restart
wait=true (API default): sync, returns success/failed
wait=false: fire-and-forget 202 accepted
GET /deploy-status?slug=… — last deploy status JSON for slug
POST /provision { slug, host, gitRepoUrl } — clone + nginx + ecosystem + allowlist (no certbot)
POST /ssl { host, slug? } — certbot for apex + www (nginx must exist)
POST /park { host, canonicalHost } — nginx 301 apex+www → https://canonical
POST /unpark { host } — remove parked nginx site
GET /health
Scripts on the VM (same folder):
patch-nginx-seo.sh — add /sitemap.xml + /robots.txt API proxies to an existing nginx site
patch-nginx-pay.sh — add /meshkee/payments/{zarinpal|mellat}/callback API proxies
patch-nginx-torob.sh — add /torob_api/v3/products API proxy (store-module tenants)
Env (.env): PORT, DEPLOY_TOKEN, ALLOWED_SLUGS
Note: provision.sh intentionally skips certbot. SSL is issued via POST /ssl so
Edit/Add Domain does not hang when www DNS is wrong.
deploy.sh checks out origin/HEAD (falls back to main, then master).
If the site builds with Next output: 'standalone', deploy copies static/public
into .next/standalone, points PM2 at server.js, and removes full node_modules.
Vinext apps (vinext in package.json / vinext start) have no .next production
build — deploy runs vinext start against dist/ instead of next start.
A build that produces neither standalone, .next/BUILD_ID, nor Vinext dist/
is marked failed (avoids nginx 502 from a crash-looping next start).
REQUIRED for all Meshkee Next storefronts: next.config must include
output: "standalone"
Without it, PM2 runs next start + full node_modules (~150–500MB RSS each) and
the shared websites VM OOMs. Target ~80–120MB RSS per site via standalone.
Paste for website-building agents:
"Always set output: 'standalone' in next.config. Deploy expects .next/standalone
and deletes node_modules. Never ship next start / full node_modules runtime."