Docker Layout
All services run as Docker containers, composed via docker-compose.yml files scattered across /opt/. There is no orchestrator above Docker Compose. This is deliberate — one machine, simple tools.
Container count
Total: 38 containers running. Captured 2026-08-12.
Containers grouped by function
Infrastructure base — shared by everything
| Container |
Purpose |
Compose location |
infra-nginx |
Reverse proxy, TLS termination |
/opt/infrastructure/nginx/ |
infra-certbot |
Let's Encrypt cert renewal |
same as nginx |
infra-postgres |
Shared Postgres for most apps |
/opt/infrastructure/postgres/ |
infra-redis |
Shared Redis cache/queue |
/opt/infrastructure/redis/ |
infra-telegram-webhook |
Outbound Telegram bot relay |
/opt/infrastructure/telegram/ |
falco |
Runtime security monitoring |
/opt/infrastructure/falco/ |
clamav |
Malware scanner (antivirus) |
/opt/infrastructure/clamav/ |
Identity, secrets, code
| Container |
Purpose |
Port |
forgejo |
Git server (sovereign GitHub replacement) |
3000 (http), 2222 (ssh) |
vaultwarden |
Password vault |
internal |
headscale |
Self-hosted Tailscale coordination server |
3478, 8091 |
| Container |
Purpose |
Port |
admin-dashboard |
Control Center SPA at joaoluisbrazao.cloud |
8084 |
dashboard-refresh |
Periodic dashboard data refresher |
— |
rabbithall |
Admin/ops UI for VPS internals |
5001 |
LLM and skills
| Container |
Purpose |
Port |
litellm |
LLM proxy router (25 models, cost cap) |
4000 |
jb-skills-gateway |
Paperclip skills runtime, 43 skills |
8095 |
| Container |
Purpose |
Port |
gamine-web |
Hub + agency + backoffice frontend |
8090 |
gamine-app |
Backend app |
— |
gamine-db |
Postgres for Gamine |
5432 (internal) |
gamine-minio |
Object storage for Gamine |
9000 (internal) |
gamine-brain-api |
Gamine intelligence API |
8140 |
gamine-brain-web |
Gamine intelligence frontend |
8141 |
JB Brain (knowledge graph)
| Container |
Purpose |
Port |
jb-brain-api |
Brain API + RAG |
8130 |
jb2b-api |
Curator backend, Q&A claims routing |
8120 |
ghrepos-api |
Skills catalog (open-source agents) |
8086 |
Gestso (Odoo ERP)
| Container |
Purpose |
Port |
sandbox-odoo-web |
Odoo 18 web |
8210 |
sandbox-odoo-db |
Odoo Postgres |
5432 (internal) |
sandbox-odoo-docai |
Document AI extractor |
8211 |
Productivity / ops
| Container |
Purpose |
Port |
vikunja |
Task manager (single source of truth) |
3456 |
uptime-kuma |
Uptime monitoring, 36 monitors |
3001 |
triage-bot |
Email triage automation |
— |
triage-dashboard |
Triage UI |
8082 |
bear-overnight |
Overnight batch worker |
— |
Conventions
- Every container has a healthcheck where the runtime allows it
- Every volume is named — never anonymous
-v mounts
- No
latest tag in any production image — pinned versions only
- Containers expose ports to
127.0.0.1 by default. Nginx is the only public entry point on 0.0.0.0
- Resource limits should be set per container (some are missing — see tech-debt.md)
Where compose files live
/opt/infrastructure/{nginx,postgres,redis,...}/docker-compose.yml
/opt/prod/gamine/docker-compose.yml
/opt/prod/jb-brain/docker-compose.yml
/opt/rabbithall-compose/docker-compose.yml
/opt/ghrepos-api/docker-compose.yml
If unsure where a container's compose is: docker inspect <name> | grep com.docker.compose.project.config_files.