owenandClaude Sonnet 5 ba1f7c4c03 Initial vibeproxy implementation
Self-contained HTTP/HTTPS/TCP/UDP reverse proxy manager written in Go,
with SQLite storage, a Bootstrap 5 admin UI (Go templates, no JS
framework), and a REST API under /api/v1.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QTXFrNP1imCW7jtfL5SZrw
2026-08-17 10:28:59 -05:00
2026-08-17 10:28:59 -05:00
2026-08-17 10:28:59 -05:00
2026-08-17 10:28:59 -05:00
2026-08-17 10:28:59 -05:00
2026-08-17 10:28:59 -05:00
2026-08-17 10:28:59 -05:00
2026-08-17 10:28:59 -05:00

vibeproxy

A small, self-contained reverse proxy manager, written in Go. Think "Nginx Proxy Manager, but simpler and with no external dependencies" — vibeproxy handles HTTP/HTTPS reverse proxying, TCP/UDP streams, TLS termination, and Let's Encrypt certificates itself, using Go's standard networking stack (net/http, httputil.ReverseProxy, crypto/tls, net). It never shells out to nginx, HAProxy, or Caddy.

The admin UI is server-rendered Go templates + Bootstrap 5 + a little vanilla JavaScript — no React/Vue/Node build step. Everything (templates, CSS, JS, SQL migrations) is embedded into a single binary via go:embed, so deployment is just:

./vibeproxy serve

Features

  • HTTP and HTTPS reverse proxying, routed by Host header / SNI
  • Redirect hosts (301/302/307/308, with path & query preservation)
  • TCP and UDP stream proxying, with optional PROXY protocol v1 to backends
  • Multiple backends per proxy host: round robin, least-connections, or weighted load balancing, with TCP/HTTP health checks and configurable failure/recovery thresholds — unhealthy backends never receive traffic
  • TLS termination, HTTP/2, WebSockets, keep-alive, streaming responses
  • Let's Encrypt (HTTP-01 and DNS-01, via the lego ACME client library) plus custom/uploaded certificates, with automatic renewal
  • Reusable Access Lists (CIDR allow/deny + optional HTTP Basic Auth)
  • Per-host custom request/response headers
  • Configurable trusted proxy networks — X-Forwarded-For is only trusted from networks you explicitly configure
  • SQLite storage (WAL mode, foreign keys, migrations) with the active configuration cached in memory — the hot request path never touches the database, and configuration changes apply live without a restart
  • REST API under /api/v1, authenticated with revocable API tokens
  • Single administrator account (HTTP Basic Auth, Argon2id password hashing, CSRF-protected forms)
  • Request logs (with configurable retention) and an audit log of every configuration change
  • Prometheus metrics, /healthz, /readyz, graceful shutdown, automatic and on-demand SQLite backups

Quick start

go build -o vibeproxy ./cmd/vibeproxy
sudo setcap 'cap_net_bind_service=+ep' ./vibeproxy   # to bind :80/:443 without root
./vibeproxy serve

On first run, vibeproxy creates the admin account and prints a random temporary password to stdout — save it, it's not shown again. Change it under Settings → Administrator Account after logging in.

By default:

  • :80 and :443 — proxy traffic (HTTP/HTTPS reverse proxy + redirect hosts + Let's Encrypt HTTP-01 challenges)
  • :8081 — admin web UI, REST API, /healthz, /readyz, /metrics. Put this behind a firewall or VPN — Basic Auth protects it, but it shouldn't be exposed to the internet.

All of this is configurable via flags or environment variables:

Flag Env var Default Purpose
--data-dir VIBEPROXY_DATA_DIR ./data database, certs, backups
--db-path VIBEPROXY_DB_PATH ./data/vibeproxy.db SQLite file
--http-addr VIBEPROXY_HTTP_ADDR :80 HTTP proxy listener
--https-addr VIBEPROXY_HTTPS_ADDR :443 HTTPS proxy listener
--admin-addr VIBEPROXY_ADMIN_ADDR :8081 admin UI + API

Everything else (ACME email, renewal window, log retention, trusted proxy CIDRs, backup schedule, ...) is runtime configuration stored in SQLite and editable from Settings, so it takes effect without a restart.

CLI

vibeproxy serve                    # run the proxy, admin UI, and API
vibeproxy version                  # print the version
vibeproxy config check             # validate config + run migrations, then exit
vibeproxy admin reset-password     # generate a new admin password
vibeproxy database backup          # write an on-demand SQLite backup
vibeproxy database migrate         # apply pending migrations
vibeproxy certificates renew       # renew any due Let's Encrypt certs

systemd

sudo useradd --system --home /var/lib/vibeproxy --shell /usr/sbin/nologin vibeproxy
sudo cp vibeproxy /usr/local/bin/vibeproxy
sudo cp systemd/vibeproxy.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now vibeproxy
sudo journalctl -u vibeproxy -f   # first run prints the admin password here

The unit grants CAP_NET_BIND_SERVICE so vibeproxy can bind :80/:443 without running as root, and sandboxes the process with ProtectSystem, ProtectHome, PrivateDevices, etc. It stores everything under /var/lib/vibeproxy (mode 0700).

Docker

docker compose up -d

See docker-compose.yml / Dockerfile. The container runs as a non-root user, so it listens on 8080/8443 internally — docker-compose.yml maps host 80/443 to those.

REST API

All endpoints are under /api/v1 on the admin listener, authenticated with a bearer token (create one from API in the UI — it's shown once):

curl -H "Authorization: Bearer vp_xxxxxxxx" \
  http://localhost:8081/api/v1/proxy-hosts

Resources: proxy-hosts, streams, certificates, access-lists, settings, logs/requests, logs/audit, stats, tokens. See internal/api for the full route list.

Project layout

cmd/vibeproxy/        CLI entry point (cobra commands)
internal/
  api/                 REST API (/api/v1)
  app/                 wires every subsystem together for `serve`
  auth/                password hashing, Basic Auth, API tokens, CSRF
  access/              CIDR access lists + Basic Auth evaluation
  backup/               SQLite backup/restore
  certificates/        ACME (via lego) + custom cert storage & renewal
  config/               process bootstrap flags/env
  database/            SQLite connection, migrations, repositories
  health/               backend health checking
  loadbalancer/        backend pools: round robin / least-conn / weighted
  logging/              buffered request logging + audit log + retention
  metrics/              Prometheus collectors
  models/                domain types shared across packages
  proxy/                 the HTTP/HTTPS reverse proxy engine
  runtime/              in-memory active-configuration snapshot
  stats/                 dashboard/API statistics
  streams/               TCP/UDP proxying
  web/                    server-rendered admin UI (Go templates + embedded assets)
    templates/, static/
systemd/               vibeproxy.service

Design notes

  • Hot path stays out of SQLite. internal/runtime holds an immutable, atomically-swapped snapshot of proxy hosts, backends, access lists, and settings. Every proxied request/connection reads that snapshot; database writes only happen when an admin changes configuration, at which point Store.Reload rebuilds the snapshot.
  • X-Forwarded-For is not trusted by default. The real client IP is taken from the TCP peer address unless the peer is inside a configured "trusted proxy" CIDR (Settings → Trusted Proxy Networks), in which case the right-most untrusted entry in X-Forwarded-For is used instead.
  • Certificates never touch logs. Private keys are written to disk with 0600 permissions (directories 0700) and are never logged or returned by the API.
  • Reloads don't drop connections. Stream (TCP/UDP) reconciliation diffs the desired vs. running listener set and only restarts streams whose configuration actually changed; unaffected streams, and all in-flight HTTP requests on the previous configuration snapshot, are left alone.

Testing

go test ./...

Covers load-balancing strategies and health-check thresholds, access-list CIDR evaluation, password/API-token hashing, SQLite migrations and proxy-host CRUD round-trips, an end-to-end TCP stream proxy test, and a render-smoke-test for every admin UI page.

S
Description
No description provided
Readme
354 KiB
Languages
Go 74.7%
HTML 20.1%
CSS 3.1%
JavaScript 1.7%
Dockerfile 0.4%