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

332 lines
8.3 KiB
Markdown

# 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](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`:
```caddy
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)
```env
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)
```env
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
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 ✅
- [x] Landing page deployed (~December 15, 2025)
- [x] Domain connected via Cloudflare
- [x] SSL configured (Full strict)
- [x] Google Search Console verified
- [x] Umami analytics connected
- [x] Meta tags and OG image configured
- [x] Cache rules for static assets
- [x] Trailing slash redirect
- [x] Image optimization (AVIF)
- [x] PageSpeed 95+ mobile
- [x] **API service deployed (December 23, 2025)**
- [x] **PostgreSQL running**
- [x] **MinIO storage configured**
- [x] **CDN endpoint configured**
- [x] **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