No description
  • Rust 76.9%
  • JavaScript 13.2%
  • HTML 5.9%
  • CSS 4%
Find a file
Timur Gordon 1533d4bd13
All checks were successful
Build & Test / check (push) Successful in 4m2s
Rename hero_service → hero_lifecycle (#55 downstream) (#54)
2026-05-19 02:31:53 +00:00
.forgejo/workflows ci: install rust 1.95; inline cargo; skip integration tests (need real backend) 2026-05-12 23:18:40 +02:00
.hero chore: add service.toml configs, apply herolib_core service_base pattern, and update build artifacts 2026-05-12 10:33:15 +02:00
crates refactor: replace inline socket/path helpers with herolib_core::base equivalents 2026-05-17 09:18:02 +02:00
docs feat(proxy): per-method authz on management RPC + admin impersonation 2026-05-05 15:34:44 +02:00
.env.example add tls support 2026-02-18 08:07:07 +01:00
.gitignore fix: remove hardcoded /Volumes/T7 [patch] section and add .gitignore entry 2026-05-12 15:38:04 +02:00
Cargo.lock refactor: replace inline socket/path helpers with herolib_core::base equivalents 2026-05-17 09:18:02 +02:00
Cargo.toml Rename hero_service → hero_lifecycle (#55 downstream) (#54) 2026-05-19 02:31:53 +00:00
Cargo.toml.hero_builder_backup chore: apply hero_builder drift fixes — bump deps, add --info/--help, add build artifacts 2026-05-10 14:21:19 +02:00
PURPOSE.md docs: rename hero_proxy_ui → hero_proxy_admin throughout 2026-05-15 07:21:26 +02:00
README.md docs: rename hero_proxy_ui → hero_proxy_admin throughout 2026-05-15 07:21:26 +02:00

Hero Proxy

HTTP/HTTPS reverse proxy and service discovery for the Hero ecosystem. Routes incoming traffic to Hero services via URL-prefix → Unix domain socket forwarding, with TLS termination (self-signed or Let's Encrypt), SSH tunnels, OAuth, and a full management API.

Architecture

Internet / Browser
       │
  :80 (HTTP) / :443 (HTTPS)
       │
  hero_proxy_server
    ├── {domain}/* → ~/hero/var/sockets/{service}/*.sock
    ├── TLS (self-signed or Let's Encrypt / ACME)
    ├── SSH reverse-port tunnels
    ├── OAuth2 / bearer / signature auth per route
    └── OpenRPC JSON-RPC 2.0 management API
              │
       ~/hero/var/sockets/hero_proxy/rpc.sock

Crates

Crate Type Description
hero_proxy binary CLI — registers and starts/stops all services via hero_proc
hero_proxy_server binary TCP proxy + service discovery + OpenRPC API
hero_proxy_admin binary Admin dashboard
hero_proxy_sdk library Auto-generated typed client
weblib library Reusable web / TLS / ACME library

Sockets

All sockets under $HERO_SOCKET_DIR/hero_proxy/ (default ~/hero/var/sockets/hero_proxy/).

Socket Protocol Description
rpc.sock OpenRPC / JSON-RPC 2.0 Management API
admin.sock HTTP Admin dashboard

Ports (TCP)

Port Protocol Description
9997 HTTP Proxy ingress (dev / LAN)
9996 HTTPS Proxy ingress (TLS)
443 HTTPS Production ingress (Let's Encrypt)
80 HTTP Redirect → HTTPS (Let's Encrypt mode)

Service Management

All service lifecycle operations are driven by lab on top of hero_proc.

Install and start

lab service proxy --install   # build + install all declared binaries
lab service proxy --start     # register with hero_proc and start

Stop / restart

lab service proxy --stop
lab service proxy --stop && lab service proxy --start

Status

lab service proxy --status

TLS / ACME Configuration

TLS settings are persisted in the database so they survive restarts without environment variables. DB values always take precedence over env vars.

# Set the domain for Let's Encrypt (required)
proxy system config set --dns-name proxy.example.com

# Set contact email (strongly recommended — expiry notifications)
proxy system config set --acme-email admin@example.com

# Switch to production CA (default is staging — safe to test first)
proxy system config set --acme-production true

# View current effective config and where each value comes from
proxy system config get

# Clear a field (reverts to env var fallback, or unset)
proxy system config remove dns_name

Response from proxy system config get

{
  dns_name:               "proxy.example.com"
  acme_email:             "admin@example.com"
  acme_production:        true
  dns_name_source:        "db"     # db | env | unset
  acme_email_source:      "db"     # db | env | unset
  acme_production_source: "db"     # db | env | default
}

Env var fallbacks (legacy / alternative)

DB key (via API) Environment variable Default
acme_dns_name HERO_PROXY_DNS_NAME — (self-signed)
acme_email HERO_PROXY_ACME_EMAIL — (no email)
acme_production HERO_PROXY_ACME_PRODUCTION false (staging)

Changes take effect the next time a listener with tls_mode=letsencrypt is started. Running listeners are not hot-reloaded — restart the listener after changing config.


Quick-start: public HTTPS with Let's Encrypt

# 1. Install and start the service
lab service proxy --install
lab service proxy --start

# 2. Configure ACME (while service is running — no restart needed for config)
proxy system config set --dns-name proxy.example.com --acme-email admin@example.com
proxy system config set --acme-production true

# 3. Add an HTTPS listener (starts the ACME challenge immediately)
proxy listener add "0.0.0.0:443" --protocol https --tls-mode letsencrypt

# 4. Verify
proxy listener status
proxy tls check proxy.example.com

Quick-start: SSH tunnel to a public server

# Create HTTP + HTTPS + DNS-bridge tunnels in one call and start them
proxy tunnel quick_add edge.example.com admin --auth-key-path ~/.ssh/id_ed25519

# Check status
proxy tunnel status
proxy tunnel check_dns 3

Domain routing

# Route a hostname to a local service socket
proxy domain add app.example.com socket /run/myapp.sock

# Route with bearer-token auth
proxy domain add api.example.com https https://127.0.0.1:9000 --auth-mode bearer

# Route with OAuth (Google)
proxy oauth set google google $CLIENT_ID $CLIENT_SECRET \
    --scopes "openid email profile"
proxy domain add dash.example.com http http://127.0.0.1:8080 \
    --auth-mode oauth --oauth-provider google

# List / inspect routes
proxy domain list
proxy domain get 3

Development

# Fast check without producing a binary
cargo check -p hero_proxy_server

# Run tests
cargo test

# Clippy
cargo clippy --all-targets -- -D warnings

# Format
cargo fmt

Documentation