8.3 KiB
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
- og:url: https://banatie.app/
- og:image: https://banatie.app/og-image.png
- og:type: website
- og:locale: en_US
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
- NEXT_PUBLIC_ variables* — Required for client-side code, must be present at build time
- pnpm workspaces in Docker — Symlinks break between stages, use single-stage install
- 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
curlbinary 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