8.4 KiB
title, tags, created
| title | tags | created | ||||
|---|---|---|---|---|---|---|
| Infrastructure |
|
2026-05-23 |
Infrastructure
How the system is packaged, deployed and run in production. Read alongside Docker Setup (operations runbook) and CI-CD Pipeline.
1. Runtime topology
flowchart LR
DNS[DNS amn.gg] --> CF[CloudFlare / Edge SSL]
CF --> Nginx
subgraph Host[Single Docker host]
Nginx[nginx:alpine<br/>nickapp-nginx<br/>:8083]
FE[nickapp-frontend:latest<br/>Next.js standalone<br/>:8083]
BE[nickapp-backend:latest<br/>Express + Socket.IO<br/>:5001]
Mongo[(mongo:8.0<br/>mongodb_data volume)]
Redis[(redis:8-alpine<br/>redis_data volume)]
Up[/uploads volume/]
end
Nginx --> FE
Nginx --> BE
BE --> Mongo
BE --> Redis
BE --- Up
FE --- Up
Watchtower>Watchtower<br/>auto-update] -.-> BE
Watchtower -.-> FE
[!info] Single-host today. Horizontal scaling requires Redis pub/sub adapter for Socket.IO and externalizing the
uploads/volume (S3 / R2).
2. Docker images
| Image | Source Dockerfile | Stages | Final size target | User |
|---|---|---|---|---|
nickapp-backend:latest |
backend/Dockerfile.prod |
builder + runner | ~200 MB | marketplace (uid 1001) |
nickapp-backend:dev |
backend/Dockerfile.dev |
single | ~400 MB | marketplace (uid 1001) |
nickapp-frontend:latest |
frontend/Dockerfile |
builder + runner | ~250 MB | nextjs (uid 1001) |
nickapp-frontend:dev |
frontend/Dockerfile.dev |
single | ~600 MB | root |
All built on node:22-alpine. Backend images include Python+make+g++ in the builder stage for native deps (bcrypt). Frontend runner only ships the .next/standalone output + public/.
3. Compose stacks
3.1 docker-compose.dev.yml (backend repo)
Used by developers running npm run docker:dev. Three services:
| Service | Image | Ports | Volumes | Depends on |
|---|---|---|---|---|
nickdev-backend |
built from Dockerfile.dev |
5001:5001 |
./src:/app/src, ./uploads:/app/uploads |
mongodb, redis |
nickdev-mongodb |
mongo:8.0 |
27017:27017 |
mongodb_data:/data/db |
— |
nickdev-redis |
redis:8-alpine |
(internal) | redis_data:/data |
— |
Network: nickapp-network (bridge). Env: .env.local.
Frontend dev runs OUTSIDE compose — developer launches yarn dev on host so React Fast Refresh works.
3.2 docker-compose.production.yml (backend repo)
Used in production. Five services:
| Service | Image | Ports | Healthcheck | Watchtower |
|---|---|---|---|---|
nickapp-nginx |
nginx:alpine |
8083:80 |
implicit | — |
nickapp-backend |
nickapp-backend:latest (pulled) |
5001 internal | node healthcheck.js 30s |
✓ |
nickapp-frontend |
nickapp-frontend:latest (pulled) |
8083 internal | curl http://localhost:8083 30s |
✓ |
nickapp-mongodb |
mongo:8.0 |
internal | mongosh ping 30s |
— |
nickapp-redis |
redis:8-alpine (with --requirepass) |
internal | redis-cli ping 30s |
— |
Volumes: mongodb_data, redis_data, ./uploads, ./nginx/nginx.conf, ./nginx/logs. Env: single root .env.
Warning
REDIS_PASSWORDMUST be set in the production.envbefore starting — otherwise the Redis container fails its healthcheck and dependents won't start.
4. Nginx configuration
The Nginx proxy at ./nginx/nginx.conf (mounted read-only) is responsible for:
- Terminating internal HTTP (SSL handled by an external edge — CloudFlare / nginx-proxy / Caddy)
- Routing
/api/*and/socket.io/*tonickapp-backend:5001 - Routing everything else to
nickapp-frontend:8083 - Serving
/uploads/*directly from the shared volume (bypasses the Node process) - Standard gzip / compression / client_max_body_size (≥10 MB to match backend body limit)
Tip
Put the Nginx access log path on a tmpfs or rotate it aggressively — the container exposes
./nginx/logsso the host can manage retention.
5. Watchtower (auto-update)
Both nickapp-backend and nickapp-frontend carry the watchtower.enable=true label. Watchtower polls the container registry on its configured interval and re-pulls when the latest tag moves.
Release cycle:
- Developer pushes commits to a feature branch → merged into
development. - Manual Gitea workflow
docker-build-simple.ymlbuilds & pushesnickapp-backend:latest(and a versioned tag) togit.manko.yoga/manawenuz/escrow-backend. - Within the next poll interval (default 5 min) Watchtower restarts the affected service.
Warning
Because Watchtower restarts only on tag change, sequential pushes are safe — but a broken build pushed to
latestwill roll out automatically. Keepdevandproductiontags separated, or pin production to a versioned tag.
6. Persistent storage
| Volume | What it stores | Backup priority |
|---|---|---|
mongodb_data |
All business data (users, requests, payments, chats, disputes...) | Critical — daily dump |
redis_data |
Cache, session, rate counters | Low — losing it logs everyone out but no data loss |
./uploads (host bind) |
Avatars, product images, dispute evidence, documents | High — daily rsync |
./nginx/logs |
Access / error logs | Medium |
See Backup & Recovery for the runbook.
7. CI / CD
Located at backend/.gitea/workflows/:
| Workflow | Trigger | Output |
|---|---|---|
docker-build-simple.yml |
manual | Build → push backend image to registry (latest + version) |
docker-build-dev.yml |
manual | Dev image variant |
docker-build-no-cache.yml |
manual | Clean build (no GH-Actions cache) |
Frontend at frontend/.gitea/workflows/:
| Workflow | Trigger | Output |
|---|---|---|
deploy.yml |
push to main/master, manual |
Runs scripts/deploy.sh (deploy via SSH) |
devDeploy.yml |
manual | Deploy to dev env |
Single secret required: GITEATOKEN (Gitea PAT with write:package).
Full breakdown → CI-CD Pipeline.
8. Secrets
Never committed. Required in production .env:
JWT_SECRET,REFRESH_TOKEN_SECRETMONGODB_URI,REDIS_PASSWORDSHKEEPER_API_KEY,SHKEEPER_WEBHOOK_SECRETSMTP_USER,SMTP_PASSOPENAI_API_KEYGOOGLE_CLIENT_ID,GOOGLE_CLIENT_SECRETNEXT_PUBLIC_ALCHEMY_API_KEY_*(frontend public envs — embedded at build)
Recommend storing host-side in an .env outside the repo, mounted via Compose. For multi-host: Vault / AWS SSM / GCP Secret Manager.
9. Observability
| Signal | Where |
|---|---|
| App logs | container stdout → docker logs nickapp-backend |
| Access logs | ./nginx/logs |
| Frontend errors | Sentry (@sentry/nextjs) |
| Backend errors | Sentry (optional — add @sentry/node) |
| Healthchecks | GET /health (backend) · GET / (frontend) · mongosh ping · redis-cli ping |
See Monitoring for the full table of metrics & recommended alerts.
10. Networking
| Direction | Port | Protocol | Notes |
|---|---|---|---|
| Internet → Nginx | 8083 | HTTP | SSL terminated upstream |
| Browser → Backend | 5001 | HTTP + WS | via Nginx /api, /socket.io |
| Backend → MongoDB | 27017 | TCP | Docker network |
| Backend → Redis | 6379 | TCP | Docker network |
| Backend → SHKeeper | 443 | HTTPS | External |
| Backend → SMTP | 587 | TLS | External |
| Backend → OpenAI | 443 | HTTPS | External |
| Browser → Blockchain RPC | 443 | HTTPS | Alchemy URLs |
| Browser → WalletConnect | 443 | HTTPS | Relay server |
11. Hardening checklist
- Non-root user inside every container (
marketplace/nextjs) ✓ in Dockerfiles - Read-only Nginx config mount ✓
- Redis requires password ✓
- MongoDB has root credentials + bind to internal network only ✓
- Rate limit enabled before public traffic ⚠ currently disabled
- Refresh tokens rotated on use ⚠ partial
- All public env values reviewed (no
IS_DEVELOPMENT=truein prod build) ⚠ - Watchtower scoped to specific repos
- Sentry source-map upload at build time ✓ (frontend)
See Security Architecture for the deeper review.
Related
- System Architecture · Backend Architecture · Frontend Architecture
- Docker Setup — operational walk-through with commands
- CI-CD Pipeline — workflow breakdown
- Deployment — first-deploy runbook
- Backup & Recovery · Monitoring · Incident Response
- Environment Variables — full env-var catalog