/data is a named Docker volume, not a host bind-mount, so the prior scp root@host:/data/downloads/ path was wrong. Document the real host path (/var/lib/docker/volumes/bizgaze_support_data/_data/downloads) plus the docker cp alternative, and note latest.yml is the only overwritten file. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
9.2 KiB
Deploying BizGaze Support
The app runs as a Docker container behind the existing Nginx Proxy Manager,
which terminates TLS and proxies https://remote.bizgaze.com → bizgaze-support:8090
on the shared nginx_proxy_manager_default network. No host ports are published.
Deployment model: the server holds a git clone of this repo. Each deploy is a
git pull + rebuild via deploy.sh. Two files are not in git and
live only on the server — they survive every pull:
| File | Purpose |
|---|---|
.env |
Secrets — TURN credentials, optional SSO_SECRET, BIZGAZE_WEBHOOK_URL. See .env.example. |
server/cert.pem, server/key.pem |
Self-signed cert for the app's optional direct-HTTPS listener (8443). Not needed behind NPM, but harmless. |
Server facts:
- Host:
root@118.95.33.89port61 - App path:
/opt/bizgaze-support - Data: Docker named volume
bizgaze_support_data→/data/data.db(persists across rebuilds) - Backups:
/opt/bizgaze-support.backups/(newest 3.tgzsnapshots, auto-rotated)
Operational guardrails (read before every deploy)
These are correctness/security invariants, not preferences. Breaking one degrades or breaks the app even if the container starts fine.
- Single instance only. Chat, presence, and meeting (WebRTC) signaling use an in-process registry. Do not scale to multiple replicas or place several instances behind a round-robin load balancer — users on different processes can't see each other's messages/calls. One container, one process.
ALLOW_LOCAL_LOGINmust NOT be set in production. It's a dev-only escape hatch that bypasses BizGaze SSO and the local-password lockout. Production logs in via BizGaze only.BIZGAZE_DIRECTORY_TOKENis server-side only — it's used by the server to proxy directory lookups and must never be exposed to the browser/client.- HTML is served
Cache-Control: no-storeby design so new builds land immediately. Do not add an HTTP/CDN cache layer that caches.html. Static JS (icons.js) is cache-busted with a?v=query, currently?v=4. - Node ≥ 22.5 (the image uses
node:24-alpine) — required for the built-innode:sqlitethatdb.jsrelies on.deploy.shrebuilds the image, sonpm install(incl.web-push) happens automatically; no manual install. - No DB migration is required for routine UI/chat releases. The
data.dbvolume persists across rebuilds; schema changes (when present) auto-apply on boot.
Env vars to confirm in .env
.env lives only on the server (never in git) and must contain, beyond the TURN
secrets already documented:
| Group | Vars | Needed for |
|---|---|---|
| Login / SSO | BIZGAZE_LOGIN_URL, BIZGAZE_DIRECTORY_URL, BIZGAZE_DIRECTORY_TOKEN, SSO_SECRET |
BizGaze sign-in + directory search |
| Web Push | VAPID_PUBLIC_KEY, VAPID_PRIVATE_KEY, VAPID_SUBJECT |
Background push for browsers / installed PWA |
| Native push — Android | FCM_SERVICE_ACCOUNT (path to / inline Firebase service-account JSON) |
FCM push to the Android app |
| Native push — iOS | APNS_KEY (path/inline .p8), APNS_KEY_ID, APNS_TEAM_ID, APNS_BUNDLE_ID, APNS_PRODUCTION=1 |
APNs push to the iOS app |
| Calls | TURN_URLS / TURN_SECRET (or TURN_USERNAME+TURN_CREDENTIAL) |
Audio/video across NATs & mobile networks |
If the VAPID keys are missing, push silently no-ops (the app still runs). Push on iOS additionally requires the user to Add to Home Screen (iOS 16.4+) — an end-user step, not ops.
Per-release verification
After deploy, open the app and check the browser console logs the expected build,
e.g. Biz Connect build 2026-06-30-batch14. That confirms the new HTML is being
served (not a stale cache).
One-time bootstrap (server → git clone)
Run once to convert the existing folder into a git checkout without losing the
secrets. Prerequisite: the deployment files (Dockerfile, docker-compose.yml,
deploy.sh, etc.) are committed and pushed to origin/master first.
ssh -p 61 root@118.95.33.89 # or: plink -ssh -P 61 -pw '<pw>' root@118.95.33.89
# 1. Store git credentials so pulls are non-interactive (once per server).
git config --global credential.helper store
printf 'https://devops%%40bizgaze.com:Bizgaze%%40123@code.bizgaze.com\n' > ~/.git-credentials
chmod 600 ~/.git-credentials
# 2. Stash the live secrets.
cd /opt
cp -a bizgaze-support /opt/bizgaze-support.preclone.bak
mkdir -p /tmp/bzsecrets
cp bizgaze-support/.env /tmp/bzsecrets/ 2>/dev/null || true
cp bizgaze-support/server/cert.pem /tmp/bzsecrets/ 2>/dev/null || true
cp bizgaze-support/server/key.pem /tmp/bzsecrets/ 2>/dev/null || true
# 3. Replace the folder with a fresh clone.
rm -rf bizgaze-support
git clone https://code.bizgaze.com/Sravan/BizGaze_Remote.git bizgaze-support
cd bizgaze-support
# 4. Restore the secrets the clone doesn't carry.
cp /tmp/bzsecrets/.env ./.env
cp /tmp/bzsecrets/cert.pem ./server/cert.pem 2>/dev/null || true
cp /tmp/bzsecrets/key.pem ./server/key.pem 2>/dev/null || true
rm -rf /tmp/bzsecrets
# 5. Build & launch.
chmod +x deploy.sh
docker compose up -d --build
docker compose ps
If .env did not exist yet, create it from the template and fill in the TURN secret:
cp .env.example .env && nano .env
Routine deploy
After pushing changes to origin/master:
ssh -p 61 root@118.95.33.89 'cd /opt/bizgaze-support && ./deploy.sh'
deploy.sh snapshots the current tree (keeping 3 backups), git reset --hards to
origin/master, rebuilds, and verifies /api/ice. Flags:
./deploy.sh --no-pull— rebuild the current checkout without pulling./deploy.sh --rollback— restore the newest backup snapshot and rebuild
Desktop app releases (make the installer live + auto-update)
Web/UI changes reach the desktop app instantly (it loads the live site). Only a change to the
native shell (desktop/) needs a new installer. Publishing one both powers the site's
"Download for Windows" button and pushes an auto-update to already-installed apps.
The installer feed is served from DOWNLOADS_DIR, which docker-compose now points at
/data/downloads (the persistent volume) so uploads survive deploy.sh rebuilds. First time
only, redeploy once after pulling so the container picks up DOWNLOADS_DIR, then create the dir:
ssh -p 61 root@118.95.33.89 'docker exec bizgaze-support mkdir -p /data/downloads'
Each desktop release:
- Build on a Windows machine (needs
desktop/build/icon.ico; bumpdesktop/package.jsonversionfirst):Output incd desktop && npm install && npm run distdesktop/dist/:Biz Connect Setup <ver>.exe,….exe.blockmap,latest.yml. - Upload those three files into the container's
/data/downloads(all three are required —latest.ymlis the update manifest,.blockmapenables differential updates)./datais a named Docker volume (bizgaze_support_data), not a host bind-mount, so its real host path is/var/lib/docker/volumes/bizgaze_support_data/_data. scp straight into it — one step, no restart needed (the server serves the folder live):Alternatively, scp to# from the repo's desktop\dist folder on the Windows build machine scp -P 61 "Biz Connect Setup <ver>.exe" "Biz Connect Setup <ver>.exe.blockmap" latest.yml ` root@118.95.33.89:/var/lib/docker/volumes/bizgaze_support_data/_data/downloads//tmpon the server anddocker cpin (avoids touching the volume path):Keep both versions'docker cp "/tmp/Biz Connect Setup <ver>.exe" bizgaze-support:/data/downloads/ docker cp "/tmp/Biz Connect Setup <ver>.exe.blockmap" bizgaze-support:/data/downloads/ docker cp "/tmp/latest.yml" bizgaze-support:/data/downloads/.exe/.blockmapon the server (older blockmaps let installed apps pull deltas); onlylatest.ymlis overwritten — there must be exactly one, pointing at the newest. - Verify:
curl -I https://remote.bizgaze.com/download/windows # 302 → the new .exe curl https://remote.bizgaze.com/downloads/latest.yml # shows version <ver>
Installed apps check the feed on launch and every 6h, download in the background, and update on
next restart. Keep the .exe + .blockmap that latest.yml references on the server; older
versions can be pruned. Note: the installer is not code-signed, so Windows SmartScreen shows
an "unknown publisher" warning — supply an EV/OV code-signing cert to remove it (see
desktop/PACKAGING.md).
Verify
curl https://remote.bizgaze.com/api/ice
Response must list the public STUN entry and a TURN entry at
global.relay.metered.ca. If only STUN appears, .env isn't reaching the
container — check docker exec bizgaze-support env | grep TURN.
Rollback
cd /opt/bizgaze-support && ./deploy.sh --rollback # newest snapshot
# or restore a specific snapshot:
ls -1t /opt/bizgaze-support.backups/*.tgz
tar -xzf /opt/bizgaze-support.backups/<stamp>.tgz -C /opt/bizgaze-support && docker compose up -d --build
The data.db volume is never overwritten by a rebuild, so data is retained
regardless of code version.