# Caddy config for digibyte.x — hosts the static wallet bundle AND # reverse-proxies /p2p/ to the local dgb-daemon on the same VPS. # # Trust model: # TLS is a self-signed cert whose SHA-256 is pinned on-chain via the # digibyte.x BNS record (`tls` field). No ACME, no Let's Encrypt. # Wallet clients verify by resolving the name → {ip, tls} and # comparing the observed cert to the pinned fingerprint. # # Runtime shape: # - / and /assets/* → static files from /var/www/dgb-wallet (the # built `dist/` bundle from @dgb-wallet/web-ui) # - /p2p/* → dgb-daemon (127.0.0.1:5174) so Balance/Send # work for visitors without a local daemon # - Everything else → 404 # # Tokens replaced by ops/deploy-wallet.sh: # @CERT_FILE@ path to server.crt (DER SHA-256 goes in the BNS record) # @KEY_FILE@ path to server.key # @SITE_ROOT@ filesystem path to the deployed dist/ bundle # # Rate limiting (caddy-ratelimit plugin) caps abuse — /p2p/balance is # cheap per call but the daemon has finite CPU and finite peer slots. { auto_https off } :443 { tls @CERT_FILE@ @KEY_FILE@ encode zstd gzip header { # Wallet bundle is versioned in-filename; long cache on assets, # never cache the entry HTML (needs to pick up new asset hashes). Cache-Control "no-store" X-Content-Type-Options "nosniff" Referrer-Policy "no-referrer" # CSP: the wallet runs entirely from its own origin; block # everything else. `unsafe-inline` on styles because Vite emits # a tiny inline style block for its own runtime. Content-Security-Policy "default-src 'self'; script-src 'self' 'wasm-unsafe-eval'; style-src 'self' 'unsafe-inline'; connect-src 'self'; img-src 'self' data:; base-uri 'none'; frame-ancestors 'none'" Strict-Transport-Security "max-age=31536000; includeSubDomains" -Server } @assets path /assets/* header @assets Cache-Control "public, max-age=31536000, immutable" # /p2p/* → local dgb-daemon. Strip the /p2p prefix so daemon sees # /health, /balance, /broadcast at the roots it registered. handle_path /p2p/* { # rate_limit { # zone p2p_zone { # key {client.ip} # events 60 # window 1m # } # } reverse_proxy 127.0.0.1:5174 { header_up Host {host} header_up X-Real-IP {remote_host} header_up X-Forwarded-For {remote_host} transport http { keepalive 30s keepalive_idle_conns 4 } } } # Static site — SPA fallback so any unknown path serves index.html # (the tabs are all client-side; no routing to break). handle { root * @SITE_ROOT@ try_files {path} /index.html file_server } log { output stdout format json level INFO } }