A community based topic aggregation platform built on atproto
1# Coves Production Caddyfile 2# Handles HTTPS for both coves.social (AppView) and coves.me (PDS) 3# 4# Domain architecture: 5# - coves.social: AppView (API, web app) 6# - *.coves.social: Community handles (route atproto-did to PDS) 7# - pds.coves.me: PDS canonical hostname (for relay registration) 8# - coves.me: PDS legacy hostname (kept for compatibility) 9 10# Community handle subdomains (e.g., gaming.coves.social) 11# These need to route /.well-known/atproto-did to PDS for handle resolution 12# 13# NOTE: Wildcard certs require DNS challenge. For Cloudflare: 14# 1. Create API token with Zone:DNS:Edit permissions 15# 2. Set CLOUDFLARE_API_TOKEN environment variable 16# 3. Use caddy-dns/cloudflare plugin (see docker-compose.prod.yml) 17*.coves.social { 18 tls { 19 dns cloudflare {env.CLOUDFLARE_API_TOKEN} 20 } 21 # Handle resolution - proxy to PDS 22 handle /.well-known/atproto-did { 23 reverse_proxy pds:3000 24 } 25 26 # OAuth well-known endpoints - proxy to PDS 27 handle /.well-known/oauth-protected-resource { 28 reverse_proxy pds:3000 29 } 30 31 handle /.well-known/oauth-authorization-server { 32 reverse_proxy pds:3000 33 } 34 35 # All other requests return 404 (subdomains only exist for handle resolution) 36 handle { 37 respond "Not Found" 404 38 } 39 40 # Security headers 41 header { 42 Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" 43 X-Content-Type-Options "nosniff" 44 -Server 45 } 46} 47 48# AppView Domain (root) 49coves.social { 50 # Serve .well-known files for DID verification 51 handle /.well-known/* { 52 header Access-Control-Allow-Origin "*" 53 root * /srv 54 file_server 55 } 56 57 # Serve OAuth client metadata 58 handle /client-metadata.json { 59 root * /srv 60 file_server 61 } 62 63 # Serve OAuth callback page 64 handle /oauth/callback { 65 root * /srv 66 rewrite * /oauth/callback.html 67 file_server 68 } 69 70 # Proxy all other requests to AppView 71 handle { 72 reverse_proxy appview:8080 { 73 # Health check 74 health_uri /xrpc/_health 75 health_interval 30s 76 health_timeout 5s 77 78 # Headers for proper DPoP verification 79 # Host headers are critical for DPoP htu (HTTP URI) matching 80 header_up Host {host} 81 header_up X-Real-IP {remote_host} 82 header_up X-Forwarded-For {remote_host} 83 header_up X-Forwarded-Proto {scheme} 84 header_up X-Forwarded-Host {host} 85 } 86 } 87 88 # Logging (Docker captures stdout/stderr) 89 log { 90 output stdout 91 format json 92 } 93 94 # Security headers 95 header { 96 Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" 97 X-Content-Type-Options "nosniff" 98 X-Frame-Options "DENY" 99 Referrer-Policy "strict-origin-when-cross-origin" 100 Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; connect-src 'self' https://*.bsky.network wss://*.bsky.network" 101 # Remove Server header 102 -Server 103 } 104 105 # Enable compression 106 encode gzip zstd 107} 108 109# PDS Domain (both hostnames point to same PDS) 110# pds.coves.me is the canonical hostname for relay registration 111pds.coves.me, coves.me { 112 reverse_proxy pds:3000 { 113 # Health check 114 health_uri /xrpc/_health 115 health_interval 30s 116 health_timeout 5s 117 118 # Headers for proper client IP handling 119 header_up Host {host} 120 header_up X-Real-IP {remote_host} 121 header_up X-Forwarded-For {remote_host} 122 header_up X-Forwarded-Proto {scheme} 123 124 # Note: Caddy v2 handles WebSocket upgrades automatically 125 # No need for explicit Connection/Upgrade headers 126 } 127 128 # Logging (Docker captures stdout/stderr) 129 log { 130 output stdout 131 format json 132 } 133 134 # Security headers 135 header { 136 Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" 137 X-Content-Type-Options "nosniff" 138 X-Frame-Options "DENY" 139 Referrer-Policy "strict-origin-when-cross-origin" 140 -Server 141 } 142 143 # Enable compression 144 encode gzip zstd 145}