Custom Domains
Allow users to serve images from their own subdomains (e.g., cdn.example.com) instead of your default Pixflare domain. Uses Cloudflare for SaaS to handle SSL, DNS verification, and routing automatically.
Setup
Enable custom domains with the following environment variables:
ENABLE_CUSTOM_DOMAINS='true'
CLOUDFLARE_ZONE_ID='your-zone-id'
CLOUDFLARE_API_TOKEN='your-api-token-with-ssl-certs-permissions'
CUSTOM_DOMAIN_FALLBACK_CNAME='cdn.yourpixflare.com' # Generated by TerraformThe API token needs SSL and Certificates:Edit permissions to manage custom hostnames via Cloudflare for SaaS.
Important: Cloudflare for SaaS is only available on Enterprise plans by default, but you can request access for Free/Pro/Business accounts. The first 100 custom hostnames are free on Enterprise.
How It Works
Users add their subdomain through the API, then configure DNS records to verify ownership:
sequenceDiagram
participant User
participant API
participant CF as Cloudflare API
participant Queue as Custom Domain Queue
participant DNS
User->>API: POST /v1/custom-domains<br/>hostname: cdn.example.com
API->>API: Validate subdomain format
API->>CF: Create custom hostname
CF-->>API: Verification records<br/>CNAME + TXT
API->>Queue: Enqueue verification check
API-->>User: DNS records to configure
User->>DNS: Add CNAME to fallback<br/>Add TXT for verification
loop Every 30s (max 40 retries)
Queue->>CF: Check verification status
CF->>DNS: Verify DNS records
DNS-->>CF: Records found
CF-->>Queue: Status: pending/active/error
alt Status: active
Queue->>Queue: Cache hostname in KV
Queue->>User: Domain verified!
else Status: pending
Queue->>Queue: Re-queue with delay
else Max retries reached
Queue->>User: Verification timeout
end
end
Note over User,DNS: Once active, images serve from custom domainDNS Verification
When a user adds a custom domain, they receive two DNS records to configure:
CNAME Record:
cdn.example.com CNAME cdn.yourpixflare.comTXT Record (for ownership verification):
_cf-custom-hostname.cdn.example.com TXT "verification-code-here"The verification queue polls every 30 seconds for up to 20 minutes (40 retries). Once DNS propagates and verification succeeds, the domain becomes active.
Path Formats
Images on custom domains support flexible URL formats:
# By image ID
https://cdn.example.com/{imageId}
https://cdn.example.com/{imageId}/{variant}
# By album + filename
https://cdn.example.com/{album}/{filename}
https://cdn.example.com/{album}/{filename}/{variant}
# Profile page (proxied)
https://cdn.example.com/u/{owner}All requests are automatically scoped to the domain owner, so users only see their own images.
API Endpoints
Add Custom Domain
POST /v1/custom-domains
{
"hostname": "cdn.example.com"
}Returns DNS verification records.
Get Custom Domain Status
GET /v1/custom-domainsReturns current custom domain with verification status (pending, active, error, blocked).
Remove Custom Domain
DELETE /v1/custom-domains/:idRemoves the custom hostname from Cloudflare for SaaS and deletes the database record.
Check Verification Status
POST /v1/custom-domains/verifyManually triggers a verification check (normally handled by the queue automatically).
Validation Rules
Subdomains must meet the following requirements:
- Format: Valid subdomain (RFC 1123) - alphanumeric and hyphens only
- Length: 3-253 characters total
- Label length: Max 63 characters per label (part between dots)
- Depth: Must be a subdomain, not an apex domain (e.g.,
cdn.example.com, notexample.com) - Reserved: Cannot use common reserved names (www, mail, api, ftp, etc.)
Examples:
- ✅
cdn.example.com - ✅
images.mysite.co.uk - ✅
img-cdn.company.io - ❌
example.com(apex domain) - ❌
api.example.com(reserved subdomain) - ❌
my_cdn.example.com(underscores not allowed)
Limits
Per-Instance Limit
Maximum 99 custom domains per Pixflare instance to stay within Cloudflare's free tier (100 custom hostnames included with Enterprise). This is a hard limit enforced by the API.
For deployments needing more than 99 domains, you'll need to adjust MAX_CUSTOM_DOMAINS in the source code and ensure your Cloudflare plan supports it.
Per-User Limit
Currently one custom domain per user (enforced by database unique constraint on owner field). Multi-domain support would require schema changes.
Performance
Custom domain lookups are cached in KV for fast resolution:
- Cache TTL: 1 hour
- Lookup time: ~1-2ms (cached) or ~10-20ms (database fallback)
- Cache invalidation: Automatic on domain deletion or status change
The first request to a custom domain hits the database, subsequent requests use KV cache.
Troubleshooting
Verification fails
- Check DNS records are configured correctly (CNAME + TXT)
- Wait for DNS propagation (can take 5-10 minutes)
- Verify TXT record name includes
_cf-custom-hostname.prefix - Ensure CNAME points to the fallback domain provided in the response
- Check domain isn't already used by another Cloudflare zone
Domain shows as active but images don't load
- Verify the CNAME record is correct
- Check browser isn't caching old DNS
- Confirm SSL certificate has been issued (can take a few minutes)
- Review Worker logs for routing errors
Queue not processing
- Ensure
ENABLE_QUEUES='true'is set - Verify queue binding exists in
wrangler.toml - Check Worker logs for queue consumer errors
- Confirm
CLOUDFLARE_ZONE_IDandCLOUDFLARE_API_TOKENare set correctly
Disabling
To disable custom domains:
ENABLE_CUSTOM_DOMAINS='false'Existing custom domains remain in the database but won't route traffic. Users won't be able to add new domains.