NestJS backend with Prisma, Docker Compose for Postgres/Redis, and deploy docs for the production VM.
4.3 KiB
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
Note: Until the Git remote is accessible from the VM (deploy key / credentials), updates can be synced with
rsyncfrom your laptop. Pinsharp@0.33.5— this VM CPU lacks x64-v2 required by sharp 0.35+.
Prerequisites
- Debian VM with SSH access
- Domain
Arecord 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
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:
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw --force enable
2. Clone the app
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
cp .env.example .env
nano .env # set strong secrets — never commit this file
Required production values:
- Strong
POSTGRES_PASSWORDand matchingDATABASE_URL - Long random
JWT_ACCESS_SECRET/JWT_REFRESH_SECRET - Real
S3_ACCESS_KEY_ID/S3_SECRET_ACCESS_KEY PORT=3000SMS_ENABLEDas needed
4. Database + Redis
cd /opt/meshkee/app
docker compose up -d
docker compose ps
First Postgres volume init runs SQL under database/migrations/ automatically.
Later schema updates:
./database/migrate.sh
5. Build and run (on the server)
cd /opt/meshkee/app
npm ci
npm run prisma:generate
npm run build
Production seed (super admin only — skip sample data):
./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:
pm2 start ecosystem.config.js
pm2 save
pm2 startup # run the command it prints (usually with sudo)
Health check locally on the VM:
curl -s http://127.0.0.1:3000/api/v1/ | head
# or hit a known public route such as tenant resolve
6. Nginx + HTTPS
Create /etc/nginx/sites-available/meshkee-api:
server {
listen 80;
server_name api.example.com; # replace with your domain
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 a certificate:
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.example.com
API base URL: https://api.example.com/api/v1
Ongoing updates
cd /opt/meshkee/app
git pull
./database/migrate.sh # if there are new SQL migrations
npm ci
npm run prisma:generate
npm run build
pm2 restart meshkee-api
Useful commands
pm2 status
pm2 logs meshkee-api
docker compose logs -f postgres