mirror of
https://git.meshkee.com/Meshkee/backend.git
synced 2026-08-11 22:30:59 +04:30
Serve public storefront docs at /docs/website, expose api.{domain} hosts for API SSL sync, and require push-then-pull deploys instead of rsync.
Co-authored-by: Cursor <cursoragent@cursor.com>
236 lines
7.1 KiB
Markdown
236 lines
7.1 KiB
Markdown
# Deploy Meshkee CMS API (Debian VM)
|
|
|
|
Stack: Docker (Postgres + Redis) → Node build on server → PM2 → Nginx + Let's Encrypt.
|
|
|
|
App path on server: `/opt/meshkee/app`
|
|
|
|
API domain: `api.meshkee.com` → `https://api.meshkee.com/api/v1`
|
|
|
|
Per-business API aliases (same Nest app on this VM): `api.{apex}` e.g. `api.sanihome.ir` → `https://api.sanihome.ir/api/v1`. Storefronts still pass the **website apex** in paths (`/tenants/sanihome.ir/...`); only the API hostname changes.
|
|
|
|
> **Deploy path:** push to `git.meshkee.com` (`Meshkee/backend`), then on the API VM `git fetch` + `reset --hard origin/main` + build + `pm2 restart`. Do **not** rsync the app as the normal update path. The API VM uses a read-only SSH deploy key (`meshkee-api-vm-deploy`). Pin `sharp@0.33.5` — this VM CPU lacks x64-v2 required by sharp 0.35+.
|
|
|
|
## Prerequisites
|
|
|
|
- Debian VM with SSH access
|
|
- Domain `A` record pointing at the VM (for HTTPS)
|
|
- Git remote with this codebase (private repo → deploy key)
|
|
- Production secrets (JWT, Postgres password, S3 keys)
|
|
|
|
## 1. Server packages
|
|
|
|
```bash
|
|
sudo apt update && sudo apt upgrade -y
|
|
sudo apt install -y ca-certificates curl gnupg git nginx ufw
|
|
|
|
# Docker
|
|
sudo install -m 0755 -d /etc/apt/keyrings
|
|
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
|
sudo chmod a+r /etc/apt/keyrings/docker.gpg
|
|
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
|
sudo apt update
|
|
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
|
|
sudo usermod -aG docker "$USER"
|
|
# log out/in (or newgrp docker) so docker works without sudo
|
|
|
|
# Node.js 20 LTS
|
|
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
|
|
sudo apt install -y nodejs
|
|
sudo npm install -g pm2
|
|
|
|
# Certbot (after Nginx is installed)
|
|
sudo apt install -y certbot python3-certbot-nginx
|
|
```
|
|
|
|
Firewall:
|
|
|
|
```bash
|
|
sudo ufw allow OpenSSH
|
|
sudo ufw allow 'Nginx Full'
|
|
sudo ufw --force enable
|
|
```
|
|
|
|
## 2. Clone the app
|
|
|
|
```bash
|
|
sudo mkdir -p /opt/meshkee
|
|
sudo chown "$USER:$USER" /opt/meshkee
|
|
cd /opt/meshkee
|
|
git clone <YOUR_GIT_REMOTE_URL> app
|
|
cd app
|
|
```
|
|
|
|
Private repo: create an SSH deploy key on the VM (`ssh-keygen -t ed25519 -C "meshkee-deploy"`), add the public key as a read-only deploy key on GitHub/GitLab, clone via SSH URL.
|
|
|
|
## 3. Production env
|
|
|
|
```bash
|
|
cp .env.example .env
|
|
nano .env # set strong secrets — never commit this file
|
|
```
|
|
|
|
Required production values:
|
|
|
|
- Strong `POSTGRES_PASSWORD` and matching `DATABASE_URL`
|
|
- Long random `JWT_ACCESS_SECRET` / `JWT_REFRESH_SECRET`
|
|
- Real `S3_ACCESS_KEY_ID` / `S3_SECRET_ACCESS_KEY`
|
|
- `PORT=3000`
|
|
- `SMS_ENABLED` as needed
|
|
|
|
## 4. Database + Redis
|
|
|
|
```bash
|
|
cd /opt/meshkee/app
|
|
docker compose up -d
|
|
docker compose ps
|
|
```
|
|
|
|
First Postgres volume init runs SQL under `database/migrations/` automatically.
|
|
|
|
Later schema updates:
|
|
|
|
```bash
|
|
./database/migrate.sh
|
|
```
|
|
|
|
## 5. Build and run (on the server)
|
|
|
|
```bash
|
|
cd /opt/meshkee/app
|
|
npm ci
|
|
npm run prisma:generate
|
|
npm run build
|
|
```
|
|
|
|
Production seed (super admin only — skip sample data):
|
|
|
|
```bash
|
|
./database/seed.sh database/seeds/002_super_admin_user.sql
|
|
# optional reference data:
|
|
# ./database/seed.sh database/seeds/004_iran_cities.sql
|
|
# ./database/seed.sh database/seeds/005_business_categories.sql
|
|
```
|
|
|
|
Start with PM2:
|
|
|
|
```bash
|
|
pm2 start ecosystem.config.js
|
|
pm2 save
|
|
pm2 startup # run the command it prints (usually with sudo)
|
|
```
|
|
|
|
Health check locally on the VM:
|
|
|
|
```bash
|
|
curl -s http://127.0.0.1:3000/api/v1/ | head
|
|
# or hit a known public route such as tenant resolve
|
|
```
|
|
|
|
## 6. Nginx + HTTPS
|
|
|
|
### DNS (per business website domain)
|
|
|
|
On the **business domain** DNS (e.g. zone `sanihome.ir`), add a subdomain that points at this **API VM** (same target as `api.meshkee.com`):
|
|
|
|
| Type | Name / host | Value | Notes |
|
|
|------|-------------|-------|--------|
|
|
| **A** (preferred) | `api` | `<API_VM_PUBLIC_IP>` | Resolves `api.sanihome.ir` → API server |
|
|
| **CNAME** (alternative) | `api` | `api.meshkee.com` | Same effect if your DNS panel allows CNAME on subdomains |
|
|
|
|
Do **not** point `api.{apex}` at the websites VM or dashboards VM — only the Nest API VM.
|
|
|
|
Repeat for each storefront apex (`api.ali-mohammadi.ir`, etc.). Central Meshkee DNS already has `api.meshkee.com` → this VM.
|
|
|
|
### Nginx
|
|
|
|
Create `/etc/nginx/sites-available/meshkee-api`:
|
|
|
|
```nginx
|
|
server {
|
|
listen 80;
|
|
# Central + per-business aliases (add more api.{apex} as domains go live)
|
|
server_name api.meshkee.com api.sanihome.ir;
|
|
|
|
client_max_body_size 15M;
|
|
|
|
location / {
|
|
proxy_pass http://127.0.0.1:3000;
|
|
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;
|
|
}
|
|
}
|
|
```
|
|
|
|
Enable and get certificates:
|
|
|
|
```bash
|
|
sudo ln -sf /etc/nginx/sites-available/meshkee-api /etc/nginx/sites-enabled/
|
|
sudo rm -f /etc/nginx/sites-enabled/default
|
|
sudo nginx -t && sudo systemctl reload nginx
|
|
sudo certbot --nginx -d api.meshkee.com -d api.sanihome.ir
|
|
# later, when another business goes live:
|
|
# sudo certbot --nginx -d api.meshkee.com -d api.sanihome.ir -d api.other-site.ir
|
|
```
|
|
|
|
API base URLs (identical Nest routes):
|
|
|
|
- Central: `https://api.meshkee.com/api/v1`
|
|
- Alias example: `https://api.sanihome.ir/api/v1`
|
|
|
|
### Website API docs (global link for storefront teams)
|
|
|
|
After deploy, these are public (no auth):
|
|
|
|
- Hub: `https://api.meshkee.com/docs/website`
|
|
- OpenAPI: `https://api.meshkee.com/docs/website/openapi.json`
|
|
- Postman: `https://api.meshkee.com/docs/website/Meshkee-Website-API.postman_collection.json`
|
|
- AI brief: `https://api.meshkee.com/docs/website/AI_PROMPT.md`
|
|
|
|
Files live in `docs/website-api/` and are served by Nest from process cwd. Keep that folder on the VM when deploying.
|
|
|
|
### Automated cert host list (API VPS)
|
|
|
|
After deploy, a sync agent on this VM can pull names to cover:
|
|
|
|
```bash
|
|
curl -s -H "X-SSL-Sync-Token: $SSL_SYNC_TOKEN" \
|
|
https://api.meshkee.com/api/v1/internal/ssl/api-hosts
|
|
# → { "hosts": ["api.ali-mohammadi.ir", "api.meshkee.com", "api.sanihome.ir", ...] }
|
|
```
|
|
|
|
Dashboards VPS keeps using `GET /api/v1/internal/ssl/hosts` (`business.` / `customer.` / `manage`) — do not mix the two lists.
|
|
|
|
## Ongoing updates (git only)
|
|
|
|
From your laptop:
|
|
|
|
1. Commit and **push** to `origin/main` (`git.meshkee.com/Meshkee/backend`).
|
|
2. Deploy on the API VM from that commit (never rsync the tree as the primary path):
|
|
|
|
```bash
|
|
ssh -i ~/.ssh/id_ed25519 root@185.164.72.119 'bash -s' <<'REMOTE'
|
|
set -euo pipefail
|
|
cd /opt/meshkee/app
|
|
git fetch origin
|
|
git reset --hard origin/main
|
|
./database/migrate.sh
|
|
npm ci
|
|
npm run prisma:generate
|
|
npm run build
|
|
pm2 restart meshkee-api
|
|
REMOTE
|
|
```
|
|
|
|
Preserve `/opt/meshkee/app/.env` on the server. App remote must be SSH: `git@git.meshkee.com:Meshkee/backend.git` with the VM deploy key registered as a **read-only deploy key** on the repo.
|
|
|
|
## Useful commands
|
|
|
|
```bash
|
|
pm2 status
|
|
pm2 logs meshkee-api
|
|
docker compose logs -f postgres
|
|
```
|