Infrastructure & Deployment¶
The portfolio's deployment baseline is Docker Compose on a self-hosted IONOS VPS, fronted by nginx. ~75% of apps follow this pattern. The exceptions are a small set of static-export marketing sites and Tauri / Electron desktop apps that ship as binaries.
The baseline stack¶
For the typical app, docker-compose.yml defines:
nginx (reverse proxy, port 80/443 → app)
app (node:20-slim or php:8.2-fpm)
db (postgres:15-alpine + pgvector or mysql:8.0)
redis (redis:7-alpine, optional)
worker (BullMQ / Celery / arq, optional)
minio (object storage, on AI document apps)
External port range is 8088–8151 (per the user's local notes — careful not to collide). Internal services bind to 3000, 3001, 5432, 6379 inside the bridge network.
Docker¶
What it is. Containerization — package an app + its OS deps into an image, run it isolated.
Patterns universal across the portfolio:
- Multi-stage builds. FROM node:20-slim AS builder → FROM node:20-alpine AS runner. Cuts production image size 5–10×.
- .dockerignore to exclude node_modules, .git, .env, build artifacts.
- Health checks in docker-compose.yml: curl/wget /healthz for app services, SQL readiness probes for DBs.
- Restart policy: unless-stopped (auto-restart on crash, stay down if explicitly stopped).
- Volumes for DB data and MinIO. node_modules is typically NOT volume-mounted in prod (rebuilt on every image).
- Custom bridge network per app — services find each other by service name, not IP.
Base images seen:
- Node: node:20-slim, node:20-alpine.
- Python: python:3.11-slim (Automotive, GoGreen-DOC-AI, GoGreen-SmartForms).
- PHP: php:8.2-fpm (Maximus, AI-Wordpress, Voting).
- Reverse proxy: nginx:alpine.
- Databases: postgres:15-alpine, pgvector/pgvector:pg15 or pg16/pg17, mysql:8.0, mariadb:10.4.
- Cache / queue: redis:7-alpine.
- Storage: minio/minio.
Kubernetes (Helm)¶
What it is. Container orchestration — declarative Deployments, Services, Ingress, and autoscaling across a cluster. Reached for on the larger, production-grade products where single-host Docker Compose isn't enough.
Used in (real k8s manifests): OpenSentinel, GoGreen Workflow Hub, Toolbelt, SuperCabs (RideShare), GoGreen DOC-AI, GoGreen SmartForms, GoGreen Seller AI (Ecom-Sales / GogreenSellerAI), AutoDiag AI, PolyMarketAI, and Recruiting AI — 11 products ship Kubernetes manifests.
Patterns. Packaged as Helm charts (deploy/helm/<app>, infrastructure/k8s, helm/<app> with Chart.yaml) containing Deployment + Service + Ingress, plus HorizontalPodAutoscaler (HPA) for the services that scale on load.
Relationship to the baseline. Docker Compose on the IONOS VPS stays the default for simpler products; Kubernetes is the path for anything needing multi-replica scaling, HPA, or cluster-grade orchestration. Both patterns coexist in the portfolio.
nginx¶
What it is. Reverse proxy, web server, SSL terminator. Routes incoming requests by host or path to the right backend container.
Used in: ~25 apps as the docker-compose front door.
Common patterns:
- Path-based routing for sub-path deploys (e.g. pawsc-explorer ships at /pawsc/ on a shared host).
- WebSocket upgrade headers for Socket.IO / ws apps.
- Static-asset caching with expires headers.
- Let's Encrypt / Certbot for TLS — cron-renewed.
The user's nginx note (per global CLAUDE.md): Never use sed on nginx via SSH. Use scp'd Python scripts to edit nginx configs — the escaping issues are well-documented in their feedback_nginx_escaping.md memory.
Caddy / Traefik / Apache (not used)¶
Caddy and Traefik are popular nginx alternatives. Traefik shines with auto-discovery in Docker (labels-based config). The portfolio chose nginx for familiarity. Apache is only present inside WordPress containers.
IONOS VPS¶
The single production host: 74.208.129.33. SSH key auth as root. Locations of note (per user's global rules):
- Nginx config:
/etc/nginx/sites-available/gogreen-verify - WordPress:
/var/www/html/Wordpress/ - PHP 8.3-fpm, MariaDB, WP-CLI installed.
Process supervision is Docker, not systemd or PM2. restart: unless-stopped handles crash-recovery; reboots come back to a clean state because every service has a docker-compose up -d invocation.
TLS: Let's Encrypt via Certbot. Auto-renewed via cron.
Hosting alternatives present in the portfolio¶
| Platform | Used for |
|---|---|
| IONOS VPS | ~35 apps (production) |
| Tauri binary | AscendOne, ChoreAndMoreTracker, GoGreenMarketing, Jarvis_Rust_Tauri |
| Electron binary | Ecom-Sales, FamilyChat, GogreenSellerAI, PolyMarketAI, Jarvis_Electron |
| Vercel / Netlify | A handful of static-export sites may be there; not explicitly in docker-compose configs |
Orchestration is a two-tier model: Docker Compose on the IONOS VPS is the default for simpler products, and Kubernetes (Helm) is used for the larger, scale-sensitive products (11 of them — see the Kubernetes section above). No AWS ECS / Fargate or Cloud Run — the portfolio's clusters are vanilla Kubernetes with Helm.
Build & dev tools¶
| Tool | Used |
|---|---|
| npm | 17+ apps |
| pnpm | FamilyChat, GoGreen-AI-Concierge (monorepos) |
| yarn | 0 apps |
| bun | OpenSentinel (runtime, not just package mgr) |
| Composer (PHP) | Maximus, AI-Wordpress, Voting |
| pip / poetry / uv | Automotive, DOC-AI, SmartForms (Python apps) |
| cargo | ChoreAndMoreTracker (Rust), Jarvis_Rust_Tauri |
No Turborepo, Nx, or Lerna. Two pnpm-workspaces monorepos. Most apps are single-repo single-package.
Make / Just / Taskfile. Not used. npm scripts (npm run start, npm run build, npm run deploy) handle task running.
Cloudflare / CDN¶
Status: referenced in user's notes ("possibly Cloudflare proxying") but no app config explicitly shows Cloudflare. CDN is generally handled at the domain-DNS layer rather than in app code.
Domain & DNS¶
Most likely: IONOS DNS (since the VPS is IONOS). No Cloudflare DNS, Route53, or third-party DNS configs surfaced in the audit.
The user's portfolio reference memory tracks a per-app domain-to-app mapping (see reference_portfolio.md and feedback_domain_mappings.md in their persistent memory).
Secrets management¶
Approach: .env files at the project root, gitignored. .env.example checked in as the schema. The master file API_Keys_and_Secrets_Master.md at the portfolio root is the source of truth for which keys belong to which app.
Not used: AWS Secrets Manager, HashiCorp Vault, Doppler, Infisical, 1Password Secrets Automation. Per the user's tooling preferences, .env + the master Markdown file is intentional.
Comparison alternatives (not used)¶
| Pattern | Notes |
|---|---|
| Serverless (Vercel Functions / Lambda / Cloud Run) | Doesn't fit the always-on Postgres + Redis + queue worker model. |
| Render / Railway / Fly.io | "PaaS-on-Docker." Self-hosted IONOS is cheaper at portfolio scale. |
| Docker Swarm | Light-weight orchestration. Compose is enough. |
| Nomad | Same. |
| Terraform / Ansible / Pulumi | IaC. Manual deploy is the current model — feasible because there's only one production host. |
Decision guide¶
New web app, going to production? Dockerfile + docker-compose.yml + nginx + IONOS.
Need a TLS cert? Certbot, cron-renewed.
Need a CDN? Cloudflare in front of nginx.
Need scheduled jobs? BullMQ repeatable jobs (Node) or arq/Celery (Python). No cron container.
Static marketing site, no auth? Next.js static export → nginx serves the /out dir.
Desktop app distribution? Tauri (small) or Electron (familiar).
Simple product / single host? Docker Compose on the IONOS VPS (the default).
Needs multi-replica scaling / HPA? Kubernetes + Helm (as 11 of the larger products do).
What lives where (mental map)¶
74.208.129.33 (IONOS VPS)
├── nginx (host-level)
│ ├── /etc/nginx/sites-available/* (per-app vhost)
│ └── Let's Encrypt cron
├── /var/www/html/Wordpress/ (legacy WordPress)
└── /opt/apps/{appname}/ (per-app docker-compose stacks)
├── docker-compose.yml
├── .env
└── data volumes (postgres, redis, minio)