From 6615cc218ed3c9bb515dbc4b199de58ecbb134f0 Mon Sep 17 00:00:00 2001 From: s1d3sw1ped_bot <12+s1d3sw1ped_bot@git.s1d3sw1ped.com> Date: Tue, 1 Sep 2026 13:37:24 -0500 Subject: [PATCH 1/4] docs: Add CONTRIBUTING.md Contributors need a short guide for develop-targeted PRs, commit subject form, and Gitea issue-closing rules. --- CONTRIBUTING.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..ca38dc7 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,40 @@ +# Contributing + +## Propose changes + +Open a pull request against `develop`. Keep the default branch for releases and +stable tips; land work on `develop` first. + +Point at an existing issue when one fits. Prefer a short issue that states the +symptom or request before a large PR. + +## Commits + +Subject form: + +``` +area: Imperative summary +``` + +- **Area** is a real package, directory, or subsystem token (`ci:`, `docs:`, + Go package name). Not a lone filename. +- **Imperative** mood: Fix, Add, Remove — not "Fixed" or "This patch…". +- No trailing period. Aim ≤ ~70–75 characters for the whole subject. +- Not conventional-commits (`feat:` / `fix:` / `chore:` as types). + +Body explains **why**. Establish the problem, then say what you are doing. +One logical change per commit; split fix and cleanup. + +## Pull requests + +Title matches the primary commit subject. + +- **What** changed +- **Why** (problem and impact) +- **Test** (concrete steps; "CI green" alone is weak) + +## Issues and closing + +Cite leftover issues by **full URL**. Gitea closes issues when `#N` appears in +merge text, so do not put `#N` in the merge message unless that issue is actually +done. Use `Fixes #N` / `Closes #N` only when the leftover work is finished. -- 2.39.5 From 549fdd8171a20b1d35a1ea32d9da8b899d19200f Mon Sep 17 00:00:00 2001 From: s1d3sw1ped_bot Date: Tue, 1 Sep 2026 18:54:34 +0000 Subject: [PATCH 2/4] docs: Add CONTRIBUTING.md Point new contributors at develop for PRs, kernel-style commit subjects, What/Why/Test PR bodies, and safe issue citations under Gitea merge-text closing rules. --- CONTRIBUTING.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..ca38dc7 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,40 @@ +# Contributing + +## Propose changes + +Open a pull request against `develop`. Keep the default branch for releases and +stable tips; land work on `develop` first. + +Point at an existing issue when one fits. Prefer a short issue that states the +symptom or request before a large PR. + +## Commits + +Subject form: + +``` +area: Imperative summary +``` + +- **Area** is a real package, directory, or subsystem token (`ci:`, `docs:`, + Go package name). Not a lone filename. +- **Imperative** mood: Fix, Add, Remove — not "Fixed" or "This patch…". +- No trailing period. Aim ≤ ~70–75 characters for the whole subject. +- Not conventional-commits (`feat:` / `fix:` / `chore:` as types). + +Body explains **why**. Establish the problem, then say what you are doing. +One logical change per commit; split fix and cleanup. + +## Pull requests + +Title matches the primary commit subject. + +- **What** changed +- **Why** (problem and impact) +- **Test** (concrete steps; "CI green" alone is weak) + +## Issues and closing + +Cite leftover issues by **full URL**. Gitea closes issues when `#N` appears in +merge text, so do not put `#N` in the merge message unless that issue is actually +done. Use `Fixes #N` / `Closes #N` only when the leftover work is finished. -- 2.39.5 From ac98b8e9427a66fdfc07d689a95522f39d699ad7 Mon Sep 17 00:00:00 2001 From: s1d3sw1ped_bot Date: Wed, 2 Sep 2026 10:44:13 -0500 Subject: [PATCH 3/4] README: Fix default ports and ADMIN_PASSWORD boot rules Docs sync: align README with current ports/password rules. Co-authored-by: s1d3sw1ped_bot Co-committed-by: s1d3sw1ped_bot --- README.md | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index ffe3e48..80a2408 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # 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; defaults to "password", first login forces a change which is then bcrypt-hashed and stored in the DB). +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. @@ -12,12 +12,14 @@ A pure-Go reverse proxy with embedded web UI. Supports proxy hosts, TCP/UDP stre ## Quick start (binary) ```bash make # builds UI (placeholder) + Go binary with embed -./helix-proxy -# Admin UI + API on :81 -# Proxy on :8080 (or 80/443 when you have perms / run in docker) +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://localhost:81 +Visit http://127.0.0.1:8081 Data (db, certs, logs, www html) lives in `./data` relative to where you ran the binary. @@ -26,9 +28,13 @@ Data (db, certs, logs, www html) lives in `./data` relative to where you ran the docker compose up -d # or docker build -t helix-proxy:dev . -docker run -p 81:81 -v $PWD/data:/app/data --workdir /app helix-proxy:dev +docker run --env ADMIN_PASSWORD='choose-a-real-password' \ + -e ADMIN_PORT=81 -e ADMIN_HOST=0.0.0.0 -e PROXY_HTTP_PORT=80 -e PROXY_HTTPS_PORT=443 \ + -p 80:80 -p 81:81 -p 443:443 -v $PWD/data:/app/data --workdir /app helix-proxy:dev ``` +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): ```yaml # user: "0:0" # root to allow chown+drop inside @@ -41,7 +47,7 @@ environment: 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 full example (exposes 80/81/443, volume for data/). +See docker-compose.yml for a full example (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`) @@ -55,13 +61,13 @@ 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 (defaults to "password"; first login forces change; hashed + stored in DB; no registration or multi-user) +- 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; see TESTING.md). Real LE will be used otherwise (requires valid email, port 80 reachable etc). +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/) -- 2.39.5 From a6e06934090225f0afc9b2d226fcc0230a426070 Mon Sep 17 00:00:00 2001 From: s1d3sw1ped_bot <12+s1d3sw1ped_bot@git.s1d3sw1ped.com> Date: Wed, 2 Sep 2026 11:31:39 -0500 Subject: [PATCH 4/4] docker: Align compose healthcheck with admin port Set compose ADMIN_PORT/PROXY_* to 81/80/443 so healthcheck and EXPOSE match; document binary defaults vs Docker ports in README. Fixes #10 --- README.md | 16 +++++++++++----- docker-compose.yml | 20 ++++++++++++-------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index ffe3e48..1a3eca9 100644 --- a/README.md +++ b/README.md @@ -13,22 +13,28 @@ A pure-Go reverse proxy with embedded web UI. Supports proxy hosts, TCP/UDP stre ```bash make # builds UI (placeholder) + Go binary with embed ./helix-proxy -# Admin UI + API on :81 -# Proxy on :8080 (or 80/443 when you have perms / run in docker) +# Admin UI + API on 127.0.0.1:8081 +# Proxy HTTP on :8080, HTTPS on :18443 ``` -Visit http://localhost:81 +Visit http://localhost:8081 Data (db, certs, logs, www html) lives in `./data` relative to where you ran the binary. ## Docker (recommended) ```bash 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 -p 81:81 -v $PWD/data:/app/data --workdir /app helix-proxy:dev +docker run -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. + PUID/PGID + DISABLE_IPV6 example (see docker-compose.yml for full): ```yaml # user: "0:0" # root to allow chown+drop inside @@ -41,7 +47,7 @@ environment: 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 full example (exposes 80/81/443, volume for data/). +See docker-compose.yml for full example (listens on 80/81/443 via env, publishes 80/443, volume for data/). ## Paths (all overridable) - `data/db.bolt` (or `DATA_DIR`) diff --git a/docker-compose.yml b/docker-compose.yml index 6a123cf..0596301 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,14 +12,18 @@ services: - ./data:/app/data # user: "0:0" # required when using PUID/PGID != built-in to allow binary to chown+drop # working_dir: /app # binary uses CWD for relative data/ + data/www/ - # environment: - # - JWT_SECRET= # optional; otherwise a random secret is stored in data/.jwt_secret - # - DATA_DIR=/app/data - # - WWW_DIR=/app/data/www - # - PUID=1000 - # - PGID=1000 - # - DISABLE_IPV6=1 - # # PUID_NO_DROP=1 # if using low ports (80/443) + PUID: chown as root but skip drop (stay root for bind; default drop runs as PUID after, requires high ports or NET_BIND_SERVICE cap) + environment: + - ADMIN_PORT=81 + - PROXY_HTTP_PORT=80 + - PROXY_HTTPS_PORT=443 + # ADMIN_HOST defaults to 127.0.0.1 (healthcheck hits 127.0.0.1:81) + # - JWT_SECRET= # optional; otherwise a random secret is stored in data/.jwt_secret + # - DATA_DIR=/app/data + # - WWW_DIR=/app/data/www + # - PUID=1000 + # - PGID=1000 + # - DISABLE_IPV6=1 + # # PUID_NO_DROP=1 # if using low ports (80/443) + PUID: chown as root but skip drop (stay root for bind; default drop runs as PUID after, requires high ports or NET_BIND_SERVICE cap) # To use optional SQL backend instead of default yaml: # - DB_TYPE=postgres # - DB_POSTGRES_HOST=db -- 2.39.5