From 6dbf00466b40c9c949b59112a867856b3a21a0c4 Mon Sep 17 00:00:00 2001 From: thiennatra Date: Thu, 16 Apr 2026 16:49:17 +0700 Subject: [PATCH] docs: deploy guides --- deploy/README.md | 2 + deploy/app/docker-compose.yml | 2 +- deploy/vps/README.md | 40 ++++++++++++++ deploy/vps/npm-one-domain-walk-cwish-me.md | 62 ++++++++++++++++++++++ docs/07-ops/deployment.md | 2 + docs/README.md | 1 + 6 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 deploy/vps/npm-one-domain-walk-cwish-me.md diff --git a/deploy/README.md b/deploy/README.md index 1ca752e..62e954b 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -61,6 +61,8 @@ curl -fsS http://127.0.0.1:13001/ready - If you already run host-level Nginx/Caddy for TLS, proxy `https://your-domain` to `http://127.0.0.1:${TRACKING_CONSOLE_PORT}`. - `tracking-api` may still need a public endpoint for ingestion (`POST /track`) depending on your architecture. - If GHCR images are private, `docker login ghcr.io` is required on the VPS. +- Internal API port is always `3000` inside container. External host port is `${TRACKING_API_PORT:-13001}`. +- For single-domain production on Nginx Proxy Manager, see `deploy/vps/README.md` and `deploy/vps/npm-one-domain-walk-cwish-me.md`. ## GHCR image naming from CI diff --git a/deploy/app/docker-compose.yml b/deploy/app/docker-compose.yml index b90e1fe..718d362 100644 --- a/deploy/app/docker-compose.yml +++ b/deploy/app/docker-compose.yml @@ -27,7 +27,7 @@ services: - .env environment: NODE_ENV: production - PORT: ${TRACKING_API_PORT:-13001} + PORT: 3000 ports: - "${TRACKING_API_PORT:-13001}:3000" healthcheck: diff --git a/deploy/vps/README.md b/deploy/vps/README.md index 0c273fc..37a7e78 100644 --- a/deploy/vps/README.md +++ b/deploy/vps/README.md @@ -32,6 +32,13 @@ Edit `.env.app` with production values: - `ADMIN_API_TOKEN=...` - `TRACKING_API_SECRET=...` +Recommended production values: + +- `NODE_ENV=production` +- `TRACKING_API_AUTH_MODE=shared-secret` +- `REDIS_URL=redis://tracking-redis:6379/0` (container-to-container, do not use `localhost`) +- `TRACKING_CORS_ALLOW_ORIGINS=https://staging.prankbook.com,https://prankbook.com,https://walk.cwish.me` + ## Run containers ```bash @@ -51,6 +58,39 @@ curl -fsS http://127.0.0.1:13001/health curl -fsS http://127.0.0.1:13001/ready ``` +## Port map (current standard) + +- `tracking-console` container: `80` -> host `${TRACKING_CONSOLE_PORT}` (default `18081`) +- `tracking-api` container: `3000` -> host `${TRACKING_API_PORT}` (default `13001`) +- `redis` container: `6379` -> host `${REDIS_PORT}` (default `6379`) + +## Single-domain setup (Nginx Proxy Manager) + +When using one public domain (example: `walk.cwish.me`) for both console and API: + +1. Proxy Host Details: + - Domain: `walk.cwish.me` + - Forward Hostname/IP: `77.42.71.202` + - Forward Port: `18081` +2. SSL tab: + - Enable certificate for `walk.cwish.me` + - Force SSL enabled +3. Custom Nginx config (gear icon): + - copy from `deploy/vps/npm-one-domain-walk-cwish-me.md` + +Why this is needed: + +- `/api/*` admin routes need `ADMIN_API_TOKEN` header. Nginx normally rejects underscore headers unless configured. +- `/track` needs preflight `OPTIONS` and must route to API (`13001`) instead of console (`18081`). + +Quick validation: + +```bash +curl -i https://walk.cwish.me/health +curl -i https://walk.cwish.me/ready +curl -i "https://walk.cwish.me/api/admin/events?limit=1&offset=0" -H "ADMIN_API_TOKEN: " +``` + ## Host Nginx 1. Copy `nginx.tracking-base.conf.example` to `/etc/nginx/sites-available/tracking-base.conf` diff --git a/deploy/vps/npm-one-domain-walk-cwish-me.md b/deploy/vps/npm-one-domain-walk-cwish-me.md new file mode 100644 index 0000000..75bde1c --- /dev/null +++ b/deploy/vps/npm-one-domain-walk-cwish-me.md @@ -0,0 +1,62 @@ +# Nginx Proxy Manager: One-Domain Config (`walk.cwish.me`) + +Use this in Proxy Host -> Edit -> gear icon -> `Custom Nginx Configuration`. + +Important: + +- Replace `77.42.71.202` if VPS IP changes. +- Replace `` with your real value. +- Do not commit real secrets. + +```nginx +underscores_in_headers on; +ignore_invalid_headers off; + +location /api/ { + proxy_pass http://77.42.71.202:13001/; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header ADMIN_API_TOKEN $http_admin_api_token; +} + +location = /api/track { + proxy_pass http://77.42.71.202:13001/track; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Tracking-Secret ; +} + +location = /track { + proxy_pass http://77.42.71.202:13001/track; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; +} +``` + +## Why these blocks exist + +- `underscores_in_headers on;` and `ignore_invalid_headers off;` allow forwarding `ADMIN_API_TOKEN`. +- `/api/` forwards dashboard admin API calls to tracking-api. +- `/api/track` forwards frontend `/api/track` calls and injects `x-tracking-secret`. +- `/track` forwards direct SDK/browser calls and preserves CORS preflight behavior. + +## Validation commands + +```bash +curl -i -X OPTIONS https://walk.cwish.me/track \ + -H 'Origin: https://staging.prankbook.com' \ + -H 'Access-Control-Request-Method: POST' \ + -H 'Access-Control-Request-Headers: content-type,x-tracking-secret' + +curl -i "https://walk.cwish.me/api/admin/events?limit=1&offset=0" \ + -H "ADMIN_API_TOKEN: " +``` diff --git a/docs/07-ops/deployment.md b/docs/07-ops/deployment.md index f7959b3..5e7a029 100644 --- a/docs/07-ops/deployment.md +++ b/docs/07-ops/deployment.md @@ -28,3 +28,5 @@ - [Configuration](configuration.md) - [Runbooks](runbooks.md) +- [Deploy folder guide](../../deploy/README.md) +- [VPS upload-only guide](../../deploy/vps/README.md) diff --git a/docs/README.md b/docs/README.md index 2288e70..fc7944d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -44,6 +44,7 @@ The layout is designed so humans and coding agents can navigate the repository w - [`06-frontend/`](06-frontend/tracking-sdk.md): browser and backend client integration - [`06-frontend/frontend-layout-architecture.md`](06-frontend/frontend-layout-architecture.md): canonical frontend layering rules - [`07-ops/`](07-ops/deployment.md): deployment and operations +- [`../deploy/vps/README.md`](../deploy/vps/README.md): VPS deployment checklist (compose + proxy) - [`07-ops/queue-worker-go-live-checklist.md`](07-ops/queue-worker-go-live-checklist.md): step-by-step queue/worker go-live checklist - [`08-security/`](08-security/privacy-and-gdpr.md): privacy and security controls - [`09-testing/`](09-testing/test-strategy.md): quality gates