225 lines
8.4 KiB
Markdown
225 lines
8.4 KiB
Markdown
---
|
|
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<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_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
|