Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -229,14 +229,18 @@ log_path = "/home/user/.hermes-node/audit.log"
# One of: debug, info, warn, error
log_level = "debug"

# Reconnect backoff (defaults shown)
# Proxy: optional HTTP(S) proxy for the WebSocket connection.
# When set, overrides HTTPS_PROXY / HTTP_PROXY env vars.
proxy_url = "http://proxy.corp.example:8080"

# Reconnect backoff: fine-tune the exponential backoff for
# transient network drops. The defaults work for most setups.
backoff_initial = "1s" # default; Go duration, e.g. "500ms", "5s"
backoff_max = "60s" # default; maximum delay between retries
backoff_factor = 2.0 # default; multiplier per retry

# Proxy: hermes-node respects HTTPS_PROXY / HTTP_PROXY / NO_PROXY
# env vars automatically. No config field needed — just set them
# in the shell before running `hermes-node run`.
# Proxy: set proxy_url above, or use HTTPS_PROXY / HTTP_PROXY / NO_PROXY
# env vars for env-level config.
```

### `[server]` section
Expand Down Expand Up @@ -333,7 +337,7 @@ Quick summary:

- **Q: Can I reload config without restarting?** A: Send `SIGHUP` to the daemon process to reload `log_level`. Other changes require a restart.

- **Q: Does the node support HTTP proxies?** A: Yes. The WebSocket client respects the standard `HTTPS_PROXY`, `https_proxy`, `HTTP_PROXY`, `http_proxy`, and `NO_PROXY` environment variables automatically. For Basic auth, include credentials in the URL: `http://user:password@proxy:port`. For NTLM/Kerberos proxies, use a local authenticating proxy bridge (e.g. `cntlm`).
- **Q: Does the node support HTTP proxies?** A: Yes. Set `proxy_url` in `config.toml` under `[node]`, or use the standard `HTTPS_PROXY`/`HTTP_PROXY` env vars. For Basic auth, include credentials in the URL: `http://user:password@proxy:port`. For NTLM/Kerberos proxies, use a local authenticating proxy bridge (e.g. `cntlm`).

- **Q: What does `--version` show?** A: The version, Go version, commit SHA, and build date. Example: `hermes-node v0.1.0 go1.26.3 abc12345 2026-06-22`.

Expand Down
17 changes: 17 additions & 0 deletions cmd/hermes-node/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"fmt"
"io"
"net/http"
"net/url"
"os"
"os/exec"
"os/signal"
Expand Down Expand Up @@ -699,6 +700,21 @@ func runValidate(args []string, configPath string, stdout, stderr io.Writer) int
}
// If no TLS settings are configured, that's fine — no check needed.

// 5. Proxy URL — validate the URL when set.
if cfg.Node.ProxyURL != "" {
proxyURL, err := url.Parse(cfg.Node.ProxyURL)
if err != nil {
fmt.Fprintf(stdout, " [FAIL] proxy_url: %v\n", err)
failed++
} else if proxyURL.Scheme != "http" && proxyURL.Scheme != "https" {
fmt.Fprintf(stdout, " [FAIL] proxy_url: scheme %q must be http or https\n", proxyURL.Scheme)
failed++
} else {
fmt.Fprintf(stdout, " [OK] proxy_url: %s\n", cfg.Node.ProxyURL)
passed++
}
}

if failed == 0 {
fmt.Fprintf(stdout, "\nhermes-node: config is valid (%d checks passed).\n", passed)
return 0
Expand Down Expand Up @@ -809,6 +825,7 @@ func runRun(ctx context.Context, configPath string, stdout, stderr io.Writer) in
Arch: runtime.GOARCH,
Capabilities: []string{"exec", "read", "write"},
TLSConfig: tlsCfg,
ProxyURL: cfg.Node.ProxyURL,
})
},
// Setup is invoked once per (re)connect. We build a fresh
Expand Down
1 change: 1 addition & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ type NodeConfig struct {
AllowedPaths []string `toml:"allowed_paths"`
LogPath string `toml:"log_path"`
LogLevel string `toml:"log_level"`
ProxyURL string `toml:"proxy_url"`
BackoffInitial string `toml:"backoff_initial"`
BackoffMax string `toml:"backoff_max"`
BackoffFactor float64 `toml:"backoff_factor"`
Expand Down
15 changes: 15 additions & 0 deletions internal/wire/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"crypto/tls"
"errors"
"fmt"
"net/http"
"net/url"
"time"

Expand Down Expand Up @@ -97,6 +98,13 @@ type DialOptions struct {
// handed over. A future maintainer should not construct a
// per-call closure here.
TLSConfig *tls.Config

// ProxyURL is an optional HTTP(S) proxy URL for the WebSocket
// dialer. When set, it overrides the HTTP_PROXY / HTTPS_PROXY
// environment variables. Leave empty to use the default
// proxy-from-environment behaviour (ProxyFromEnvironment).
// Example: "http://proxy.corp.example:8080".
ProxyURL string
}

// withDefaults returns a copy of opts with zero-valued fields filled
Expand Down Expand Up @@ -166,6 +174,13 @@ func Connect(ctx context.Context, opts DialOptions) (*Client, error) {
if opts.TLSConfig != nil {
dialer.TLSClientConfig = opts.TLSConfig
}
if opts.ProxyURL != "" {
proxyURL, err := url.Parse(opts.ProxyURL)
if err != nil {
return nil, fmt.Errorf("wire: parse proxy_url: %w", err)
}
dialer.Proxy = http.ProxyURL(proxyURL)
}
conn, _, err := dialer.DialContext(wsCtx, opts.ServerURL, nil)
if err != nil {
return nil, fmt.Errorf("wire: dial %s: %w", opts.ServerURL, err)
Expand Down
Loading