본문으로 건너뛰기

2026-07-04 Mac mini deployment work summary

Overview

Today the Mac mini deployment environment was organized around PM2, Caddy, PostgreSQL, and a token-protected TypeScript deploy API.

Primary goals completed:

  • Persisted qrstay.dongholab.com Caddy routing into /etc/caddy/Caddyfile.
  • Installed and configured PostgreSQL for deploy-run storage.
  • Brought up deploy-api under PM2 on 127.0.0.1:3300.
  • Exposed deploy-api through Caddy as https://pm2-deploy.dongholab.com.
  • Connected qrstay to the deploy API flow.
  • Fixed PM2 environment leakage during cross-service reloads.
  • Added automatic deployment status documentation into this repository.

Repositories touched

pm2-multi-service-starter

Repository:

Important commits:

  • 5ca2a1ffeat: add TypeScript deploy API starter
  • fd14379feat: record deploy status to Git repo

Major additions:

  • TypeScript deploy API under services/deploy-api.
  • PostgreSQL-backed deploy_runs storage with JSONL fallback.
  • deploy.config.json runtime config for services.
  • GitHub Actions deploy workflow example.
  • Caddy/deploy architecture documentation.
  • Status repo writer that creates Markdown and JSON deployment records.

Runtime config:

  • Deploy API port: 127.0.0.1:3300
  • Public endpoint: https://pm2-deploy.dongholab.com
  • Status repo path: /Users/dongho/macmini-deploy-status

qr-stay

Repository:

Important commit:

  • 3996f1echore: add PM2 production ecosystem config

Major additions:

  • ecosystem.config.cjs for production PM2 execution.
  • Canonical qrstay runtime env:
    • PORT=3010
    • HOSTNAME=127.0.0.1
    • NODE_ENV=production

macmini-deploy-status

Repository:

Important commits:

  • 68b5295 — initial repository setup.
  • 21670c7 — first automatic qrstay deployment status commit.

Purpose:

  • Store Mac mini deployment status snapshots by date and service.

Directory convention:

releases/YYYY-MM-DD/<service>/

Each deployment creates:

  • latest.md
  • runs/<timestamp>-<run-id>.md
  • runs/<timestamp>-<run-id>.json

Caddy configuration

Static Caddyfile path:

  • /etc/caddy/Caddyfile

Persisted routes:

qrstay.dongholab.com {
reverse_proxy 127.0.0.1:3010
}

pm2-deploy.dongholab.com {
reverse_proxy 127.0.0.1:3300
}

Validation performed:

  • caddy validate --config /etc/caddy/Caddyfile --adapter caddyfile
  • caddy reload --config /etc/caddy/Caddyfile --adapter caddyfile

Backups created during Caddy changes:

  • /etc/caddy/Caddyfile.backup-20260704-165931
  • /etc/caddy/Caddyfile.backup-deploy-api-20260704-172249

PostgreSQL setup

Installed service:

  • postgresql@16

Homebrew service status:

  • postgresql@16 started

Deploy DB:

  • Database: pm2_deploy
  • User: pm2_deploy
  • Table: deploy_runs

Runtime secret/env file:

  • /Users/dongho/.config/pm2-multi-service-starter/deploy-api.env

Contains:

  • DEPLOY_API_PORT
  • DEPLOY_CONFIG_PATH
  • DEPLOY_TOKEN
  • DATABASE_URL
  • DEPLOY_STATUS_REPO_PATH

Secret values are intentionally not recorded in this repository.

PM2 services

Relevant services after setup:

  • deploy-api — online, Node deploy API, listens on 127.0.0.1:3300.
  • qrstay — online, Next.js app, listens on 3010.
  • pm2-webui — online.

PM2 state was saved with:

pm2 save

Deploy API behavior

Endpoint:

POST https://pm2-deploy.dongholab.com/deploy/<service>

Authentication:

  • Authorization: Bearer <DEPLOY_TOKEN>
  • or x-deploy-token: <DEPLOY_TOKEN>

Current configured service:

  • qrstay

Deployment sequence:

  1. git fetch origin main
  2. git checkout main
  3. git pull --ff-only origin main
  4. npm ci
  5. npm run build
  6. pm2 reload /Users/dongho/qr-stay/ecosystem.config.cjs --only qrstay --update-env
  7. curl -fsSIL https://qrstay.dongholab.com/ --retry 10 --retry-all-errors --retry-delay 1

Issues found and fixed

PM2 environment leakage

Issue:

  • deploy-api uses PORT=3300.
  • A plain pm2 reload qrstay --update-env caused qrstay to inherit the deploy API environment.
  • qrstay temporarily started on port 3300, while Caddy expected port 3010, causing 502.

Fix:

  • Changed qrstay reload command to use qrstay's own ecosystem file:
pm2 reload /Users/dongho/qr-stay/ecosystem.config.cjs --only qrstay --update-env

Result:

  • qrstay consistently runs on port 3010.

Transient Caddy 502 immediately after reload

Issue:

  • Healthcheck sometimes hit Caddy immediately after PM2 reload, before the app was ready.
  • This caused transient 502 failures.

Fix:

  • Added curl retries to healthcheck:
curl -fsSIL https://qrstay.dongholab.com/ --retry 10 --retry-all-errors --retry-delay 1

Result:

  • Final qrstay deployments pass healthcheck reliably.

PostgreSQL table ownership

Issue:

  • deploy_runs table was initially owned by the local user.
  • The pm2_deploy DB user could not insert rows.

Fix:

ALTER TABLE deploy_runs OWNER TO pm2_deploy;
GRANT ALL PRIVILEGES ON TABLE deploy_runs TO pm2_deploy;

Result:

  • deploy-api can write deployment records to PostgreSQL.

Deployment run history from DB

Runs recorded today:

ServiceStatusStepsStartedFinishedNotes
smokesuccess42026-07-04 17:25:42 KST2026-07-04 17:25:42 KSTSmoke test for status/DB path
qrstayfailed72026-07-04 17:26:11 KST2026-07-04 17:26:22 KSTqrstay inherited PORT=3300; Caddy expected 3010
qrstayfailed72026-07-04 17:27:24 KST2026-07-04 17:27:35 KSTtransient 502 before retry logic
qrstaysuccess72026-07-04 17:28:11 KST2026-07-04 17:28:23 KSTdeploy path working
qrstaysuccess72026-07-04 17:30:12 KST2026-07-04 17:30:24 KSTverified after qrstay repo commit
qrstaysuccess72026-07-04 17:35:55 KST2026-07-04 17:36:07 KSTverified automatic status repo commit/push

Final verification

Verified endpoints:

https://pm2-deploy.dongholab.com/health
https://pm2-deploy.dongholab.com/services
https://qrstay.dongholab.com/

Final known results:

  • deploy-api health endpoint returned OK.
  • deploy-api service list returned qrstay.
  • qrstay.dongholab.com returned HTTP 200.
  • deploy_runs has qrstay success records.
  • This status repository received an automatic deployment commit.

For each additional service:

  1. Add its PM2 ecosystem.config.cjs in the service repo.
  2. Add a service entry to /Users/dongho/pm2-multi-service-starter/deploy.config.json.
  3. Add a Caddy block pointing the public domain to the service port.
  4. Trigger deploy through pm2-deploy.dongholab.com.
  5. Confirm a new folder appears under releases/YYYY-MM-DD/<service>/ in this repository.