diff --git a/caddy/Caddyfile b/caddy/Caddyfile index 2668fa6..b11c046 100644 --- a/caddy/Caddyfile +++ b/caddy/Caddyfile @@ -1,22 +1,57 @@ # Caddy fronts the whole Hephaestus stack. -# - Automatic Let's Encrypt cert for code.silentmode.st (HTTP-01 challenge on :80) -# - Path-based routing: -# /auth/* → auth-proxy container (prefix stripped before forwarding) -# / → Forgejo container -# - HTTPS-only for browser traffic; SSH git access stays on port 2222 outside Caddy. # -# {$SITE_HOSTNAME} is provided by docker-compose from .env (SITE_HOSTNAME). +# TWO HOSTNAMES: +# code.silentmode.st Traditional DNS + Let's Encrypt HTTP-01 cert. Same as before. +# hephaestus.x BCNR name (chipnet). TLS cert issued by Silent Mode's own +# root CA (Argonautica) — trusted by Theseus/Ariadne users; +# other browsers see a self-signed-style warning. hephaestus.x +# also serves static content from /srv/hephaestus.x/* (the +# landing pages) BEFORE falling through to Forgejo, so +# marketing/docs pages don't get eaten by Forgejo's routes. +# +# ROUTING (both hostnames): +# /auth/* → auth-proxy container (prefix stripped) +# / → Forgejo container (with per-hostname behaviour below) +# +# {$SITE_HOSTNAME} comes from docker-compose .env (SITE_HOSTNAME=code.silentmode.st). +# --- code.silentmode.st: unchanged from before --- {$SITE_HOSTNAME} { encode gzip zstd - # Auth-proxy under /auth/*. handle_path STRIPS the /auth prefix before proxying, - # so /auth/challenge upstream is just /challenge on auth-proxy. handle_path /auth/* { reverse_proxy auth-proxy:4000 } - # Everything else → Forgejo. Big body size so git push + LFS + release uploads work. + handle { + reverse_proxy forgejo:3000 + request_body { + max_size 2GB + } + } +} + +# --- hephaestus.x: static-first, Forgejo-fallback, Silent Mode CA cert --- +hephaestus.x { + encode gzip zstd + + # TLS cert from Silent Mode's Argonautica CA (name-constrained to permitted TLDs). + # Theseus + Ariadne users have this CA in their trust store per the setup docs. + tls /etc/caddy/certs/hephaestus.x.crt /etc/caddy/certs/hephaestus.x.key + + handle_path /auth/* { + reverse_proxy auth-proxy:4000 + } + + # Static-file-first, Forgejo-fallback. If /srv/hephaestus.x/{path} (or {path}/index.html) + # exists, serve it. Otherwise the request falls through to Forgejo so all git/api/user + # routes still work. + root * /srv/hephaestus.x + @static file {path} {path}index.html {path}/index.html + handle @static { + try_files {path} {path}index.html {path}/index.html + file_server + } handle { reverse_proxy forgejo:3000 request_body { diff --git a/docker-compose.yml b/docker-compose.yml index aefadf4..30193b1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,7 +9,10 @@ services: environment: SITE_HOSTNAME: ${SITE_HOSTNAME} volumes: - - ./caddy/Caddyfile:/etc/caddy/Caddyfile:ro + # Mount the whole caddy/ dir so both Caddyfile AND certs/ are accessible. + - ./caddy:/etc/caddy:ro + # Static content for hephaestus.x — landing pages served before falling through to Forgejo. + - /var/www/hephaestus.x:/srv/hephaestus.x:ro - caddy-data:/data - caddy-config:/config depends_on: diff --git a/scripts/sync-hephaestus-x-to-sia.sh b/scripts/sync-hephaestus-x-to-sia.sh new file mode 100644 index 0000000..21d1b37 --- /dev/null +++ b/scripts/sync-hephaestus-x-to-sia.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +# sync-hephaestus-x-to-sia.sh — nightly disaster-recovery backup of the +# static hephaestus.x content from VPS to the Sia bucket. +# +# The BCNR record on hephaestus.x currently points at the VPS via `ip:` only, +# so users route through this VPS. This script keeps a parallel copy on Sia +# for disaster recovery: if the VPS dies, updating the BCNR record from +# `ip:` back to `s3:"bns/hephaestus.x/"` (single Argus CLI call) restores +# service from the Sia bucket in the time it takes for one BCH transaction +# to confirm on chipnet. +# +# Runs on the p2pexchange VPS via systemd timer (hephaestus-x-sia-sync.timer). +set -euo pipefail + +cd "$(dirname "$0")/.." # → /root/hephaestus +set -a; source .env; set +a + +: "${SIA_STORAGE_ENDPOINT:?}" +: "${SIA_STORAGE_ACCESS_KEY:?}" +: "${SIA_STORAGE_SECRET_KEY:?}" + +# Use rclone with an inline S3 remote — no config file needed. +export RCLONE_CONFIG_SIA_TYPE=s3 +export RCLONE_CONFIG_SIA_PROVIDER=Other +export RCLONE_CONFIG_SIA_ENDPOINT="https://${SIA_STORAGE_ENDPOINT}" +export RCLONE_CONFIG_SIA_ACCESS_KEY_ID="$SIA_STORAGE_ACCESS_KEY" +export RCLONE_CONFIG_SIA_SECRET_ACCESS_KEY="$SIA_STORAGE_SECRET_KEY" +export RCLONE_CONFIG_SIA_REGION=us-east-1 + +echo "[$(date -u +%FT%TZ)] syncing /var/www/hephaestus.x/ → sia:bns/hephaestus.x/" +rclone sync /var/www/hephaestus.x/ sia:bns/hephaestus.x/ --checksum + +echo "[$(date -u +%FT%TZ)] done. bucket contents:" +rclone size sia:bns/hephaestus.x/