banatie-strategy/execution/18-production-infrastructur...

8.3 KiB

Production Infrastructure

Date: December 21, 2025 Purpose: Document production deployment configuration and external services Status: 🔄 Full Stack Deployed (Testing WIP) Related docs: 12-the-current-tech-state.md


1. Production URLs

URL Purpose Status
https://banatie.app/ Landing page Live
https://www.banatie.app/ Redirects to non-www Configured
https://api.banatie.app/ API service 🔄 Deployed (testing pending)
https://storage.banatie.app/ MinIO Console 🔄 Deployed (testing pending)
https://cdn.banatie.app/ Image CDN (MinIO public) 🔄 Deployed (testing pending)

Canonical URL: https://banatie.app/ (non-www, with trailing slash)


2. Hosting Infrastructure

VPS Provider

  • Provider: Contabo
  • Location: Singapore
  • Plan: Minimum tier
  • Shared with: Family Nextcloud, Gitea

Server Stack

  • Reverse Proxy: Caddy (auto SSL via Let's Encrypt)
  • Container Runtime: Docker Compose
  • Base Path: /opt/banatie/

Docker Services

banatie-landing:
  - Next.js 15 standalone server
  - Port: 3000 (internal)
  - Volume: ./data/waitlist-logs

banatie-api:
  - Express.js API service
  - Port: 3000 (internal)
  - Volumes: ./data/api-results, ./data/api-uploads

banatie-postgres:
  - PostgreSQL database (isolated, not shared)
  - Port: 5432 (internal)
  - Volume: ./data/postgres

banatie-minio:
  - S3-compatible object storage
  - Port: 9000 (API), 9001 (Console)
  - Volume: ./data/minio

banatie-storage-init:
  - One-time bucket initialization
  - Creates 'banatie' bucket with public policy

Network Configuration

  • External network: services_proxy-network (shared with Caddy)
  • Internal network: banatie-internal (isolated for DB/MinIO)

3. Domain & DNS

Domain Registration

  • Registrar: GoDaddy
  • Domain: banatie.app

DNS Management

  • Provider: Cloudflare (migrated from GoDaddy)
  • Nameservers: cosmin.ns.cloudflare.com, ursula.ns.cloudflare.com

DNS Records

Type Name Value Proxy
A banatie.app [VPS IP] Proxied
CNAME www banatie.app Proxied
CNAME api banatie.app Proxied
CNAME storage banatie.app Proxied
CNAME cdn banatie.app Proxied
TXT @ google-site-verification=... DNS only
TXT _dmarc v=DMARC1;... DNS only

4. Cloudflare Configuration

SSL/TLS

  • Mode: Full (strict)
  • Certificate: Cloudflare Edge + Caddy (Let's Encrypt) on origin

Cache Rules

Rule: "Cache Next.js static"

Match: 
  - URI Path starts with /_next/static
  - URI Path ends with .png
  - URI Path starts with /_next/image

Then:
  - Browser TTL: 1 month
  - Edge TTL: 1 month
  - Cache Key: Include all query string parameters

Redirect Rules

Rule: "Add trailing slash"

Match: http.request.full_uri eq "https://banatie.app"
Then: 301 redirect to https://banatie.app/

AI Crawl Control

  • Managed robots.txt: Disabled (self-managed)
  • AI bot access: Allowed for all crawlers

5. Caddy Configuration

Routes in /opt/services/configs/caddy/Caddyfile:

www.banatie.app {
    redir https://banatie.app{uri} permanent
}

banatie.app {
    reverse_proxy banatie-landing:3000
    header {
        Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
        X-Content-Type-Options "nosniff"
        X-Frame-Options "DENY"
    }
}

api.banatie.app {
    reverse_proxy banatie-api:3000
}

storage.banatie.app {
    reverse_proxy banatie-minio:9001
}

cdn.banatie.app {
    reverse_proxy banatie-minio:9000
    header Access-Control-Allow-Origin "*"
}

6. Environment Variables

.env (non-secret)

NODE_ENV=production
PORT=3000
POSTGRES_DB=banatie_db
POSTGRES_USER=banatie_user
DATABASE_URL=postgresql://USER:PASSWORD@banatie-postgres:5432/banatie_db
MINIO_ENDPOINT=banatie-minio:9000
MINIO_USE_SSL=false
MINIO_BUCKET_NAME=banatie
MINIO_PUBLIC_URL=https://cdn.banatie.app
STORAGE_TYPE=minio
API_BASE_URL=https://api.banatie.app
API_PUBLIC_URL=https://api.banatie.app
NEXT_PUBLIC_API_URL=https://api.banatie.app
CORS_ORIGIN=https://banatie.app,https://api.banatie.app
DEFAULT_ORG_ID=default
DEFAULT_PROJECT_ID=main
DEFAULT_USER_ID=system

secrets.env (sensitive)

POSTGRES_PASSWORD=<generated>
MINIO_ROOT_USER=banatie_admin
MINIO_ROOT_PASSWORD=<generated>
MINIO_ACCESS_KEY=banatie_service
MINIO_SECRET_KEY=<generated>
GEMINI_API_KEY=<api-key>
JWT_SECRET=<generated>
SESSION_SECRET=<generated>

7. SEO Configuration

Meta Tags

  • Title: AI Image Generation Inside Your Workflow | Banatie
  • Description: Generate production-ready images via API, SDK, CLI, or live URLs...
  • Keywords: API-first image generation, AI image API, image generation for developers...
  • Author: Banatie
  • Robots: index, follow

Open Graph

Technical SEO

  • Canonical: <link rel="canonical" href="https://banatie.app/"/>
  • Alternate hreflang: en (self-referencing)
  • robots.txt: /robots.txt (self-managed)
  • Sitemap: https://banatie.app/sitemap.xml

Google Search Console

  • Status: Verified (TXT record)
  • Indexed pages: 1 (banatie.app/)
  • Last crawl: December 19, 2025

8. Analytics

Umami Analytics

  • Plan: Cloud (free tier)
  • Dashboard: cloud.umami.is
  • Website ID: 5af6a122-ca2e-4a48-9bfd-9cfd4d7b5174
  • Future: Self-hosted planned

9. Performance

PageSpeed Scores (December 19, 2025)

Metric Mobile Desktop
Performance 95 99
Accessibility 100 100
Best Practices 100 100
SEO 100 100

Core Web Vitals (Mobile)

  • FCP: 1.7s
  • LCP: 2.9s
  • TBT: 10ms
  • CLS: 0

Image Optimization

  • Optimizer: Next.js built-in
  • Formats: AVIF (primary), WebP (fallback)
  • Logo size: 376KB → 7.5KB (50x reduction)

10. Deploy Scripts

Located in ~/workspace/projects/banatie-service/scripts/:

  • deploy-landing.sh — Deploy landing page to VPS
  • deploy-api.sh — Deploy API service to VPS

11. Key Learnings (December 23, 2025)

Docker & Next.js

  1. NEXT_PUBLIC_ variables* — Required for client-side code, must be present at build time
  2. pnpm workspaces in Docker — Symlinks break between stages, use single-stage install
  3. HOSTNAME=0.0.0.0 — Required for Next.js multi-network binding in containers

Docker User NS Remapping

  • Host UID = Container UID + 165536
  • PostgreSQL: sudo chown -R 165606:165606 /opt/banatie/data/postgres
  • MinIO: sudo chown -R 166536:166536 /opt/banatie/data/minio

Database

  • DATABASE_URL encoding — Special characters like = must be encoded as %3D

12. Known Issues

⚠️ Healthcheck Unhealthy

  • Issue: Landing and API containers show "unhealthy" status
  • Cause: No curl binary in containers
  • Impact: Cosmetic only, services work correctly
  • Fix: Add curl to Dockerfiles or use wget/node healthcheck

⚠️ Cache Permission Warning

  • Issue: Landing container logs warning about .next/cache
  • Impact: Minor, caching still works
  • Fix: Adjust volume permissions or Dockerfile user

13. Deployment Checklist

Completed

  • Landing page deployed (~December 15, 2025)
  • Domain connected via Cloudflare
  • SSL configured (Full strict)
  • Google Search Console verified
  • Umami analytics connected
  • Meta tags and OG image configured
  • Cache rules for static assets
  • Trailing slash redirect
  • Image optimization (AVIF)
  • PageSpeed 95+ mobile
  • API service deployed (December 23, 2025)
  • PostgreSQL running
  • MinIO storage configured
  • CDN endpoint configured
  • Master API key generated
  • Full API testing (generation, upload, CDN URLs) — planned by end of week

Pending

  • Full API workflow testing
  • Healthcheck fix (curl in containers)
  • Cache permission fix
  • Email service integration
  • Self-hosted Umami migration

Document Owner: Oleg Last Updated: December 23, 2025 Next Review: After production testing