3.8 KiB
3.8 KiB
CDN URL Architecture Fix - VPS Deployment
This document describes the changes needed on VPS to support the new CDN URL architecture.
Problem
Previous URL structure used presigned URLs with 24-hour expiry, which doesn't work for permanent image embedding on websites.
Solution
New URL structure with direct CDN access:
cdn.banatie.app/{org}/{proj}/img/{imageId}- Direct MinIO access for static imagescdn.banatie.app/{org}/{proj}/img/@{alias}- API-mediated alias resolutioncdn.banatie.app/{org}/{proj}/live/{scope}?prompt=...- API-mediated live generation
Storage Path Format
Old: {orgSlug}/{projectSlug}/{category}/{timestamp-filename.ext}
New: {orgSlug}/{projectSlug}/img/{imageId}
Where imageId = UUID (same as images.id in database).
VPS Deployment Steps
1. Update Caddy Configuration
Add the following routing rules to your Caddy config:
# CDN Domain
cdn.banatie.app {
# UUID pattern - direct to MinIO (no extension in URL)
@uuid path_regexp uuid ^/([^/]+)/([^/]+)/img/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$
handle @uuid {
reverse_proxy banatie-minio:9000 {
# Rewrite to bucket path
header_up Host cdn.banatie.app
rewrite * /banatie{uri}
}
}
# Alias pattern (@name) - proxy to API
@alias path_regexp alias ^/([^/]+)/([^/]+)/img/@(.+)$
handle @alias {
reverse_proxy banatie-api:3000 {
rewrite * /cdn{uri}
}
}
# Live URL pattern - proxy to API
@live path_regexp live ^/([^/]+)/([^/]+)/live/(.+)$
handle @live {
reverse_proxy banatie-api:3000 {
rewrite * /cdn{uri}
}
}
# Fallback for other patterns
handle {
reverse_proxy banatie-minio:9000 {
header_up Host cdn.banatie.app
rewrite * /banatie{uri}
}
}
}
2. Update Environment Variables
Add to /opt/banatie/.env:
CDN_BASE_URL=https://cdn.banatie.app
3. Reset Database and MinIO Storage
Since this is a breaking change to the storage path format:
# Stop services
cd /opt/banatie
docker compose down
# Clean database (WARNING: deletes all data)
rm -rf /opt/banatie/data/postgres/*
# Clean MinIO storage (WARNING: deletes all files)
rm -rf /opt/banatie/data/minio/drive{1,2,3,4}/*
# Rebuild and start services
docker compose up -d --build
4. Run Storage Initialization
After rebuild, the banatie-storage-init container will:
- Create the
banatiebucket - Configure service user with readwrite access
- Enable public anonymous download access for CDN
Verify public access is enabled:
docker exec banatie-minio mc anonymous get local/banatie
# Should show: Access permission for `local/banatie` is `download`
Verification
Test Direct UUID Access
# After generating an image, get its UUID from database or API response
# Then test direct CDN access:
curl -I "https://cdn.banatie.app/{orgSlug}/{projectSlug}/img/{uuid}"
# Expected: HTTP 200 with Content-Type: image/png (or similar)
Test Alias Resolution
# Assign an alias to an image via API, then test:
curl -I "https://cdn.banatie.app/{orgSlug}/{projectSlug}/img/@hero"
# Expected: HTTP 200 (API resolves alias and streams image)
Test Live URL Generation
curl -I "https://cdn.banatie.app/{orgSlug}/{projectSlug}/live/test?prompt=mountain"
# Expected: HTTP 200 (generates or returns cached image)
Rollback
If issues occur:
- Revert code changes
- Rebuild API container
- Regenerate any images (old storage paths won't work)
Notes
filename = image.id(UUID) ensures consistent identification across DB, storage, and URLs- Files are stored without extension; Content-Type is served from MinIO metadata
- Cloudflare caching can be enabled for UUID patterns (see url-fix-cloudflare-site.md)