Skip to content

Sync upstream (September 26) - #40

Merged
mangyan1 merged 74 commits into
developfrom
fix/upstream-sync-20260926
Sep 27, 2026
Merged

mangyan1 merged 74 commits into
developfrom
fix/upstream-sync-20260926

Conversation

@mangyan1

Copy link
Copy Markdown
Owner

September 26 upstream integration: the 71-commit gap (03688155 → a4a29e09) since the September 22 syncs. Follows PR #33 with the same resolution discipline.

Adopted

  • meta_to_columns: nginx online/err, directory, mTLS, and the certificate DNS-challenge fields move from row meta into dedicated npmplus_* columns, and the migration wipes meta (the fork's reach-probe state is transient and recomputes at the next save)
  • Global jsonReplacer in helpers.js, wired with app.set("json replacer", …): password blanks and certificate/certificate_key/dns-provider credentials drop from every API response — it supersedes the fork's per-site meta masking for those fields
  • Upstream's savedRow/try/finally CRUD shape in the host modules and the sync canAdmin()/canUser(id) + async can() permission model
  • Per-path access lists (upstream_location_access_list), ECH key rotation (cron-ech.sh, ech.sh, ECH_ROTATION_INTERVAL), crowdsec alert pagination ({items, limit, truncated}), user.js email/avatar handling, and the goaccess dinit flag reorder

Fork-specific resolution

  • The reachability probe (configureWithReachability) survives as the only meta writer: reach_ok/reach_err only, patched after configure persists its own columns. proxy_host's $parseDatabaseJson keeps meta readable; Table.jsx sorts enabled → offline → unreachable → online off npmplus_nginx_online plus the meta reach state
  • The crowdsec routes gate through a local requireAdmin(res) on top of the merged permission model
  • assertPrivilegedNginxFields, validateIncomingPort, mTLS, and the SSL/HSTS cleanup stay intact inside the adopted CRUD shape; session-token architecture and the setup-token flow are unchanged; bounded fetches kept (gravatar, site24x7)
  • Access-list row masking (maskItems/maskAccessListItems, lodash _.omit) is kept with lodash back in the manifest; any redundancy with the recursive replacer gets swept in a normal reviewable commit per FORK.md, never inside the merge
  • Supply-chain aging held: @tabler/core 1.6.0 and vite 8.3.1 failed minimumReleaseAge and stay at 1.5.1/8.3.0; backend pins (undici, ref-parser, swagger-parser, biome) kept ours
  • The caddy source build with its CVE pin matrix and the goaccess CSP/no-cache headers in npmplus.conf are kept
  • README ECH section trimmed to the release-discipline word budget; the full guide lives in docs/ech.md
  • Test fixtures and smokes track the new contract per FORK.md: certificate-dns.test.js, the sqlite-upgrade.test.js raw-knex legacy seed, and security-regressions.mjs/rc5-features.mjs reading npmplus_nginx_online + meta.reach_ok

Validation

  • Backend 163 tests, frontend 15 tests, validate-schema, biome clean on both LF-normalized trees, vite build, security invariants, frozen lockfiles
  • Full docker-security container battery green against an image built from this branch (socket-injection regressions, MFA replay, browser-driven first-admin setup and UI flows)
  • Docker upgrade simulation: rc.7 → this branch's image on the same data volume — admin login, proxy host, and access list survive, meta_to_columns verified on real pre-merge data, the probe re-runs on save, item passwords masked
  • Linux-only python contracts (installer-recovery, heal-migration, upstream-sync) reproduce identically on a pristine fork-HEAD worktree; they stay green on CI

jc21 and others added 30 commits June 3, 2026 14:14
A Stream Host with an IPv6 address as the Forward Host was accepted and
saved but never activated. The generated stream config rendered
`proxy_pass {{ forwarding_host }}:{{ forwarding_port }}` as e.g.
`fe80::528:3c87:e7bb:ab08:25`, which nginx rejects with
"invalid port in upstream" because an IPv6 literal must be wrapped in
square brackets before the port is appended (`[fe80::...]:25`).

Normalize the stream forward host in generateConfig (alongside the existing
per-host-type data massaging) using net.isIPv6(), so IPv6 hosts render as
`[address]:port` while IPv4 addresses and hostnames are emitted unchanged.
The mutation is applied to the deep-copied render object, so persisted and
audit data are unaffected.

Fixes NginxProxyManager#5740
- Per-path access lists: assign different access lists to individual
  locations on the same proxy host
- Host logs modal: view access/error logs from proxy host dropdown
- PostgreSQL JSON containment query (@>) for location regeneration
- Locale keys: action.logs, column.error
- Use optional chaining for nullable checks
- Replace template literals with string literals for plain SQL
- Add node: protocol to fs/promises import in setup.js
processItems() passed proxyHostModel and the literal "proxy_host" to
configure() for every host type. host_type selects both the template and
the output path, and each host type has its own id sequence, so
redirection hosts, 404 hosts and streams were rendered through
proxy_host.conf and written over /data/nginx/proxy_host/<id>.conf. The
proxy host sharing that id lost its config file and had the resulting
nginx error recorded in its own meta.
The credentials file written for a DNS-01 challenge was only cleaned up when
certbot failed - the unlink sat in a catch block. On success the file stayed in
/etc/letsencrypt/credentials for the entire life of the certificate, holding a
live DNS provider API token in plaintext.

The file cannot simply be deleted at issuance, because certbot records its path
in the renewal config and reads it back on every `certbot renew`. So the renew
path now writes the file itself immediately before invoking certbot, and both
paths remove it in a finally block.

Net effect: the credentials exist on disk for the duration of a certbot run
rather than permanently. The value still lives in the certificates table, which
is unavoidable - it has to come from somewhere to be written at all.

renewLetsEncryptSslWithDnsChallenge reads the row directly from the model
because renew() sources its certificate from internalCertificate.get(), which
strips meta.dns_provider_credentials via omissions().
setupCertbotPlugins() wrote a credentials file for every DNS-01 certificate
each time the backend started, using flag "wx" so it only filled in missing
ones. That existed because the renew path did not write the file itself, so
something had to put it back before `certbot renew` looked for it.

With the previous commit the renew path writes the file immediately before
invoking certbot, so this is now the only thing putting those credentials back
on disk - and it does so for every certificate on every restart, which undoes
the cleanup entirely.

Removing the write leaves the `fs` import and the `promises` array unused. The
"Added Certbot plugins" log line is kept but now gates on plugins.length, since
it was previously gated on a promise array that only ever held credential
writes.
Bumps [@humanfs/node](https://github.com/humanwhocodes/humanfs/tree/HEAD/packages/node) from 0.16.7 to 0.16.8.
- [Release notes](https://github.com/humanwhocodes/humanfs/releases)
- [Changelog](https://github.com/humanwhocodes/humanfs/blob/main/packages/node/CHANGELOG.md)
- [Commits](https://github.com/humanwhocodes/humanfs/commits/node-v0.16.8/packages/node)

---
updated-dependencies:
- dependency-name: "@humanfs/node"
  dependency-version: 0.16.8
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
certbot-dns-azure 2.6.1 requires certbot<4.0; installing it into the image's certbot 5.x venv downgrades certbot and acme to 3.3.0, and acme 3.3.0 no longer imports against pyOpenSSL 26 (NginxProxyManager#5606). The maintained fork certbot-dns-azure-modern keeps module, entry point, flags and credentials format, requires certbot>=3.0 without an upper bound and declares its own azure-mgmt-dns range, so the extra dependency pin is no longer needed.
The template was the longest of all plugins (1181 characters, nine comment lines) and carried the upstream example secret that trips secret scanning. It now shows what a user has to fill in: the service principal, and one zone line in the format ZONE_NAME:RESOURCE_GROUP_ID, plus a link to the docs for everything else.
### Summary

    This PR adds support for **Tencent Cloud EdgeOne (TEO)** as a DNS provider for Let's Encrypt DNS-01 certificate validation using the [`certbot-dns-
  edgeone`](<https://pypi.org/project/certbot-dns-edgeone/>) plugin.

### Details

    - **Provider Name:** Tencent Cloud EdgeOne
    - **Plugin Name:** `dns-edgeone`
    - **PyPI Package:** [`certbot-dns-edgeone`](https://pypi.org/project/certbot-dns-edgeone/) (v0.1.0+)
    - **Plugin Repository:** https://github.com/hurole/certbot-dns-edgeone
    - **License:** Apache-2.0

    ### Credentials Template

    ```ini
    dns_edgeone_secret_id = YOUR_TENCENTCLOUD_SECRET_ID
    dns_edgeone_secret_key = YOUR_TENCENTCLOUD_SECRET_KEY
    ```

### Verification

  • Verified certbot-dns-edgeone package installation and entrypoint discovery with Certbot.
  • Verified DNS-01 TXT record creation and cleanup flows via unit tests.
  • Formatted in backend/certbot/dns-plugins.json in alphabetical order.
Bumps [qs](https://github.com/ljharb/qs) from 6.15.3 to 6.16.0.
- [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md)
- [Commits](ljharb/qs@v6.15.3...v6.16.0)

---
updated-dependencies:
- dependency-name: qs
  dependency-version: 6.16.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
…h 2 updates

Bumps the prod-patch-updates group with 2 updates in the /frontend directory: [query-string](https://github.com/sindresorhus/query-string) and [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom).


Updates `query-string` from 9.5.0 to 9.5.1
- [Release notes](https://github.com/sindresorhus/query-string/releases)
- [Commits](sindresorhus/query-string@v9.5.0...v9.5.1)

Updates `react-router-dom` from 7.18.2 to 7.18.4
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/react-router-dom@7.18.4/packages/react-router-dom/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router-dom@7.18.4/packages/react-router-dom)

---
updated-dependencies:
- dependency-name: query-string
  dependency-version: 9.5.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: prod-patch-updates
- dependency-name: react-router-dom
  dependency-version: 7.18.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: prod-patch-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
…with 5 updates

Bumps the dev-patch-updates group with 5 updates in the /frontend directory:

| Package | From | To |
| --- | --- | --- |
| [@formatjs/cli](https://github.com/formatjs/formatjs) | `6.16.19` | `6.16.30` |
| [@testing-library/dom](https://github.com/testing-library/dom-testing-library) | `10.4.1` | `10.4.2` |
| [@testing-library/react](https://github.com/testing-library/react-testing-library) | `16.3.2` | `16.3.3` |
| [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react) | `6.1.0` | `6.1.1` |
| [postcss](https://github.com/postcss/postcss) | `8.5.26` | `8.5.28` |



Updates `@formatjs/cli` from 6.16.19 to 6.16.30
- [Release notes](https://github.com/formatjs/formatjs/releases)
- [Commits](https://github.com/formatjs/formatjs/compare/@formatjs/cli@6.16.19...@formatjs/cli@6.16.30)

Updates `@testing-library/dom` from 10.4.1 to 10.4.2
- [Release notes](https://github.com/testing-library/dom-testing-library/releases)
- [Changelog](https://github.com/testing-library/dom-testing-library/blob/main/CHANGELOG.md)
- [Commits](testing-library/dom-testing-library@v10.4.1...v10.4.2)

Updates `@testing-library/react` from 16.3.2 to 16.3.3
- [Release notes](https://github.com/testing-library/react-testing-library/releases)
- [Changelog](https://github.com/testing-library/react-testing-library/blob/main/CHANGELOG.md)
- [Commits](testing-library/react-testing-library@v16.3.2...v16.3.3)

Updates `@vitejs/plugin-react` from 6.1.0 to 6.1.1
- [Release notes](https://github.com/vitejs/vite-plugin-react/releases)
- [Changelog](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite-plugin-react/commits/plugin-react@6.1.1/packages/plugin-react)

Updates `postcss` from 8.5.26 to 8.5.28
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](postcss/postcss@8.5.26...8.5.28)

---
updated-dependencies:
- dependency-name: "@formatjs/cli"
  dependency-version: 6.16.30
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@testing-library/dom"
  dependency-version: 10.4.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@testing-library/react"
  dependency-version: 16.3.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@vitejs/plugin-react"
  dependency-version: 6.1.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: postcss
  dependency-version: 8.5.28
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
Nginx Proxy Manager had no way to inspect application or nginx logs
from the web UI - admins had to shell into the container or read
`docker logs`. This adds an admin-only Logs page that can tail:

- the backend application log, now also mirrored to
  /data/logs/backend.log (in addition to stdout) and rotated by the
  logrotate timer that already runs every 2 days
- the Let's Encrypt/certbot log, which certbot already writes to
  /data/logs/letsencrypt.log via its existing --logs-dir flag
- per-host nginx access/error logs (proxy, redirection, 404 and
  stream hosts), with the file path always resolved server-side from
  a validated host_type enum + numeric host_id, never from client
  input

Reads use a reverse chunked scan (64KB chunks, capped at 5MB scanned
per request) instead of loading whole files into memory, and the
frontend polls every 5s only while the tab is focused and "Live" is
on, so this stays cheap on both CPU and memory. No new runtime
dependencies were added on either side.

Purely additive: two new admin-only endpoints
(GET /api/logs/sources, GET /api/logs/tail), no existing behaviour
changed.
…ted-login-redirect-5753

fix(router): redirect authenticated login visits to dashboard
…ndabot/npm_and_yarn/frontend/dev-patch-updates-846ffa5b48

build(deps-dev): bump the dev-patch-updates group across 1 directory with 5 updates
…ndabot/npm_and_yarn/frontend/prod-patch-updates-d144f49a8f

build(deps): bump the prod-patch-updates group across 1 directory with 2 updates
…with 5 updates

Bumps the dev-minor-updates group with 5 updates in the /frontend directory:

| Package | From | To |
| --- | --- | --- |
| [@tanstack/react-query-devtools](https://github.com/TanStack/query/tree/HEAD/packages/react-query-devtools) | `5.101.4` | `5.103.1` |
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `26.2.0` | `26.6.2` |
| [happy-dom](https://github.com/capricorn86/happy-dom) | `20.11.6` | `20.14.5` |
| [sass](https://github.com/sass/dart-sass) | `1.103.1` | `1.104.1` |
| [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) | `8.2.2` | `8.3.0` |



Updates `@tanstack/react-query-devtools` from 5.101.4 to 5.103.1
- [Release notes](https://github.com/TanStack/query/releases)
- [Changelog](https://github.com/TanStack/query/blob/main/packages/react-query-devtools/CHANGELOG.md)
- [Commits](https://github.com/TanStack/query/commits/@tanstack/react-query-devtools@5.103.1/packages/react-query-devtools)

Updates `@types/node` from 26.2.0 to 26.6.2
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `happy-dom` from 20.11.6 to 20.14.5
- [Release notes](https://github.com/capricorn86/happy-dom/releases)
- [Commits](capricorn86/happy-dom@v20.11.6...v20.14.5)

Updates `sass` from 1.103.1 to 1.104.1
- [Release notes](https://github.com/sass/dart-sass/releases)
- [Changelog](https://github.com/sass/dart-sass/blob/main/CHANGELOG.md)
- [Commits](sass/dart-sass@1.103.1...1.104.1)

Updates `vite` from 8.2.2 to 8.3.0
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/create-vite@8.3.0/packages/vite)

---
updated-dependencies:
- dependency-name: "@tanstack/react-query-devtools"
  dependency-version: 5.102.8
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-minor-updates
- dependency-name: "@types/node"
  dependency-version: 26.5.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-minor-updates
- dependency-name: happy-dom
  dependency-version: 20.14.3
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-minor-updates
- dependency-name: sass
  dependency-version: 1.104.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-minor-updates
- dependency-name: vite
  dependency-version: 8.3.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-minor-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
feat: add Tencent Cloud EdgeOne DNS provider
…tbot-dns-azure-modern

fix(certbot): switch the Azure DNS plugin to certbot-dns-azure-modern
…ndabot/npm_and_yarn/test/humanfs/node-0.16.8

Bump @humanfs/node from 0.16.7 to 0.16.8 in /test
…ndabot/npm_and_yarn/backend/qs-6.16.0

build(deps): bump qs from 6.15.3 to 6.16.0 in /backend
…entials-lifetime

Remove DNS provider credentials from disk after certbot runs
…erate-config-wrong-host-type

Use the row's own model and host type in regenerate-config
…ndabot/npm_and_yarn/frontend/dev-minor-updates-793a873af9

build(deps-dev): bump the dev-minor-updates group across 1 directory with 5 updates
…-ipv6-forward-host-brackets

fix(stream): bracket IPv6 forward host for valid nginx upstream
Zoey2936 and others added 28 commits September 24, 2026 15:02
Signed-off-by: Zoey <zoey@z0ey.de>
Signed-off-by: Zoey <zoey@z0ey.de>
Signed-off-by: Zoey <zoey@z0ey.de>
Signed-off-by: Zoey <zoey@z0ey.de>
Signed-off-by: Zoey <zoey@z0ey.de>
Signed-off-by: Zoey <zoey@z0ey.de>
Signed-off-by: Zoey <zoey@z0ey.de>
Signed-off-by: Zoey <zoey@z0ey.de>
Signed-off-by: Zoey <zoey@z0ey.de>
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Signed-off-by: Zoey <zoey@z0ey.de>
Signed-off-by: Zoey <zoey@z0ey.de>
Signed-off-by: Stephan Paternotte <Stephan-P@users.noreply.github.com>
Co-Authored-By: Stephan Paternotte <10008599+stephan-p@users.noreply.github.com>
Signed-off-by: Zoey <zoey@z0ey.de>
Signed-off-by: Zoey <zoey@z0ey.de>
Signed-off-by: Zoey <zoey@z0ey.de>
Signed-off-by: Zoey <zoey@z0ey.de>
Signed-off-by: Zoey <zoey@z0ey.de>
Signed-off-by: Zoey <zoey@z0ey.de>
Signed-off-by: Zoey <zoey@z0ey.de>
Signed-off-by: Zoey <zoey@z0ey.de>
…c-20260926

September 26 upstream integration (71 commits). Adopts upstream's
meta-to-columns move (nginx online/err, directory, mTLS, and the
DNS-challenge fields now live in npmplus_* columns) with its global
jsonReplacer, which supersedes our per-site meta masking, plus the
savedRow/try-finally CRUD shape, per-path access lists, the ECH
rotation feature, and the crowdsec alert pagination. Kept the fork's
session-token architecture, setup-token flow, bounded fetches,
htpasswd username validation, the privileged nginx-field and
incoming-port assertions, and the forward-destination reachability
probe, which now writes only reach state to meta and stays readable
because the model parse keeps meta. Mask functions keep lodash, and
the supply-chain aging pins hold (tabler 1.5.1 and vite 8.3.0; the
fresher versions failed minimumReleaseAge). The README keeps its
1300-word budget by moving the ECH detail to docs/ech.md. Test
fixtures and the smoke drivers track the new npmplus_* contract per
FORK.md; the Linux-only python contracts are untouched and stay green
on CI.
@mangyan1
mangyan1 merged commit 1b710ed into develop Sep 27, 2026
15 checks passed
@mangyan1
mangyan1 deleted the fix/upstream-sync-20260926 branch September 27, 2026 01:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.