Certbot fails 404 on nginx, succeeds on webroot

I've seen all the 404 Q's here I could manage without my brain melting. Mine seems not to match the others well in detail. I can use the --webroot flavor of certbot commands to get a cert (dry runs only so far), but the preferable --nginx flavor instead fails with 404 every time, dry run or real run.

I have nginx set up to proxy to local Node.js apps with subdomains, but I'm setting that all aside as needed to get HTTPS working; to work with certbot, I put in a first-in-server-block root /var/www directive (not /var/www/html for now at least), and made sure I could access an HTML file there using curl with nginx running. Actually I added a .well-known/acme-challenge subfolder tree there as well and can get HTML from there.

Oh yes, I also saw old advice here about using let's debug . net, and I tried that. It said there were no apparent issues with the site.

Anyway, what am I doing wrong? Surely it isn't supposed to be this hard. I'm a newbie to this stuff but not an idiot. What have I missed?

Please fill out the fields below so we can help you better. Note: you must provide your domain name to get help. Domain names for issued certificates are all made public in Certificate Transparency logs (e.g. crt.sh | example.com), so withholding your domain name here does not increase secrecy, but only makes it harder for us to provide help.

My domain is: jadeemperorware.com

I ran this command:

  • Fails: certbot --nginx -d jadeemperorware.com
  • Succeeds: certbot --dry-run --webroot -w /var/www -d jadeemperorware.com

It produced this output:

  • Fails:
Certbot failed to authenticate some domains (authenticator: nginx). The Certificate Authority reported these problems:
  Domain: jadeemperorware.com
  Type:   unauthorized
  Detail: Invalid response from http://jadeemperorware.com/.well-known/acme-challenge/R4kJVcmXNSRQBoJoyCu9U9mCVdirBSfcuBSz72vV5jc: 404
  • Succeeds:
Simulating a certificate request for jadeemperorware.com
The dry run was successful.

My web server is (include version): nginx/1.18.0 (Ubuntu)

The operating system my web server runs on is (include version):

VERSION="22.04.2 LTS (Jammy Jellyfish)"

My hosting provider, if applicable, is: Vultr

I can login to a root shell on my machine (yes or no, or I don't know): Yes

I'm using a control panel to manage my site (no, or provide the name and version of the control panel): No

The version of my client is (e.g. output of certbot --version or certbot-auto --version if you're using Certbot): certbot 2.5.0

Welcome @jadeemperor

The --nginx plug-in does not use a file in /.well-known folder. It makes temp changes to your nginx config to return the result and removes those changes after

You can see this in the log file

I would be happy to help further but it is late and I am signing off for the night. perhaps this info is a clue to help you find the reason for the failure. If no one else helps I will check in tomorrow


Maybe showing the nginx config may shed some light on the matter.
nginx -T


Hi, thanks to both of you for replying. Yes, I saw that message in the logging for the bot. Anyway here is the .conf contents as suggested, this is sans any changes by the bot. I'm going to sleep soon too and as this is not a site that customers are depending on, it is free of that kind of urgency.

According to the nginx output, the file is OK. By its standards anyway. I'm skipping the contents from linked files. I disabled the lines that would bring in config from other files, but those made no difference. As in, it failed the same way when they were enabled and that other content was inlined into nginx's active configuration.

I always ran nginx -s reload after changes.


user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
	worker_connections 768;
	# multi_accept on;

http {

	# Basic Settings

	sendfile on;
	tcp_nopush on;
	types_hash_max_size 2048;

	include /etc/nginx/mime.types;
	default_type application/octet-stream;

	# SSL Settings

	ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
	ssl_prefer_server_ciphers on;

	# Logging Settings

	access_log /var/log/nginx/access.log;
	error_log /var/log/nginx/error.log;

	gzip on;

	# These must be disabled to prevent secondary configuration you don't want.
	# Conversely, they can be enabled, and the files customized, to provide 
	# site-specific configuration that you do want.

	#include /etc/nginx/conf.d/*.conf;
	#include /etc/nginx/sites-enabled/*;

	server {
	    	# `listen` directive needed for any listening to work.
		# The IP address must be present, unlike examples online.


		# Allowing files to be served from a default location.

		location / {
			root /var/www;

		# KonekoJs as the key non-default, matching konekojs.deusware.com for now.

		location /konekojs/ {
			proxy_pass http://localhost:7666/;

		# Redirects, but site only works if its services have separate 
		# redirections as long as they are at the same URL level.

		location /plainwrite/ {
			proxy_pass http://localhost:2000/;

		# These redirect services used by PlainWrite. 

		location /users/ {
			proxy_pass http://localhost:2000/users/;

		location /texts/ {
			proxy_pass http://localhost:2000/texts/;
1 Like

Try adding a server_name in that block for your domain

Also probably best to not use the IP in the listen - just use port


Hi, thanks. I'll try server_name. As for the IP, I only did that because it didn't work without it. Perhaps that was a side effect though of all the conf files being used. I'll try it again and see if I can get it rolling.

1 Like


Thanks a lot @MikeMcQ and @rg305, that did it!

To put it more specifically for others who may come this way:

Taking MikeMcQ's two suggestions together (add a server_name directive in nginx.conf, drop IP address from the listen directive there) solved my 404 problem and got the --nginx flavor of certbot to work, both with --dry-run and with real certificate generation / verification.

This success comes in the context of having a location / { ...webroot-path... } directive in the conf file. I mention this because the first problem I had, well before posting here, was that the domain's root URL ( jadeemperorware . com ) was redirected to apps internally with proxy_pass. However well that may / may not work with certbot if you know more than me, it appears not to be the right basic approach.

Fascinating to know that something that seems optional like server_name makes such a difference. I had to include IP address in the past for some reason, I will have to further review why at some point. Still things to learn, clearly!

In conclusion... The nginx.conf file includes certbot's verified emendations. And my (placeholder) page itself is accessible from a browser now using HTTPS too, so the final and acid test has passed.

Thanks again, guys!


This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.