Compare commits

..

3 Commits

Author SHA1 Message Date
wmantly aecf275031 Merge pull request #174 from theta42/release/v1.2.1
Release v1.2.1: fix bootstrap admin lockout, refresh screenshots
2026-07-21 02:23:06 -04:00
wmantly 3f46a807e5 Correct version to 1.2.1: v1.2.0 was already tagged for load balancing
The load-balancing feature (merged in #172/#173) was tagged v1.2.0 on
GitHub, but nodejs/package.json and CHANGELOG.md were never bumped for
it. Backfill a 1.2.0 CHANGELOG entry and bump this release to 1.2.1
instead of 1.1.18, so package.json/CHANGELOG stay ahead of the highest
existing tag rather than behind it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-21 02:07:28 -04:00
wmantly bb1b84b56d Release 1.1.18: fix bootstrap admin lockout, refresh screenshots
models/user_redis.js hardcoded the bootstrap anti-lockout admin
username to 'proxyadmin2', while migrations/permission_bootstrap.js
grants the global-admin permission to conf.auth.adminUsers[0]. An
operator who customized adminUsers away from the default ended up
with a bootstrapped account that had no admin permissions -- a
silent lockout. user_redis.js now derives the bootstrap username the
same way permission_bootstrap.js does.

Also corrected a secrets.js.example comment that claimed the
bootstrap password defaults to the username itself (it actually
generates and logs a random password), and refreshed all README
screenshots against the current UI, including a new load-balancing
screenshot.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-21 02:04:26 -04:00
10 changed files with 34 additions and 10 deletions
+14
View File
@@ -6,6 +6,20 @@ correspond to git tags (`vX.Y.Z`) and `nodejs/package.json`'s `version`.
## [Unreleased] ## [Unreleased]
## [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 ## [1.1.17] - 2026-07-20
### Fixed ### Fixed
+4
View File
@@ -31,6 +31,10 @@ management once basic auth is enabled:
[![Per-host basic auth](docs/images/host-auth-basic.png)](docs/images/host-auth-basic.png) [![Per-host basic auth](docs/images/host-auth-basic.png)](docs/images/host-auth-basic.png)
Multiple backend targets per host, load balanced round-robin:
[![Load balancing](docs/images/load-balancing.png)](docs/images/load-balancing.png)
## Why this over the alternatives ## Why this over the alternatives
Nginx Proxy Manager, Traefik, and Caddy are all good reverse proxies with Nginx Proxy Manager, Traefik, and Caddy are all good reverse proxies with
Binary file not shown.

Before

Width:  |  Height:  |  Size: 141 KiB

After

Width:  |  Height:  |  Size: 368 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 151 KiB

After

Width:  |  Height:  |  Size: 354 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 126 KiB

After

Width:  |  Height:  |  Size: 394 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 428 KiB

+5 -1
View File
@@ -87,7 +87,11 @@ class User extends Table{
User.register(); User.register();
(async function(){ (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 // Optional: an orchestrator (e.g. theta-env's setup.sh) can set
// auth.localAdminPass in proxy-secrets.js to a generated password so this // 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 // bootstrap account isn't left at a well-known default. Only used on first
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "proxy-api", "name": "proxy-api",
"version": "1.1.17", "version": "1.2.1",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "proxy-api", "name": "proxy-api",
"version": "1.1.17", "version": "1.2.1",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-free": "^7.3.0", "@fortawesome/fontawesome-free": "^7.3.0",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "proxy-api", "name": "proxy-api",
"version": "1.1.17", "version": "1.2.1",
"author": [ "author": [
{ {
"name": "William Mantly", "name": "William Mantly",
+8 -6
View File
@@ -67,12 +67,14 @@ module.exports = {
adminUsers: ['proxyadmin'], adminUsers: ['proxyadmin'],
groupRoleMap: {}, groupRoleMap: {},
// Optional: the local anti-lockout admin's initial password, used // Optional: the local anti-lockout admin's initial password, used
// ONLY the first time that account is created. Leave unset and it // ONLY the first time that account is created. Leave unset and a
// defaults to the username itself ("proxyadmin2") — fine for a quick // random password is generated and printed to the container log on
// local test, but change it (or set this) before exposing the proxy // first boot — fine for a quick local test if you copy it from the
// publicly. Once the account exists, this key is never read again; // log right away, but set this (or change the password afterward)
// change the password via the app itself (or delete the Redis user // before exposing the proxy publicly. Once the account exists, this
// to force it to be re-bootstrapped with a new value here). // 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', // localAdminPass: 'change-me',
}, },