Silent Mode Hephaestus — the docker-compose + Caddyfile + auth-proxy that runs code.silentmode.st and hephaestus.x. BCH wallet auth via OIDC, Sia cold storage, restic backups. Open source.
Site: - Rename the "Tools" nav label to "Theseus" on every subpage. URL slug /tools/ is kept intact so bookmarks and cross-links survive; the page's own title + h1 rename to Theseus; homepage product card retitled. - Remove the /tlds/ self-nav entry so its 7-item header matches every other subpage (was 8 items, causing the same "header rearranges" glitch Hephaestus had before). Auth-proxy (fixes reported by a concurrent session working with a chipnet wallet): - verify.ts now auto-detects the CashAddr prefix (bitcoincash, bchtest, bchreg) instead of hardcoding "bitcoincash". Chipnet wallets sign the same message with the same key but display bchtest: addresses; the old code compared their claim against a re-encoded bitcoincash: version and always rejected. Same key material, different envelope. - /challenge accepts any of the three known prefixes at the input gate. - /verify accepts an optional `state` param in the request body — used as a fallback if the challenge record didn't carry one (which happens when a scripted caller runs the /verify step without passing state through /challenge). Ensures RFC 6749 §4.1.2 compliance: the OAuth callback URL always echoes state when the client provided one. |
||
|---|---|---|
| auth-proxy | ||
| caddy | ||
| scripts | ||
| .env.example | ||
| docker-compose.yml | ||
| PROTOCOL.md | ||
| README.md | ||
Hephaestus
Decentralized code forge. Forgejo web UI on a VPS, Sia network for durable storage, Bitcoin Cash wallet signatures for identity — no email required.
Architecture
User browser
│
├── OIDC login via wallet signature ──▶ auth-proxy ──▶ (issues id_token)
│ │
└── Forgejo web UI ◀─── OIDC handshake ────────────────────┘
│
├── live git repos, Postgres ──▶ local SSD on VPS (hot path)
└── LFS, attachments, packages,
archive downloads, backups ──▶ sia.storage S3 (cold path)
- Identity: users generate or import a BCH wallet client-side. Their
cashaddris their username. Login = signing a challenge. - Hot storage: live
.gitbare repos + Postgres live on the VPS's local disk. Git operations stay fast. - Cold storage: every large or immutable blob (LFS, attachments, release artifacts, package registries) lives on sia.storage via its S3-compatible endpoint. Forgejo speaks S3 natively.
- Backups: nightly
resticsnapshot of repos +pg_dumpto a second bucket. Dual-write to independent storage for the belt-and-suspenders story since sia.storage caps liability at ~$100.
Why sia.storage instead of self-hosted renterd for MVP
- Their free tier gives 50 GB pooled + 4 Gbps throughput with no monthly egress meter
- Standard S3 API — zero code changes to Forgejo
- No Sia wallet management, no SC volatility, no contract-formation ops
- Swap to self-hosted
renterdlater without touching Forgejo config (both speak S3)
Quota math
The 50 GB sia.storage free tier is one pooled resource we allocate to Forgejo users via Forgejo's built-in per-user quotas.
| Our tier | Per-user quota | Users on Free (50 GB) | Users on Plus (500 GB) | Users on Pro (5 TB) |
|---|---|---|---|---|
| Free | 500 MB | ~100 | ~1,000 | ~10,000 |
| Pro | 10 GB | ~5 | ~50 | ~500 |
| Team | 50 GB | ~1 | ~10 | ~100 |
Quickstart
cp .env.example .env
# fill in SIA_STORAGE_ACCESS_KEY, SIA_STORAGE_SECRET_KEY, SIA_STORAGE_BUCKET
docker compose up -d
open http://localhost:3000
First launch:
- Forgejo initialises Postgres and its schema
- Auth-proxy generates its OIDC signing keypair
- On first browser visit, the login page offers "Generate new BCH wallet" or "Import wallet"
- After signing the challenge you're logged into Forgejo — your cashaddr is your username
Directory layout
Hephaestus/
├── docker-compose.yml # forgejo + postgres + auth-proxy
├── .env.example
├── forgejo/
│ └── app.ini.template # config with sia.storage S3 + OIDC + quotas
├── auth-proxy/
│ ├── Dockerfile
│ ├── package.json
│ └── src/ # Fastify OIDC provider
│ ├── index.ts
│ ├── oidc.ts
│ ├── verify.ts # BCH signed-message verification
│ └── sessions.ts
├── auth-proxy/public/
│ ├── login.html # Wallet UI
│ └── wallet.js # Client-side keygen + signing (libauth)
├── scripts/
│ ├── smoke-test-s3.sh # Verify sia.storage handles multipart LFS
│ └── backup-restic.sh # Nightly backup
└── PROTOCOL.md # Wallet-auth flow spec
Status
- MVP scaffolding: complete
- Wallet auth: functional (challenge + signature verify, no persistence beyond cashaddr)
- sia.storage backend: config template ready; must run
scripts/smoke-test-s3.shbefore trusting LFS - Restic backup: template ready, needs cron wiring
- WalletConnect: deferred to Phase 2
- BCNR-name registration for
code.silentmode.st: separate task in Ariadne stack
Known unknowns
- sia.storage S3 multipart maturity. Their roadmap targets full S3 compatibility Q3 2026 — partial today. Smoke test verifies this before we depend on it for LFS.
- Account-recovery UX for wallet loss. No email = no password reset. Users must back up their mnemonic. Docs will hammer this. Phase 2: social recovery via BCH multisig.
- Content moderation workflow. sia.storage ToS bans certain content classes; we need our own AUP + takedown flow before public launch.