---
title: Infrastructure
tags: [architecture, infrastructure, docker, devops]
created: 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
```mermaid
flowchart LR
DNS[DNS amn.gg] --> CF[CloudFlare / Edge SSL]
CF --> Nginx
subgraph Host[Single Docker host]
Nginx[nginx:alpine
nickapp-nginx
:8083]
FE[nickapp-frontend:latest
Next.js standalone
:8083]
BE[nickapp-backend:latest
Express + Socket.IO
:5001]
Mongo[(mongo:8.0
mongodb_data volume)]
Redis[(redis:8-alpine
redis_data volume)]
Up[/uploads volume/]
end
Nginx --> FE
Nginx --> BE
BE --> Mongo
BE --> Redis
BE --- Up
FE --- Up
Watchtower>Watchtower
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_PASSWORD` MUST be set in the production `.env` before 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/*` to `nickapp-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/logs` so 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:
1. Developer pushes commits to a feature branch → merged into `development`.
2. Manual Gitea workflow `docker-build-simple.yml` builds & pushes `nickapp-backend:latest` (and a versioned tag) to `git.manko.yoga/manawenuz/escrow-backend`.
3. 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 `latest` will roll out automatically. Keep `dev` and `production` tags 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_SECRET`
- `MONGODB_URI`, `REDIS_PASSWORD`
- `SHKEEPER_API_KEY`, `SHKEEPER_WEBHOOK_SECRET`
- `SMTP_USER`, `SMTP_PASS`
- `OPENAI_API_KEY`
- `GOOGLE_CLIENT_ID`, `GOOGLE_CLIENT_SECRET`
- `NEXT_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=true` in 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