NginxProxyManager/nginx-proxy-manager · error

Plugin not found

Error message

Plugin not found

What it means

This is an HTTP 404 from POST /api/nginx/certificates/:plugin (the certbot DNS plugin install endpoint) in backend/routes/ci.js. It compares req.params.plugin against the dnsPlugins registry; an unknown or misspelled name yields a 404 with error "Plugin not found" instead of attempting a package install.

Source

Thrown at backend/routes/ci.js:45

		res.status(200).send(dnsPlugins);
	});

/**
 * /api/ci/certbot-plugins/{plugin}
 */
router
	.route("/certbot-plugins/:plugin")
	.options((_, res) => {
		res.sendStatus(204);
	})

	// Install a certbot plugin
	.post(async (req, res, next) => {
		try {
			const pluginName = req.params.plugin;
			// check if plugin exists
			if (!dnsPlugins[pluginName]) {
				return res.status(404).send({
					error: "Plugin not found",
				});
			}

			await installPlugin(pluginName);
			res.status(200).send(true);
		} catch (err) {
			debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`);
			next(err);
		}
		return;
	});

export default router;

View on GitHub (pinned to 934a3fafe5)

Solutions

  1. Check the exact key in backend/internal/dns-plugins.js (the dnsPlugins object) and use that slug verbatim, e.g. 'cloudflare', 'digitalocean', 'google'
  2. List available plugins first (the GET side of the same route / docs) and pick the key, not the display name
  3. If the provider genuinely is missing, upgrade NPM to a version that includes the dns-plugins entry, or add a custom entry locally and rebuild

Example fix

# before
curl -X POST https://npm.example.com/api/nginx/certificates/Cloudflare

# after
curl -X POST https://npm.example.com/api/nginx/certificates/cloudflare
Defensive patterns

Strategy: validation

Validate before calling

import dnsPlugins from './internal/dns-plugins.js';

const pluginExists = (name: string) => Object.prototype.hasOwnProperty.call(dnsPlugins, name);

if (!pluginExists(pluginName)) {
  throw new Error(`Unsupported plugin '${pluginName}'. Available: ${Object.keys(dnsPlugins).join(', ')}`);
}

Type guard

const isKnownDnsPlugin = (name: string): name is keyof typeof dnsPlugins =>
  Object.prototype.hasOwnProperty.call(dnsPlugins, name);

Try / catch

const res = await fetch(`/api/nginx/certificates/${plugin}`);
if (res.status === 404) {
  // re-fetch the plugin list and reconcile the slug before retrying
}

Prevention

When it happens

Trigger: POSTing to the endpoint with a plugin slug that is not a key of the dnsPlugins map — e.g. 'cloudflaree', 'route53' when unsupported, or passing a display name like 'Cloudflare DNS' instead of the slug 'cloudflare'.

Common situations: Typos in the plugin slug from hand-crafted curl/API scripts, UI dropdowns sending labels instead of keys, or scripts written against an older/newer version of NPM whose dnsPlugins registry differs (provider added/removed in that version).

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of NginxProxyManager/nginx-proxy-manager@934a3fafe5 (2026-08-27). Data as JSON: /api/errors/f41713291b7d71ef. Report an issue: GitHub.