Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 60dbfe5b9b | |||
| ecdced16fc | |||
| aecf275031 | |||
| 3f46a807e5 | |||
| bb1b84b56d |
@@ -6,6 +6,25 @@ correspond to git tags (`vX.Y.Z`) and `nodejs/package.json`'s `version`.
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [1.2.2] - 2026-07-21
|
||||
|
||||
### Fixed
|
||||
- Multi-target load balancing (added in 1.2.0) crashed every request to a load-balanced host: `ops/nginx_conf/targetinfo.lua` required a nonexistent `resty.balancer.round_robin` module. The `lua-resty-balancer` rock installed by the Dockerfile/`install.sh` doesn't provide that path — it provides `resty.roundrobin` (constructed as `roundrobin:new(nodes)`, not `:new()` + `:reinit(nodes)`). Fixed `targetinfo.lua` to use the real module and API; verified end-to-end that requests now round-robin across targets with no Lua errors.
|
||||
|
||||
## [1.2.1] - 2026-07-21
|
||||
|
||||
### Fixed
|
||||
- The bootstrap anti-lockout admin account was always created as `proxyadmin2` regardless of `conf.auth.adminUsers`, while `migrations/permission_bootstrap.js` grants the global-admin permission to `conf.auth.adminUsers[0]`. If an operator customized `adminUsers` away from the default, the bootstrapped account and the permissioned account were two different (non-matching) usernames, so the anti-lockout account ended up with no admin access. `models/user_redis.js` now derives the bootstrap username from `conf.auth.adminUsers[0]` (falling back to `proxyadmin2`), matching `permission_bootstrap.js`.
|
||||
- Corrected a `secrets.js.example` comment that claimed the bootstrap admin's password "defaults to the username itself" — it actually generates a random password printed to the container log on first boot.
|
||||
|
||||
### Changed
|
||||
- Refreshed all README screenshots (hosts, per-host SSO auth, per-host basic auth) against the current UI, and added a new load-balancing screenshot for the multi-target feature.
|
||||
|
||||
## [1.2.0] - 2026-07-21
|
||||
|
||||
### Added
|
||||
- Multi-target load balancing: hosts can now specify additional backend targets (`IP:port`, one per line) alongside the primary target; the proxy distributes requests across all of them round-robin via `lua-resty-balancer`. Fixes #47.
|
||||
|
||||
## [1.1.17] - 2026-07-20
|
||||
|
||||
### Fixed
|
||||
|
||||
@@ -31,6 +31,10 @@ management once basic auth is enabled:
|
||||
|
||||
[](docs/images/host-auth-basic.png)
|
||||
|
||||
Multiple backend targets per host, load balanced round-robin:
|
||||
|
||||
[](docs/images/load-balancing.png)
|
||||
|
||||
## Why this over the alternatives
|
||||
|
||||
Nginx Proxy Manager, Traefik, and Caddy are all good reverse proxies with
|
||||
|
||||
|
Before Width: | Height: | Size: 141 KiB After Width: | Height: | Size: 368 KiB |
|
Before Width: | Height: | Size: 151 KiB After Width: | Height: | Size: 354 KiB |
|
Before Width: | Height: | Size: 126 KiB After Width: | Height: | Size: 394 KiB |
|
After Width: | Height: | Size: 428 KiB |
@@ -87,7 +87,11 @@ class User extends Table{
|
||||
User.register();
|
||||
|
||||
(async function(){
|
||||
var defaultUser = 'proxyadmin2'
|
||||
// Matches migrations/permission_bootstrap.js: the anti-lockout account is
|
||||
// the first entry in conf.auth.adminUsers (default 'proxyadmin2'), NOT a
|
||||
// hardcoded name -- otherwise an operator who customizes adminUsers ends
|
||||
// up with a bootstrap account that has no admin permissions.
|
||||
var defaultUser = (conf.auth && conf.auth.adminUsers && conf.auth.adminUsers[0]) || 'proxyadmin2';
|
||||
// Optional: an orchestrator (e.g. theta-env's setup.sh) can set
|
||||
// auth.localAdminPass in proxy-secrets.js to a generated password so this
|
||||
// bootstrap account isn't left at a well-known default. Only used on first
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "proxy-api",
|
||||
"version": "1.1.17",
|
||||
"version": "1.2.2",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "proxy-api",
|
||||
"version": "1.1.17",
|
||||
"version": "1.2.2",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-free": "^7.3.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "proxy-api",
|
||||
"version": "1.1.17",
|
||||
"version": "1.2.2",
|
||||
"author": [
|
||||
{
|
||||
"name": "William Mantly",
|
||||
|
||||
@@ -62,7 +62,7 @@ function M.get(ngx, domain, targetInfo)
|
||||
|
||||
local json = require "cjson"
|
||||
local redis = require "resty.redis"
|
||||
local round_robin = require "resty.balancer.round_robin"
|
||||
local roundrobin = require "resty.roundrobin"
|
||||
|
||||
if not domain then
|
||||
return nil, 499
|
||||
@@ -114,12 +114,11 @@ function M.get(ngx, domain, targetInfo)
|
||||
local cache_key = domain .. "_" .. (res["updated_on"] or "0")
|
||||
|
||||
if not M.host_balancers[domain] or M.host_balancers[domain].key ~= cache_key then
|
||||
local b = round_robin:new()
|
||||
local nodes = {}
|
||||
for _, t in ipairs(target_list) do
|
||||
nodes[t] = 1
|
||||
end
|
||||
b:reinit(nodes)
|
||||
local b = roundrobin:new(nodes)
|
||||
M.host_balancers[domain] = { b = b, key = cache_key }
|
||||
end
|
||||
|
||||
|
||||
@@ -67,12 +67,14 @@ module.exports = {
|
||||
adminUsers: ['proxyadmin'],
|
||||
groupRoleMap: {},
|
||||
// Optional: the local anti-lockout admin's initial password, used
|
||||
// ONLY the first time that account is created. Leave unset and it
|
||||
// defaults to the username itself ("proxyadmin2") — fine for a quick
|
||||
// local test, but change it (or set this) before exposing the proxy
|
||||
// publicly. Once the account exists, this key is never read again;
|
||||
// change the password via the app itself (or delete the Redis user
|
||||
// to force it to be re-bootstrapped with a new value here).
|
||||
// ONLY the first time that account is created. Leave unset and a
|
||||
// random password is generated and printed to the container log on
|
||||
// first boot — fine for a quick local test if you copy it from the
|
||||
// log right away, but set this (or change the password afterward)
|
||||
// before exposing the proxy publicly. Once the account exists, this
|
||||
// key is never read again; change the password via the app itself
|
||||
// (or delete the Redis user to force it to be re-bootstrapped with a
|
||||
// new value here).
|
||||
// localAdminPass: 'change-me',
|
||||
},
|
||||
|
||||
|
||||