eva 646904ff0a
Format / gofmt (pull_request) Successful in 16s
CI / Build (pull_request) Successful in 24s
Format / gofmt (push) Successful in 14s
CI / Go Tests (pull_request) Successful in 1m0s
CI / Build (push) Successful in 25s
CI / Go Tests (push) Successful in 1m0s
helix-proxy: Promote develop to master
helix-proxy: Promote develop to master
2026-09-02 13:28:38 -05:00
2026-06-06 07:54:44 -05:00
2026-09-01 18:54:34 +00:00
2026-08-31 20:08:49 -05:00
2026-08-31 20:08:49 -05:00
2026-06-06 07:54:44 -05:00
2026-09-01 00:03:28 +00:00
2026-06-06 07:54:44 -05:00

Helix Proxy

A pure-Go reverse proxy with embedded web UI. Supports proxy hosts, TCP/UDP streams, redirections, dead hosts, certificates (Let's Encrypt + custom), access lists, audit, and more. Single static binary. Single built-in admin (no multi-user registration). Production requires ADMIN_PASSWORD on first boot (the well-known default "password" is rejected); development may leave it unset until you change it (bootstrap lock).

Key features / differences from traditional setups:

  • Entirely replaces nginx: pure Go reverse proxy (http) + TCP/UDP stream proxy engine. No nginx binary, no config files on disk for routing, live updates.
  • Single binary: the modern Svelte SPA UI is built and embedded (//go:embed) into the Go executable.
  • Storage: default is a single data/db.bolt (cwd-relative, bbolt embedded).
  • No magic paths: everything defaults to paths relative to the process CWD (data/db.bolt, data/www/, data/certs/, ...). All overridable with env vars (DATA_DIR, WWW_DIR, etc.).
  • www/html lives in data/ by default (single volume tree).

Quick start (binary)

make          # builds UI (placeholder) + Go binary with embed
ADMIN_PASSWORD='choose-a-real-password' ./helix-proxy
# Defaults (overridable via env):
#   Admin UI + API: 127.0.0.1:8081  (ADMIN_HOST / ADMIN_PORT)
#   Proxy HTTP:     :8080           (PROXY_HTTP_PORT)
#   Proxy HTTPS:    :18443          (PROXY_HTTPS_PORT)

Visit http://127.0.0.1:8081

Data (db, certs, logs, www html) lives in ./data relative to where you ran the binary.

docker compose up -d
# compose sets ADMIN_PORT=81 PROXY_HTTP_PORT=80 PROXY_HTTPS_PORT=443
# proxy :80/:443 published; admin binds 127.0.0.1:81 (not published by default)
# or
docker build -t helix-proxy:dev .
docker run --env ADMIN_PASSWORD='choose-a-real-password' \
  -p 80:80 -p 443:443 \
  -e ADMIN_PORT=81 -e PROXY_HTTP_PORT=80 -e PROXY_HTTPS_PORT=443 \
  -v $PWD/data:/app/data --workdir /app helix-proxy:dev

Publishing admin (-p 81:81) also needs -e ADMIN_HOST=0.0.0.0. Do not publish :81 on untrusted networks. Without those env overrides the binary still defaults to admin 127.0.0.1:8081 and proxy :8080 / :18443 inside the container.

PUID/PGID + DISABLE_IPV6 example (see docker-compose.yml for full):

# user: "0:0"  # root to allow chown+drop inside
environment:
  - PUID=1000
  - PGID=1000
  - DISABLE_IPV6=1
  # PUID_NO_DROP=1  # for low ports (80/443) + PUID: do chown as root but do not drop (stay root to bind low ports; default with PUID drops to non-root after chown, so use high ports or NET_BIND_SERVICE cap or run without PUID for low ports)

Binary auto-chowns data tree (if started root) then drops privs (unless PUID_NO_DROP); umask support via UMASK env. Files 0600, dirs 0755. Note: privilege drop happens early (before listeners); low-port binds require either root (with PUID_NO_DROP), capabilities, high ports in config, or external setuid wrapper.

See docker-compose.yml for a full example (ADMIN_PORT=81 / proxy 80/443 via env; publishes 80/443; admin stays on loopback unless you set ADMIN_HOST / publish the admin port).

Paths (all overridable)

  • data/db.bolt (or DATA_DIR)
  • data/certs/, data/logs/, data/letsencrypt-acme-challenge/
  • data/www/ (default site / custom html; WWW_DIR or HTML_DIR)
  • data/.jwt_secret (auto-generated admin API signing key if JWT_SECRET is unset)
  • etc.

Status

Core features implemented and verified:

  • cwd-relative + env-overridable paths/storage (single data/db.bolt primary via bbolt)
  • pure-Go engine: proxy hosts (full: locations, advanced_config parser, ssl_forced, block_exploits, websocket, hsts, caching w/ HIT/MISS, access lists, custom certs, LE), streams (tcp/udp +ssl term), redirection hosts (full forward_http_code/preservePath/scheme + CRUD), dead hosts (per-dead custom content + CRUD)
  • certificates: custom PEM (meta keys compat) + full Let's Encrypt issuance/renewal via lego (http-01). In PROXY_MODE=development all LE certs are self-signed test certs (domain-based sim tricks removed).
  • single admin (ADMIN_PASSWORD required in production; default "password" refused; hashed + stored in DB; no registration or multi-user)
  • audit (userId=1), settings (default_site + letsencrypt_email etc)
  • live reload on all CRUD, dual https/http + SNI, embedded Svelte SPA (full tabs, pickers, edits)
  • single binary (go build embeds UI after make ui-build), docker multi-stage + full PUID/PGID/umask
  • no nginx, no .conf files, no external processes for proxying

LE note: for real certs use a public DNS domain pointing at your server (port 80/http reachable). By default (production), real LE http-01 is used. Set PROXY_MODE=development and all letsencrypt cert requests will produce self-signed test certs instead (for dev/testing). Real LE will be used otherwise (requires valid email, port 80 reachable etc).

Development

  • make ui-build (once real Svelte UI added to ui/)
  • make
  • make docker

Contributions / v2 features: open an issue or just ask to implement the next piece (advanced config, full certs with lego, streams, full Svelte UI, SQL backend, etc.).

S
Description
No description provided
Readme MIT 7.8 MiB
Languages
Go 72.3%
Svelte 24.9%
TypeScript 1.1%
Makefile 0.6%
Dockerfile 0.5%
Other 0.6%