NginxProxyManager / NginxProxyManager/nginx-proxy-manager

Stale/missing nginx config files after editing existing Proxy Hosts, despite DB and UI reporting correct state

Open
#5,690 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
TypeScript
Stars
34.2k
Forks
3.9k
Avg merge
21h 12m
Merged PRs (30d)
20

Description

Checklist

  • Have you pulled and found the error with jc21/nginx-proxy-manager:latest docker image?
    • Yes
  • Are you sure you're not using someone else's docker image?
    • Yes
  • Have you searched for similar issues (both open and closed)?
    • Yes

Describe the bug
After editing an existing Proxy Host's fields (e.g. Forward Hostname/IP, Forward Port) via the Admin UI, the change is correctly saved to the database (confirmed via direct MySQL query) and the UI reflects the new value. The API also reports "nginx_online": true, "nginx_err": null" for the host. However, the actual generated nginx config file on disk (/data/nginx/proxy_host/<id>.conf) is not regenerated and silently retains the old, stale values from before the edit. This results in nginx serving traffic to the wrong backend, even though every layer of the application (database, API response, admin UI) reports the host as correctly configured and online.

In one case, this also occurred after deleting and re-adding Custom Locations on a host, which left a duplicate location block in the generated config, causing nginx to fail config validation (nginx: [emerg] duplicate location "/admin") — visible only via the API's meta.nginx_err field, not the UI.

In another case, the config file was missing entirely for a host that was created and enabled in the database.

Workaround found: Issuing a PUT request to /api/nginx/proxy-hosts/<id> with the host's existing full data (effectively a no-op save via the API) forces NPM to correctly regenerate the on-disk config file.

Nginx Proxy Manager Version
2.15.1 (build 76f09db6)

To Reproduce
Steps to reproduce the behavior:

  1. Have an existing, working Proxy Host (in our case, originally created prior to migrating the underlying database from SQLite to MySQL/MariaDB)
  2. Edit the host's Forward Hostname/IP and/or Forward Port via the Admin UI, and click Save
  3. Confirm via direct database query that the new value was saved correctly
  4. Check the generated config file at /data/nginx/proxy_host/<id>.conf inside the container's /data volume
  5. Observe that the set $server "..."; line (and/or server_name) still contains the old, pre-edit value
  6. Attempt to access the proxied domain — observe a 502 Bad Gateway, or a TLS "unrecognized name" error if the server_name itself is stale

Separately reproducible:

  1. On a Proxy Host with Custom Locations, delete all existing locations and save
  2. Re-add the same location paths (e.g. /admin) and save
  3. Check meta.nginx_err via GET /api/nginx/proxy-hosts/<id> — observe nginx: [emerg] duplicate location "/admin" even though the UI shows no error and the host appears "Online"

Expected behavior
Editing a Proxy Host's fields and saving should always regenerate the on-disk nginx config file to match the database, and the on-disk config should never silently diverge from what the database and UI report. If config generation or nginx validation fails, this should be surfaced clearly to the user, not just exposed via an undocumented meta.nginx_err API field while the UI shows "Online."

Screenshots
N/A (text/log-based bug, see logs below)

Operating System

  • Ubuntu Server (VM), Docker 28.3.3, Docker Compose v2.39.1, x86_64
  • Raspberry Pi 3B running DietPi, Docker 29.6.0, Docker Compose v5.2.0, ARM64 (same bug reproduced independently on this host as well, ruling out architecture-specific cause)

Additional context

  • This environment uses NPM in a 2-node setup sharing a single MariaDB database (yobasystems/alpine-mariadb:latest) for high-availability, with Keepalived managing a floating VIP between the two nodes. The original install long predates the MariaDB migration (was running on SQLite since Jan 2024).
  • All affected proxy hosts were created prior to the SQLite→MariaDB migration and had a field edited post-migration. We have not yet been able to confirm whether the bug also reproduces on hosts created fresh under MySQL/MariaDB from the start — this may be a relevant factor for reproduction.
  • Example of the stale config (host serving Home Assistant): database forward_host correctly showed 192.168.1.15, but the generated config file contained set $server "192.168.1.51"; — an entirely different, unrelated IP (the NPM host's own address) — despite no error being shown anywhere in the UI.
  • Forcing a PUT to /api/nginx/proxy-hosts/<id> with unchanged data reliably regenerates the config correctly and resolves the issue, suggesting the bug is isolated to whatever code path the UI's "Save" button triggers versus the full API update path, or possibly a caching/timing issue in the config-generation worker.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at the Admin UI save path and the PUT /api/nginx/proxy-hosts/ endpoint, then compare how each triggers generation of /data/nginx/proxy_host/.conf. Reproduce with an edited Proxy Host and custom locations, checking the file and meta.nginx_err; done means saved values regenerate reliably and validation failures are surfaced clearly.

Written by the indexing model from the issue text.

Assessment

Tech stack
docker, mariadb, nginx, typescript
Domain
backend, devops, infrastructure
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.