153 lines
3.8 KiB
Markdown
153 lines
3.8 KiB
Markdown
# 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 images
|
|
- `cdn.banatie.app/{org}/{proj}/img/@{alias}` - API-mediated alias resolution
|
|
- `cdn.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:
|
|
|
|
```caddyfile
|
|
# 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`:
|
|
|
|
```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:
|
|
|
|
```bash
|
|
# 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:
|
|
1. Create the `banatie` bucket
|
|
2. Configure service user with readwrite access
|
|
3. Enable public anonymous download access for CDN
|
|
|
|
Verify public access is enabled:
|
|
|
|
```bash
|
|
docker exec banatie-minio mc anonymous get local/banatie
|
|
# Should show: Access permission for `local/banatie` is `download`
|
|
```
|
|
|
|
## Verification
|
|
|
|
### Test Direct UUID Access
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
curl -I "https://cdn.banatie.app/{orgSlug}/{projectSlug}/live/test?prompt=mountain"
|
|
|
|
# Expected: HTTP 200 (generates or returns cached image)
|
|
```
|
|
|
|
## Rollback
|
|
|
|
If issues occur:
|
|
|
|
1. Revert code changes
|
|
2. Rebuild API container
|
|
3. 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)
|