No description
- Rust 65.4%
- JavaScript 12.8%
- HTML 11%
- Shell 6.5%
- CSS 3.7%
- Other 0.6%
- Rename all socket directory references from hero_proxy_server/ and hero_proxy_ui/ to hero_proxy/ to comply with the hero_sockets convention (service name, not binary name, is used for the socket directory) - Fix well-known discovery manifests: use correct service name "hero_proxy", protocol "ui" for the UI socket, and add missing "socket" field - Update hero_proxy_sdk default_socket_path() to match new layout - Add service/context filtering to role-based claim resolution (authz) - Update admin dashboard UI and dashboard.js with latest improvements - Run cargo update to pull latest dependency versions Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|---|---|---|
| .forgejo/workflows | ||
| _archive | ||
| crates | ||
| patches/rustls-acme-0.15.1 | ||
| scripts | ||
| .env.example | ||
| .gitignore | ||
| buildenv.sh | ||
| Cargo.lock | ||
| Cargo.toml | ||
| Makefile | ||
| README.md | ||
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.
Architecture
┌───────────────────────────────────────────────────────────┐
│ Internet / Browser │
│ │ │
│ :9997 (HTTP) / :9996 (HTTPS) │
│ │ │
│ hero_proxy_server (TCP listener + service discovery) │
│ /{service}/* → ~/hero/var/sockets/{service}.sock │
│ │ │
│ Unix sockets (all Hero services) │
│ hero_osis_ui.sock, hero_embedder_ui.sock, ... │
└───────────────────────────────────────────────────────────┘
Crates
| Crate | Type | Description |
|---|---|---|
hero_proxy_server |
binary | TCP proxy + service discovery + OpenRPC management API |
hero_proxy_ui |
binary | Admin dashboard (Unix socket only) |
hero_proxy_sdk |
library | Auto-generated typed client for the management API |
hero_proxy |
binary | CLI — registers and starts/stops both services via hero_proc |
hero_proxy_examples |
examples | Example programs using the SDK |
hero_proxy_tests |
library | Integration tests for the server and proxy |
weblib |
library | Reusable web server library (proxy, TLS, certs, ACME) |
Sockets
| Socket | Service | Protocol |
|---|---|---|
~/hero/var/sockets/hero_proxy_server.sock |
Management API | OpenRPC/JSON-RPC 2.0 |
~/hero/var/sockets/hero_proxy_ui.sock |
Admin dashboard | HTTP |
Ports (TCP — proxy gateway only)
| Port | Protocol | Description |
|---|---|---|
| 9997 | HTTP | Reverse proxy ingress |
| 9996 | HTTPS | Reverse proxy ingress (TLS) |
| 80 | HTTP | Redirect to HTTPS (Let's Encrypt mode only) |
Quick Start
# Build and start both services
make run
# View logs
make logs # hero_proxy_server logs
make logs-ui # hero_proxy_ui logs
# Stop services
make stop
Service Routing
The proxy routes by URL prefix to Unix sockets in ~/hero/var/sockets/:
http://localhost:9997/hero_osis/ → hero_osis_ui.sock
http://localhost:9997/hero_embedder/ → hero_embedder_ui.sock
http://localhost:9997/hero_inspector/ → hero_inspector_ui.sock
Socket lookup order for /{name}/:
{name}.sock(exact, not_server){name}_http.sock{name}_ui.sock- If
{name}ends with_server→ strip and try{name_base}_ui.sock {name}_server.sock(last resort — OpenRPC backend)
Configuration
Set in environment or .env:
| Variable | Default | Description |
|---|---|---|
HERO_DIR |
~/hero |
Root directory for sockets and certs |
HERO_AUTH_TOKEN |
(unset = dev mode) | Bearer token for auth |
HERO_PROXY_DNS_NAME |
(unset = self-signed) | Domain for Let's Encrypt |
HERO_PROXY_ACME_EMAIL |
— | Contact email for ACME |
HERO_PROXY_ACME_PROD |
false |
true = production Let's Encrypt |
HERO_PROXY_DEFAULT_SERVICE |
— | Redirect / to this service |
HERO_PROXY_UI_SOCKET |
auto | Override UI socket path |
TLS
- Self-signed (default): auto-generated on first start, stored in
~/hero/var/certs/ - Let's Encrypt: set
HERO_PROXY_DNS_NAME=your.domain.com— requires port 443 publicly reachable
Management API
The server exposes an OpenRPC 2.0 API over hero_proxy_server.sock:
| Method | Description |
|---|---|
rpc.health |
Health check |
rpc.discover |
OpenRPC spec |
proxy.list_services |
All discovered services with status |
proxy.list_sockets |
Socket file paths |
proxy.stop_endpoint(name) |
Block traffic to a service (503) |
proxy.start_endpoint(name) |
Re-enable a blocked service |
proxy.list_stopped |
Currently blocked endpoints |
domain.* |
Domain route CRUD (list, get, add, update, remove) |
tls.* |
TLS certificate management (list, set, remove, check) |
dns.* |
DNS zone and record management |
oauth.* |
OAuth provider configuration |
listener.* |
TCP listener management (list, add, remove, status) |
tunnel.* |
SSH remote port forwarding tunnels (list, get, add, update, remove, start, stop, status) |
settings.* |
Server settings (get, set, list) |
SSH Remote Port Forwarding
The proxy supports managed reverse SSH tunnels via the tunnel.* RPC methods. This allows exposing local services through remote SSH servers:
internet → remote-ssh-server:port → (SSH tunnel) → local proxy
Configure tunnels via the admin UI "Tunnels" tab or the SDK:
client.tunnel_add(TunnelAddInput {
name: "my-tunnel".into(),
ssh_host: "jump.example.com".into(),
ssh_user: "tunnel".into(),
auth_key_path: "~/.ssh/id_ed25519".into(),
remote_port: 9000,
local_target_addr: "127.0.0.1:9997".into(),
..Default::default()
}).await?;
Tunnels auto-reconnect with exponential backoff and can be set to auto-start on server boot.
Using the SDK
use hero_proxy_sdk::{HeroProxyServerClient, RpcHealthInput, ProxyListServicesInput};
let client = HeroProxyServerClient::connect_default().await?;
let health = client.rpc_health(RpcHealthInput {}).await?;
let services = client.proxy_list_services(ProxyListServicesInput {}).await?;
Development
make check # cargo check
make test # cargo test
make lint # clippy
make fmt # rustfmt
make rundev # debug build, direct execution
Installation
make install # build release + copy to ~/hero/bin/
Add ~/hero/bin to your $PATH:
echo 'export PATH="$HOME/hero/bin:$PATH"' >> ~/.bashrc