dgb-wallet/ops/Caddyfile.wallet
Digibyte.X d50286a9a5 DigiByte.X Wallet — recovery-first web wallet monorepo
Packages: core (BIP39/32/44/49/84/86 derivation, WIF), keystore (PBKDF2 +
AES-GCM), psbt, p2p (BIP157/158 SPV daemon, Dandelion++ broadcast with
relay-echo verification), blockbook, rpc, electrum, net, bns, web-ui
(React/Vite), mobile (Expo). ops/ holds the nginx vhost, systemd unit and
push.sh deploy script for digibyte.x/web.
2026-09-20 20:16:52 +02:00

85 lines
2.9 KiB
Text

# 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
}
}