211 Commits
Author SHA1 Message Date
Jamie Curnow 5b7e34eb67 Fix second round of review findings from PR #6029
Security
- Check advanced_config permissions before creating a certificate on
  host update (proxy, redirection and 404 hosts). A refused request
  previously requested a Let's Encrypt certificate first, leaving an
  orphan certificate and using up rate limit.
- Only trust X-NPM-Peer-Addr when it comes with a secret generated at
  container start. The admin nginx sends both headers. Any proxy host or
  stream forwarding to 127.0.0.1:3000 was also a loopback peer, so it
  could forge the header and get a fresh rate-limit bucket on every
  request. Without the secret (dev, or a mounted production.conf), the
  header is ignored.
- Add a login limit per IP across all accounts (30 failed attempts a
  minute) alongside the per-account one. Before this, one address could
  spray passwords over any number of accounts. Behind a shared proxy,
  everyone using that proxy shares this limit.
- Stop trusting X-Real-IP from loopback. It was only there for an older
  version of the rate limiter, and it let a stream host forwarding to a
  local proxy host forge the client IP and get past IP access lists.
  Loopback now behaves as it does on master.

Correctness
- Refuse to delete a certificate that hosts still use (400, with counts
  per host type). Their configs include its files, and a successful
  revoke deleted them anyway, which broke nginx -t. Otherwise the
  certificate is revoked and its files are removed even if the revoke
  fails.
- Let non-admins clear a location's advanced config. Deleting the
  location was already allowed and has the same effect, and a location
  deleted and re-added at the same path arrives with an empty config,
  which was refused.
- Clear proxy host grants (meta.proxy_host_ids) when visibility isn't
  "user" or proxy hosts are hidden, and drop ids of deleted hosts.
  Before, hidden grants came back when proxy hosts were shown again.
  The backend enforces this; the permissions modal also stops sending
  them.
- 404 host and redirection host modals now wait for the current user
  to load, so an admin's advanced config change isn't dropped if they
  submit before it loads.

Tests
- NonAdminHosts.cy.js: refused change doesn't create a certificate,
  location rename and clear rules, grant clearing.
- Certificates.cy.js: deleting a certificate that is in use.
2026-11-09 23:39:26 +10:00
Jamie Curnow 04c1f5ae76 Fix review findings from PR #6029
Security
- Redact certbot output before it reaches the API: strip the
  certificate's DNS credential values, URL query strings and userinfo,
  secret-looking key=value pairs and Bearer/Basic tokens. DNS plugins
  can echo request URLs carrying API keys. The raw CommandError is no
  longer attached as `previous`, since the error handler returns
  `previous` to the client on certificate routes.
- Rate limit login/2FA on the admin nginx's real TCP peer, passed as
  X-NPM-Peer-Addr ($realip_remote_addr), instead of X-Forwarded-For.
  nginx trusts X-Real-IP from private ranges, so a client on the LAN or
  Docker network could get a fresh bucket on every request. Behind
  another proxy, limits now apply per account through that proxy.
- Bound rate limiter memory: hash keys over 128 chars and cap each store
  at 50k entries, removing expired entries first and then the oldest.

Correctness
- Proxy host modal: send location advanced configs unchanged for
  non-admins instead of looking them up by path, which dropped the
  config from a renamed location.
- Location advanced config: locations that omit advanced_config now get
  a config only after explicit ones are matched, so a new location at
  an old path can't take the config from the renamed location.
- Certificate upload: check that the certificate matches the private
  key (uploaded or stored) before writing, so a mismatched pair can't
  break nginx -t.
- Certificate delete: keep the Let's Encrypt files when revoke fails and
  hosts still use the certificate, so their configs still load.

Cleanup
- Make the rate-limit certbot hint first in the list, as its comment
  says.
- Proxy host getCount uses the permissions access has already loaded
  instead of querying user_permission again.
- Rate limiter: register the success refund listener in one place and
  call it a fixed window, not a sliding one.
2026-11-09 22:53:53 +10:00
Jamie Curnow fff2b0d097 Fix for changing the upstream Host from $host to $forward_host
($http_host) forwards the raw client Host header, including the port and
any absolute-form URI mismatch, to every upstream and into the asset
cache key
2026-11-09 22:09:34 +10:00
Jamie Curnow 0cde59a8ad Fix for rate limiter only trusts X-Forwarded-For when the socket is
loopback, and the admin nginx sets that header to its own $remote_addr
2026-11-09 22:00:26 +10:00
jc21 18fc758b4f Merge pull request #5934 from lennondotw/fix/preserve-host-port
fix(proxy): preserve client ports in forwarded Host headers
2026-11-05 10:15:05 +10:00
jc21 1dd0b8fbe8 Merge pull request #5989 from Rip-07/fix/5964-stale-nginx-pid
fix: remove stale nginx pid file before starting nginx
2026-11-05 08:45:23 +10:00
mikeyheneinandClaude Opus 5.5 b28e0d5442 s6-overlay 3.2.3.2
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 20:28:35 -08:00
Askhat AkhtanovandClaude Opus 5.5 c23a1cb343 fix: remove stale nginx pid file before starting nginx
When /run/nginx is already owned by PUID:PGID, the ownership step skips
it, so a leftover nginx.pid owned by root stays in place and nginx,
running as PUID:PGID, fails with "Permission denied" on every start.

Nginx is not running yet during prepare, so remove the pid file there.

Fixes #5964

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 13:33:27 +05:00
lennondotw 3a455595e7 fix(proxy): isolate cached assets by forwarded authority 2026-10-14 14:48:22 +08:00
lennondotw c50c06530b Merge remote-tracking branch 'upstream/develop' into fix/preserve-host-port 2026-10-14 14:37:17 +08:00
lennondotw 6b26999e34 fix(proxy): preserve client ports in forwarded Host headers
Keep the incoming Host authority for default and custom locations, with the existing hostname fallback when Host is absent. Add a built-image regression that validates Host against Origin and Referer and run it after the CI image build.
2026-10-08 15:50:24 +08:00
Jamie CurnowandClaude Opus 5.5 2afd723cd8 Fix access list rules and SSL missing from re-rendered host configs
Some paths rendered host configs without fully loading the relations
the templates depend on, silently dropping access rules (and SSL):

- Enabling a proxy host loaded the access list without its clients or
  auth items, so the host came back with no access restrictions.
- Requesting a Let's Encrypt certificate re-rendered every host sharing
  its domains from bare rows, dropping access rules and SSL.

generateConfig now loads any referenced certificate or access list that
isn't fully loaded, so no caller can render a partial config. The two
callers above also fetch the relations themselves, and a warning is
logged when a host's access list is missing or has no rules.

Adds integration tests covering access lists across disable/enable.

Fixes #5919, #4286, #5710

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 22:13:31 +10:00
xJayMorex 4725153962 fix: only chown /data/keys.json if necessary 2026-09-25 11:49:17 +02:00
Jamie Curnow 2cfd3395cf Adds integration tests for per path access lists, fixes ipv6 jsv,
and enforces host-wide access list when location access list is not set
2026-09-24 12:21:49 +10:00
carlosalbertorg 4282d6c6e9 feat: Add a Logs viewer to the admin UI
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.
2026-09-22 13:11:38 -03:00
vgoer b7772016ba fix: Ensure JWT key file ownership matches PUID/PGID at startup 2026-08-24 09:30:36 +00:00
Jamie Curnow a62c2a6dc3 Adds support for custom admin port via env var #3808
and documentation
2026-06-10 11:24:53 +10:00
Tony Chau 94176d2f9c Update s6 overlay to 3.2.3.0 2026-06-03 20:03:29 +08:00
Jamie Curnow 0d832092a5 Only modify files in startup when they aren't mounted 2026-06-02 22:09:21 +10:00
jc21 79a4128b78 Merge branch 'develop' into develop 2026-05-31 22:04:14 +10:00
Jamie Curnow 7e9cc32f97 Fix cypress suite
- split out cypress tests for plugins to be isolated
- use updated testca image from proper location
2026-05-27 07:25:24 +10:00
Jamie Curnow 03c70e3902 Fixes for upgraded debian trixie
- Adds request logging in debug mode for some endpoints
- Moves certbot version determination to the startup scripts and removes
  bash script encapsulation when installing plugins
- Revert loose domain validation, which was there for a specific reason
  addressing CVE's
- Fix Cypress suite for cert generation
- Adds Cypress test that iterates over the entire certbot plugins list
  and installs each one, ensuring at the very least that the install
  works
- Fixed some plugins based on this
- (!) Still some work to do on this, hostinger is still broken at least
- Improved cypress tests for custom certs; they will generate on each
  run instead of being baked in. The baked ones were due to expire soon
2026-05-25 07:37:24 +10:00
Daan Selen 387f8d9424 cherry-pick requested changes 2026-05-17 20:23:22 +02:00
Jamie Curnow 67d40e186f Attempt to fix #5335 by allowing resovler generation to be opt-out with a env var 2026-02-26 08:32:02 +10:00
William Mahoney 7241869a9e Fix silent config corruption in 50-ipv6.sh on NFS volumes
Replace unsafe `echo "$(sed ...)" > $FILE` with atomic temp-file write.

The current pattern reads a file with sed inside a command substitution,
then writes the result back via echo redirection. If sed reads an empty
or momentarily unreadable file (e.g., NFS transient issue during
container recreation by Watchtower or similar tools), it produces no
output. The echo then writes exactly 1 byte (a newline) to the config
file, silently destroying its contents.

The fix writes sed output to a temp file first, checks it's non-empty
with `[ -s ]`, then atomically replaces the original via `mv`. If sed
produces empty output, the original file is preserved and a warning is
logged to stderr.
2026-02-20 21:24:40 -07:00
Jamie Curnow 5f5a3870e4 Drop support for armv7 builds, bump version, update docs 2026-02-17 12:55:56 +10:00
jerry-yuan eeab425ea4 fix: unknown "trust_forwarded_proto" variable error when run with already created old virtual hosts 2026-02-10 10:53:17 +00:00
Jerry 232b5b759a fix: make variable name meaningful 2026-02-01 00:16:17 +08:00
jerry-yuan 187d21a0d5 feat: add trust_forwarded_proto option for SSL redirect handling in reverse proxy scenarios
When Nginx is behind another proxy server (like CloudFlare or AWS ALB), the force-SSL
feature can cause redirect loops because Nginx sees the connection as plain HTTP
while SSL is already handled upstream. This adds a new boolean option to trust
the X-Forwarded-Proto header from upstream proxies.

Changes:
- Add `trust_forwarded_proto` column to proxy_host table (migration)
- Update model and API schema to support the new boolean field
- Modify force-ssl Nginx template to check X-Forwarded-Proto/X-Forwarded-Scheme
- Add map directives in nginx.conf to validate and sanitize forwarded headers
- Add advanced option toggle in frontend UI with i18n support (EN/ZH)
- Set proxy headers from validated map variables instead of $scheme

This allows administrators to control SSL redirect behavior when Nginx is deployed
behind a TLS-terminating proxy.
2026-01-31 13:11:47 +00:00
Jamie Curnow 534afe6067 Implement suggestion from #5216 hopefully rectifying https -> forced https hosts 2026-01-28 14:04:32 +10:00
Jamie Curnow 28982b8bc2 Updated config files for cypress 2026-01-27 10:46:30 +10:00
Alex Kitsul aeb44244a7 Added logging for streams based on port 2025-12-30 21:44:29 -08:00
Jamie Curnow 8959190d32 Change docker ci expose format for docker 28 :/ 2025-11-13 11:37:58 +10:00
Jamie Curnow 7e875eb27a Change docker ci expose format for docker 28 :/ 2025-11-13 11:35:11 +10:00
Jamie Curnow 311d6a1541 Tweaks to CI stack for postgres 2025-11-10 10:30:16 +10:00
Jamie Curnow 8eba31913f Remove pebble certs, they removed the dockerhub image that had armv7 support.
The ghcr image doesn't have it, so it was causing builds to fail.
2025-11-07 11:18:53 +10:00
Jamie Curnow 1a117a267c Fix to postgres 17 2025-10-27 08:13:03 +10:00
Jamie Curnow 5b7013b8d5 Moved certrbot plugin list to backend
frontend doesn't include when building in react version
adds swagger for existing dns-providers endpoint
2025-10-26 00:28:03 +10:00
Jamie Curnow abdf8866e0 Auto sorting of locale files 2025-10-02 08:12:37 +10:00
Jamie Curnow 8884e3b261 TZ for dev db 2025-10-02 08:12:37 +10:00
Jamie Curnow fb2708d81d Fix cypress tests following user wizard changes 2025-10-02 08:12:09 +10:00
Jamie Curnow 0b2fa826e0 Introducing the Setup Wizard for creating the first user
- no longer setup a default
- still able to do that with env vars however
2025-10-02 08:12:05 +10:00
Jamie Curnow fadec9751e React 2025-10-02 08:10:42 +10:00
Jamie Curnow 54d463ac36 Safer and flexible boolean env vars 2025-07-09 21:27:50 +10:00
Jamie Curnow a23dc24021 Tweak ownership output 2025-07-09 21:01:21 +10:00
Jamie Curnow 4f9df893c8 Ownership script shakeup
- Don't touch a file to determine if we need to run
- Instead, check ownership of each location and skip it if we are happy
- Keeping SKIP_CERTBOT_OWNERSHIP flag
- More vebose logging of outcomes
2025-07-09 20:30:27 +10:00
Jamie Curnow 304b38e82b Fix ownership if statement 2025-07-09 18:19:50 +10:00
Jamie Curnow 9a0383bc73 Move SKIP_CERTBOT_OWNERSHIP check around the entire certbot code 2025-07-09 16:30:45 +10:00
Jamie Curnow 1357774f21 Add SKIP_CERTBOT_OWNERSHIP env var support to skip certbot folder ownership 2025-07-09 13:14:27 +10:00
Jamie Curnow 817021a43d Update s6 overlay 2025-07-08 17:32:23 +10:00