Staging Deployment Guide
This document covers the full end-to-end staging deployment setup for Kloyst, including CI/CD pipelines, server layout, Nginx, monitoring, and the complete port allocation map.
Server Detailsβ
| Property | Value |
|---|---|
| IP | 49.205.216.14 |
| Jenkins | Same server (local) |
| Image Registry | None β images built on-server |
| DB Strategy | Isolated staging DB (kloyst_staging) |
Repository β Deployment Mappingβ
| Repo | Branch | Pipeline | Server Path | Domain |
|---|---|---|---|---|
kloyst-core | staging | kloyst-core/Jenkinsfile | /srv/apps/kloyst-core/ | api.staging.kloyst.com |
kloyst-front | staging | kloyst-front/Jenkinsfile | /srv/apps/kloyst-front/ | staging.vendor.kloyst.com |
Both pipelines are fully independent β deploying the backend does NOT redeploy the frontend, and vice versa.
CI/CD Pipeline Flow (Both Repos)β
Developer pushes to 'staging' branch
β
Jenkins detects push (webhook or poll)
β
ββββ Pipeline Stages βββββββββββββββββββββββββββββββββββββββββ
β 1. Checkout SCM β
β 2. Inject secrets (Jenkins secret file β .env on server) β
β 3. rsync source code β server (excludes: .git, node_mods) β
β 4. docker build (on server, no external registry) β
β 5. docker compose up -d --remove-orphans β
β 6. Symlink Nginx config β /etc/nginx/auto-sites/ β
β 7. nginx -t && systemctl reload nginx β
β 8. Health check (curl with 12 retries, 5s interval) β
β 9. docker image prune -f + docker builder prune -f β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Server Directory Layoutβ
/srv/apps/
βββ kloyst-core/ β backend app (rsync'd from Jenkins)
β βββ docker-compose.staging.yml
β βββ Dockerfile
β βββ nginx/
β β βββ staging-api.conf β symlinked to /etc/nginx/auto-sites/
β βββ monitoring/ β monitoring stack
β β βββ docker-compose.monitoring.yml
β β βββ loki-config.yml
β β βββ promtail-config.yml
β β βββ grafana-provisioning/
β β β βββ datasources/loki.yml
β β β βββ dashboards/dashboards.yml
β β βββ nginx/monitoring.conf β symlinked to /etc/nginx/auto-sites/
β β βββ .env β (manual β Grafana/Dozzle passwords)
β β βββ README.md
β βββ logs/ β Winston log files (host volume)
β βββ system-YYYY-MM-DD.log
β βββ exception-YYYY-MM-DD.log
β βββ network-YYYY-MM-DD.log
β βββ debug-YYYY-MM-DD.log β dev only, empty in staging
β
βββ kloyst-front/ β frontend app (rsync'd from Jenkins)
β βββ docker-compose.staging.yml
β βββ Dockerfile
β βββ nginx/
β βββ staging.conf β symlinked to /etc/nginx/auto-sites/
β
βββ fynli/ β separate app (co-hosted)
βββ ...
Docker Compose Services (Backend)β
File: kloyst-core/docker-compose.staging.yml
| Container | Image | Host Port | Purpose |
|---|---|---|---|
kloyst-staging-api-gateway | kloyst-core:staging-latest | 127.0.0.1:3000 | REST API |
kloyst-staging-webhook-worker | kloyst-core:staging-latest | 127.0.0.1:3002 | Meta webhooks |
kloyst-staging-worker-pool | kloyst-core:staging-latest | none | BullMQ consumer |
kloyst-staging-outbox-relay | kloyst-core:staging-latest | none | DBβRedis relay |
kloyst-staging-postgres | postgres:16-alpine | none | PostgreSQL |
kloyst-staging-redis | redis:7.2-alpine | none | Cache + BullMQ |
All services share one internal Docker network
kloyst-staging-net.
All host ports bound to127.0.0.1only (not reachable from the internet directly).
Docker Compose Services (Frontend)β
File: kloyst-front/docker-compose.staging.yml
| Container | Image | Host Port | Purpose |
|---|---|---|---|
kloyst-front-staging | kloyst-front:staging-latest | 127.0.0.1:4001 | Next.js standalone server |
Port is
4001(not 4000) because Fynli's API claims port 4000 vianetwork_mode: host.
Monitoring Stackβ
File: kloyst-core/monitoring/docker-compose.monitoring.yml
Deployed separately (not part of the app pipeline):
cd /srv/apps/kloyst-core/monitoring
cp .env.example .env # set GRAFANA_PASSWORD and DOZZLE_PASSWORD
docker compose -f docker-compose.monitoring.yml up -d
| Container | Image | Host Port | URL |
|---|---|---|---|
kloyst-monitoring-grafana | grafana/grafana:10.4.3 | 127.0.0.1:3003 | logs.staging.kloyst.com |
kloyst-monitoring-loki | grafana/loki:2.9.8 | 127.0.0.1:3100 | internal |
kloyst-monitoring-promtail | grafana/promtail:2.9.8 | none | internal |
kloyst-monitoring-dozzle | amir20/dozzle:latest | 127.0.0.1:8888 | dozzle.staging.kloyst.com |
Full Server Port Mapβ
| Port | App | Service | Binding |
|---|---|---|---|
| 80, 443 | All | Nginx | 0.0.0.0 |
| 3000 | Kloyst | API Gateway | 127.0.0.1 |
| 3001 | Fynli | Grafana | 0.0.0.0 |
| 3002 | Kloyst | Webhook Worker | 127.0.0.1 |
| 3003 | Kloyst | Grafana (monitoring) | 127.0.0.1 |
| 3100 | Kloyst | Loki | 127.0.0.1 |
| 4000 | Fynli | fynli-api (host net) | 0.0.0.0 |
| 4001 | Kloyst | Frontend (Next.js) | 127.0.0.1 |
| 5000 | MERN Blog | Staging backend | 0.0.0.0 |
| 6379 | Fynli | Redis (host-level) | 127.0.0.1 |
| 8082 | MERN Blog | Staging frontend | 0.0.0.0 |
| 8888 | Kloyst | Dozzle | 127.0.0.1 |
| 27017 | Fynli | MongoDB (host-level) | 127.0.0.1 |
Nginx Virtual Hostsβ
| Domain | Nginx config | Proxies to |
|---|---|---|
staging.vendor.kloyst.com | kloyst-front-staging.conf | 127.0.0.1:4001 |
api.staging.kloyst.com | kloyst-api-staging.conf | 127.0.0.1:3000 + :3002 |
logs.staging.kloyst.com | kloyst-monitoring.conf | 127.0.0.1:3003 |
dozzle.staging.kloyst.com | kloyst-monitoring.conf | 127.0.0.1:8888 |
fynli.blogsage.in | fynli.conf | :4000 + :3001 |
All staging domains protected by Nginx basic auth (username/password layer before app login).
Secrets Managementβ
All secrets managed in Jenkins Credentials (secret file type):
| Jenkins Credential ID | Used by | Content |
|---|---|---|
KLOYST_CORE_STAGING_ENV | Backend Jenkinsfile | Full .env for all 4 services |
KLOYST_FRONT_STAGING_ENV | Frontend Jenkinsfile | NEXT_PUBLIC_* + Meta vars |
server-ssh | Both Jenkinsfiles | SSH key for jenkins@49.205.216.14 |
First-Time Server Setup (Checklist)β
# 1. Create directory structure
sudo mkdir -p /srv/apps/{kloyst-core,kloyst-front}/nginx
sudo mkdir -p /srv/apps/kloyst-core/logs
sudo mkdir -p /srv/apps/kloyst-core/monitoring
sudo chown -R jenkins:jenkins /srv/apps/
# 2. Nginx auto-sites directory
sudo mkdir -p /etc/nginx/auto-sites
# Add to /etc/nginx/nginx.conf: include /etc/nginx/auto-sites/*.conf;
# 3. SSL certs (run once per domain group)
sudo certbot certonly --nginx \
-d staging.vendor.kloyst.com \
-d api.staging.kloyst.com
sudo certbot certonly --nginx \
-d logs.staging.kloyst.com \
-d dozzle.staging.kloyst.com
# 4. Basic auth file for staging
sudo htpasswd -c /etc/nginx/.htpasswd-staging <username>
# 5. Deploy monitoring stack
cd /srv/apps/kloyst-core/monitoring
cp .env.example .env && nano .env # set strong passwords
docker compose -f docker-compose.monitoring.yml up -d
# 6. Configure log rotation (host-level)
# See kloyst-core/logrotate/kloyst-staging