From 2cd43764e24021852830ca29a211a0c2d88b1d31 Mon Sep 17 00:00:00 2001 From: avinash Date: Wed, 10 Jun 2026 16:08:05 +0530 Subject: [PATCH 1/2] add initial Docker setup with .dockerignore, Dockerfile, docker-compose.yml, and deployment script --- .dockerignore | 8 ++++ .env.example | 19 ++++++++ .gitignore | 4 ++ Dockerfile | 20 +++++++++ deploy.sh | 110 +++++++++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 31 +++++++++++++ 6 files changed, 192 insertions(+) create mode 100644 .dockerignore create mode 100644 .env.example create mode 100644 Dockerfile create mode 100644 deploy.sh create mode 100644 docker-compose.yml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..b46bd8d --- /dev/null +++ b/.dockerignore @@ -0,0 +1,8 @@ +**/node_modules +server/data.db +server/data.db-wal +server/data.db-shm +**/*.log +agent +docs +*.bat diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..dd39fbc --- /dev/null +++ b/.env.example @@ -0,0 +1,19 @@ +# BizGaze Support — server secrets / config. +# Copy this file to `.env` next to docker-compose.yml on the server and fill in +# real values. The real `.env` is gitignored — NEVER commit credentials. +# Compose injects these into the container via `env_file:`. + +# Managed TURN relay (Metered) — makes WebRTC work on mobile/cellular & strict NATs. +# Comma-separated URL list; username + credential from the Metered dashboard. +TURN_URLS=turn:global.relay.metered.ca:80,turn:global.relay.metered.ca:80?transport=tcp,turn:global.relay.metered.ca:443,turns:global.relay.metered.ca:443?transport=tcp +TURN_USERNAME= +TURN_CREDENTIAL= + +# Optional: open self-registration of the first/any team (1 to enable). +# ALLOW_REGISTRATION=1 + +# Optional: shared secret for BizGaze SSO + signed webhook delivery. +# SSO_SECRET= + +# Optional: BizGaze webhook endpoint for session events. +# BIZGAZE_WEBHOOK_URL= diff --git a/.gitignore b/.gitignore index e0c218b..36b7169 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,10 @@ npm-debug.log* # Environment files .env .env.* +!.env.example + +# Deploy secrets (server password / host) — keep the .example tracked +deploy.config # Build output dist/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..28859c2 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,20 @@ +# BizGaze Support — server image +# Node 24 ships node:sqlite as a stable built-in (no flag), which db.js relies on. +FROM node:24-alpine + +ENV NODE_ENV=production +WORKDIR /app/server + +# Install deps first for layer caching (only `ws`, plus optional nodemailer) +COPY server/package*.json ./ +RUN npm install --omit=dev --no-audit --no-fund + +# App source +COPY server/ ./ + +# Served HTTP port (NPM terminates TLS and proxies here). DB lives on a volume. +ENV PORT=8090 +ENV DB_PATH=/data/data.db +EXPOSE 8090 + +CMD ["node", "server.js"] diff --git a/deploy.sh b/deploy.sh new file mode 100644 index 0000000..24268a5 --- /dev/null +++ b/deploy.sh @@ -0,0 +1,110 @@ +#!/usr/bin/env bash +# +# deploy.sh — run this ON THE SERVER, from inside the cloned repo +# (the app lives at /opt/bizgaze-support). +# +# What it does: +# 1. Snapshots the current working tree (code + .env + certs, excluding .git) +# into a rotating backup, keeping the newest $KEEP_BACKUPS. +# 2. Pulls the latest commit of $GIT_BRANCH (git reset --hard, so the box +# always matches origin exactly). +# 3. Rebuilds the image and recreates the container. The named data volume +# (data.db) persists; the untracked .env / server/cert.pem / server/key.pem +# are gitignored and therefore preserved across every pull. +# 4. Verifies the app is serving. +# +# Usage (on the server): +# cd /opt/bizgaze-support +# ./deploy.sh # pull latest + rebuild +# ./deploy.sh --no-pull # rebuild current checkout (no git pull) +# ./deploy.sh --rollback # restore newest backup snapshot + rebuild +# +# Fire it from your laptop without logging in: +# plink -ssh -P 61 -pw '' root@118.95.33.89 \ +# "cd /opt/bizgaze-support && ./deploy.sh" + +set -euo pipefail + +GIT_BRANCH="${GIT_BRANCH:-master}" +KEEP_BACKUPS="${KEEP_BACKUPS:-3}" +CONTAINER="${CONTAINER:-bizgaze-support}" + +cd "$(dirname "$(readlink -f "$0")")" +APP_DIR="$(pwd)" +BK_DIR="${APP_DIR}.backups" + +log() { printf '\033[1;36m==>\033[0m %s\n' "$*"; } +ok() { printf '\033[1;32m ✓\033[0m %s\n' "$*"; } +warn(){ printf '\033[1;33m ! %s\033[0m\n' "$*"; } +die() { printf '\033[1;31mERROR:\033[0m %s\n' "$*" >&2; exit 1; } + +[ -d .git ] || die "Not a git checkout. Run the one-time bootstrap first (see DEPLOY.md)." +command -v docker >/dev/null || die "docker not found on this host." + +# --- args --- +DO_PULL=1; ROLLBACK=0 +for a in "$@"; do case "$a" in + --no-pull) DO_PULL=0 ;; + --rollback) ROLLBACK=1 ;; + -h|--help) grep '^#' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;; + *) die "Unknown argument: $a" ;; +esac; done + +snapshot() { + mkdir -p "$BK_DIR" + local ts rev + ts="$(date +%Y%m%d-%H%M%S)" + rev="$(git rev-parse --short HEAD 2>/dev/null || echo nogit)" + log "Snapshot -> $BK_DIR/${ts}-${rev}.tgz" + tar --exclude=./.git --exclude=./node_modules \ + --exclude=./server/node_modules -czf "$BK_DIR/${ts}-${rev}.tgz" -C "$APP_DIR" . + # rotate: keep newest $KEEP_BACKUPS + local old + old="$(ls -1t "$BK_DIR"/*.tgz 2>/dev/null | tail -n +$((KEEP_BACKUPS + 1)) || true)" + if [ -n "$old" ]; then + echo "Pruning old backups:"; echo "$old" | sed 's/^/ rm /' + echo "$old" | xargs -r rm -f + fi +} + +rebuild() { + [ -f .env ] || warn "No .env present — TURN/SSO secrets will be unset." + log "Rebuilding and recreating the container …" + docker compose config >/dev/null || die "docker-compose.yml is invalid." + docker compose up -d --build + docker compose ps +} + +verify() { + log "Verifying /api/ice …" + if docker exec "$CONTAINER" wget -qO- http://localhost:8090/api/ice 2>/dev/null | grep -q iceServers; then + ok "App is serving." + else + warn "Could not confirm /api/ice — check: docker logs $CONTAINER" + fi +} + +# --- rollback mode --- +if [ "$ROLLBACK" -eq 1 ]; then + latest="$(ls -1t "$BK_DIR"/*.tgz 2>/dev/null | head -n1 || true)" + [ -n "$latest" ] || die "No backups found in $BK_DIR" + log "Rolling back from: $latest" + snapshot # snapshot the (broken) current state first + tar -xzf "$latest" -C "$APP_DIR" + rebuild; verify + ok "Rolled back to $latest" + exit 0 +fi + +# --- normal deploy --- +snapshot +if [ "$DO_PULL" -eq 1 ]; then + log "Fetching origin/$GIT_BRANCH …" + git fetch origin "$GIT_BRANCH" + git reset --hard "origin/$GIT_BRANCH" # untracked .env / *.pem are preserved + ok "Now at $(git rev-parse --short HEAD): $(git log -1 --pretty=%s)" +fi +rebuild +verify +ok "Deploy complete. Backups kept: $KEEP_BACKUPS (in $BK_DIR)." +echo " Rollback with: ./deploy.sh --rollback" diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..aa7340a --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,31 @@ +# BizGaze Support — deployed behind the existing Nginx Proxy Manager. +# No host ports are published: NPM reaches this container by name on the +# shared `nginx_proxy_manager_default` network. TLS is terminated by NPM, +# which proxies https://remote.bizgaze.com -> bizgaze-support:8090. +services: + app: + build: . + image: bizgaze-support:latest + container_name: bizgaze-support + restart: unless-stopped + environment: + - PORT=8090 + - DB_PATH=/data/data.db + # Secrets (TURN credentials, SSO_SECRET, BIZGAZE_WEBHOOK_URL, etc.) live in + # a .env file next to this compose file. It is gitignored — never committed. + # See .env.example for the expected keys. + env_file: + - path: .env + required: false + volumes: + - bizgaze_support_data:/data # persists data.db across rebuilds + networks: + - npm + +networks: + npm: + external: true + name: nginx_proxy_manager_default + +volumes: + bizgaze_support_data: From 7620300ef7255a404c01c9b6789ebd57d172e5cb Mon Sep 17 00:00:00 2001 From: avinash Date: Wed, 10 Jun 2026 16:31:06 +0530 Subject: [PATCH 2/2] refactor: update .gitignore for deploy secrets and add redeploy scripts --- .gitignore | 4 +- DEPLOY.md | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++ deploy.sh | 0 redeploy.bat | 27 +++++++++++++ redeploy.sh | 39 ++++++++++++++++++ 5 files changed, 177 insertions(+), 2 deletions(-) create mode 100644 DEPLOY.md mode change 100644 => 100755 deploy.sh create mode 100644 redeploy.bat create mode 100755 redeploy.sh diff --git a/.gitignore b/.gitignore index 36b7169..0625426 100644 --- a/.gitignore +++ b/.gitignore @@ -21,8 +21,8 @@ npm-debug.log* .env.* !.env.example -# Deploy secrets (server password / host) — keep the .example tracked -deploy.config +# Local deploy trigger password (never commit) +deploy.secret # Build output dist/ diff --git a/DEPLOY.md b/DEPLOY.md new file mode 100644 index 0000000..cb81a2a --- /dev/null +++ b/DEPLOY.md @@ -0,0 +1,109 @@ +# 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`](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](.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.89` port `61` +- 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 `.tgz` snapshots, auto-rotated) + +--- + +## 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. + +```bash +ssh -p 61 root@118.95.33.89 # or: plink -ssh -P 61 -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: + +```bash +cp .env.example .env && nano .env +``` + +--- + +## Routine deploy + +After pushing changes to `origin/master`: + +```bash +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 --hard`s 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 + +--- + +## Verify + +```bash +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 + +```bash +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/.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. diff --git a/deploy.sh b/deploy.sh old mode 100644 new mode 100755 diff --git a/redeploy.bat b/redeploy.bat new file mode 100644 index 0000000..ab9306d --- /dev/null +++ b/redeploy.bat @@ -0,0 +1,27 @@ +@echo off +setlocal enabledelayedexpansion +REM redeploy.bat - trigger a remote deploy FROM YOUR LAPTOP (Windows). +REM Double-click, or run from a terminal. Pass deploy.sh flags through: +REM redeploy.bat pull latest + rebuild +REM redeploy.bat --no-pull rebuild current checkout +REM redeploy.bat --rollback restore newest backup on the server +REM +REM Password order: %DEPLOY_PASS% -> deploy.secret file -> prompt. + +set "HOST=118.95.33.89" +set "PORT=61" +set "USER=root" +set "APPDIR=/opt/bizgaze-support" + +REM Locate plink +set "PLINK=plink" +where plink >nul 2>nul || set "PLINK=C:\Program Files\PuTTY\plink.exe" + +REM Resolve password +set "PW=%DEPLOY_PASS%" +if "!PW!"=="" if exist "%~dp0deploy.secret" set /p PW=<"%~dp0deploy.secret" +if "!PW!"=="" set /p "PW=Server password for %USER%@%HOST%: " + +echo ==^> Triggering deploy on %USER%@%HOST% (%APPDIR%) ... +"%PLINK%" -ssh -batch -P %PORT% -pw "!PW!" %USER%@%HOST% "cd %APPDIR% && bash deploy.sh %*" +endlocal diff --git a/redeploy.sh b/redeploy.sh new file mode 100755 index 0000000..c477fc3 --- /dev/null +++ b/redeploy.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +# +# redeploy.sh — trigger a remote deploy FROM YOUR LAPTOP (Git Bash). +# It SSHes into the server and runs the server-side ./deploy.sh. +# +# Usage: +# ./redeploy.sh # pull latest + rebuild +# ./redeploy.sh --no-pull # rebuild current checkout +# ./redeploy.sh --rollback # restore newest backup on the server +# +# Password (in priority order): +# 1. $DEPLOY_PASS environment variable +# 2. a gitignored `deploy.secret` file next to this script (one line = the pw) +# 3. hidden prompt +set -euo pipefail + +HOST=118.95.33.89 +PORT=61 +USER=root +APPDIR=/opt/bizgaze-support + +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# Locate plink (PuTTY). +PLINK="$(command -v plink 2>/dev/null || true)" +[ -n "$PLINK" ] || PLINK="/c/Program Files/PuTTY/plink" +[ -x "$PLINK" ] || { echo "ERROR: plink not found (install PuTTY or add to PATH)"; exit 1; } + +# Resolve password. +PW="${DEPLOY_PASS:-}" +if [ -z "$PW" ] && [ -f "$DIR/deploy.secret" ]; then + PW="$(tr -d '\r\n' < "$DIR/deploy.secret")" +fi +if [ -z "$PW" ]; then + read -rsp "Server password for $USER@$HOST: " PW; echo +fi + +echo "==> Triggering deploy on $USER@$HOST ($APPDIR) …" +exec "$PLINK" -ssh -batch -P "$PORT" -pw "$PW" "$USER@$HOST" "cd $APPDIR && bash deploy.sh $*"