Checklist
- Have you pulled and found the error with
jc21/nginx-proxy-manager:latest docker image?
- Are you sure you're not using someone else's docker image?
- Have you searched for similar issues (both open and closed)?
Describe the bug
Nginx Proxy Manager fails during backend startup when stored DNS provider credentials contain shell-significant characters.
In my case this happened with the Strato DNS challenge. The password contained a single quote ' and a pipe |.
During startup, NPM recreates /etc/letsencrypt/credentials/credentials-<id>. That write path appears to use a shell echo '...' > file command. If the credentials contain a single quote, shell quoting breaks. If the remaining value contains |, /bin/sh interprets it as a pipe
and startup aborts.
This causes the backend to crash before startup completes.
Relevant log excerpt:
❯ Starting backend ...
[4/1/2026] [11:34:44 AM] [Global ] › ℹ info Using Sqlite: /data/database.sqlite
[4/1/2026] [11:34:44 AM] [Migrate ] › ℹ info Current database version: none
[4/1/2026] [11:34:44 AM] [Certbot ] › ▶ start Installing strato...
node:internal/process/promises:394
triggerUncaughtException(err, true /* fromPromise */);
^
[Error: /bin/sh: 2: Syntax error: "|" unexpected
] {
This does not look Strato-specific. It should likely affect any DNS provider credentials containing characters that are unsafe in shell-quoted strings.
Nginx Proxy Manager Version
2.14.0
To Reproduce
1. Configure a Let's Encrypt DNS challenge certificate
2. Use DNS provider credentials where the secret contains a single quote '
3. Include another shell metacharacter after that, for example |
4. Restart the container
5. Observe backend startup failure
Expected behavior
Credentials should be written safely regardless of password contents. Special characters in secrets should not break startup.
Screenshots
N/A
Operating System
docker --version
Docker version 27.1.2-qnap8, build b8cbe19
Additional context
A local workaround/fix was to stop writing the credentials file through a shell command and instead write it directly from Node.js, for example with fs.writeFileSync(...).
That avoids failures with ', |, backslashes, $, and multiline values.
Possible fix
The credentials bootstrap in setup.js should avoid shell-based file creation.
Instead of building a shell command that writes the credentials file via echo '...' > file, write the file directly from Node.js. That avoids shell parsing entirely and should safely handle ', |, $, backslashes, and multiline secrets.
For example, the startup code could do something like this:
import fs from "node:fs";
// Make sure credentials file exists
const credentials_loc = `/etc/letsencrypt/credentials/credentials-${certificate.id}`;
if (typeof certificate.meta.dns_provider_credentials === "string") {
promises.push(
Promise.resolve().then(() => {
fs.mkdirSync("/etc/letsencrypt/credentials", { recursive: true });
try {
fs.writeFileSync(credentials_loc, certificate.meta.dns_provider_credentials, {
flag: "wx",
mode: 0o600,
});
fs.chmodSync(credentials_loc, 0o600);
} catch (err) {
if (err?.code !== "EEXIST") {
throw err;
}
}
}),
);
}
This preserves the current "create only if missing" behavior, but removes the shell quoting problem entirely.
Checklist
jc21/nginx-proxy-manager:latestdocker image?Describe the bug
Nginx Proxy Manager fails during backend startup when stored DNS provider credentials contain shell-significant characters.
In my case this happened with the Strato DNS challenge. The password contained a single quote
'and a pipe|.During startup, NPM recreates
/etc/letsencrypt/credentials/credentials-<id>. That write path appears to use a shellecho '...' > filecommand. If the credentials contain a single quote, shell quoting breaks. If the remaining value contains|,/bin/shinterprets it as a pipeand startup aborts.
This causes the backend to crash before startup completes.
Relevant log excerpt:
docker --version
Docker version 27.1.2-qnap8, build b8cbe19