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# - coves.me: PDS (data storage) 8 9# Community handle subdomains (e.g., gaming.coves.social) 10# These need to route /.well-known/atproto-did to PDS for handle resolution 11# 12# NOTE: Wildcard certs require DNS challenge. For Cloudflare: 13# 1. Create API token with Zone:DNS:Edit permissions 14# 2. Set CLOUDFLARE_API_TOKEN environment variable 15# 3. Use caddy-dns/cloudflare plugin (see docker-compose.prod.yml) 16*.coves.social { 17 tls { 18 dns cloudflare {env.CLOUDFLARE_API_TOKEN} 19 } 20 # Handle resolution - proxy to PDS 21 handle /.well-known/atproto-did { 22 reverse_proxy pds:3000 23 } 24 25 # OAuth well-known endpoints - proxy to PDS 26 handle /.well-known/oauth-protected-resource { 27 reverse_proxy pds:3000 28 } 29 30 handle /.well-known/oauth-authorization-server { 31 reverse_proxy pds:3000 32 } 33 34 # All other requests return 404 (subdomains only exist for handle resolution) 35 handle { 36 respond "Not Found" 404 37 } 38 39 # Security headers 40 header { 41 Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" 42 X-Content-Type-Options "nosniff" 43 -Server 44 } 45} 46 47# AppView Domain (root) 48coves.social { 49 # Serve .well-known files for DID verification 50 handle /.well-known/* { 51 root * /srv 52 file_server 53 } 54 55 # Serve OAuth client metadata 56 handle /client-metadata.json { 57 root * /srv 58 file_server 59 } 60 61 # Serve OAuth callback page 62 handle /oauth/callback { 63 root * /srv 64 rewrite * /oauth/callback.html 65 file_server 66 } 67 68 # Proxy all other requests to AppView 69 handle { 70 reverse_proxy appview:8080 { 71 # Health check 72 health_uri /xrpc/_health 73 health_interval 30s 74 health_timeout 5s 75 76 # Headers 77 header_up X-Real-IP {remote_host} 78 header_up X-Forwarded-For {remote_host} 79 header_up X-Forwarded-Proto {scheme} 80 } 81 } 82 83 # Logging (Docker captures stdout/stderr) 84 log { 85 output stdout 86 format json 87 } 88 89 # Security headers 90 header { 91 Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" 92 X-Content-Type-Options "nosniff" 93 X-Frame-Options "DENY" 94 Referrer-Policy "strict-origin-when-cross-origin" 95 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" 96 # Remove Server header 97 -Server 98 } 99 100 # Enable compression 101 encode gzip zstd 102} 103 104# PDS Domain 105coves.me { 106 reverse_proxy pds:3000 { 107 # Health check 108 health_uri /xrpc/_health 109 health_interval 30s 110 health_timeout 5s 111 112 # Headers for proper client IP handling 113 header_up X-Real-IP {remote_host} 114 header_up X-Forwarded-For {remote_host} 115 header_up X-Forwarded-Proto {scheme} 116 117 # WebSocket support for firehose 118 header_up Connection {>Connection} 119 header_up Upgrade {>Upgrade} 120 } 121 122 # Logging (Docker captures stdout/stderr) 123 log { 124 output stdout 125 format json 126 } 127 128 # Security headers 129 header { 130 Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" 131 X-Content-Type-Options "nosniff" 132 X-Frame-Options "DENY" 133 Referrer-Policy "strict-origin-when-cross-origin" 134 -Server 135 } 136 137 # Enable compression 138 encode gzip zstd 139}