Unable to renew certificate - client lacks authorization

Been unable to renew my certificate since I started using it about a year ago. Two times I’ve been able to obtain new ones, but never renewed. Thought I’d finally try to get to the bottom with this.

I’m running nginx 1.6.2 on Raspbian Jessie on a Raspberry Pi.

Running sudo certbot renew --dry-run I get the following output:

Saving debug log to /var/log/letsencrypt/letsencrypt.log

-------------------------------------------------------------------------------
Processing /etc/letsencrypt/renewal/<domain>.conf
-------------------------------------------------------------------------------
Cert is due for renewal, auto-renewing...
Starting new HTTPS connection (1): acme-staging.api.letsencrypt.org
Renewing an existing certificate
Performing the following challenges:
http-01 challenge for <domain>
Waiting for verification...
Cleaning up challenges
Attempting to renew cert from /etc/letsencrypt/renewal/<domain>.conf produced an unexpected error: Failed authorization procedure. <domain> (http-01): urn:acme:error:unauthorized :: The client lacks sufficient authorization :: Invalid response from http://<domain>/.well-known/acme-challenge/a0GEz736YTMbYjSPyZtWd7tXG8fPNeonHcU0zpNRsto: "<!DOCTYPE html>
<html class="ng-csp" data-placeholder-focus="false" lang="en" >
        <head data-requesttoken="OdfXMUAY7BeoAR4BksbCzx". Skipping.
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates below have not been saved.)

All renewal attempts failed. The following certs could not be renewed:
  /etc/letsencrypt/live/<domain>/fullchain.pem (failure)
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates above have not been saved.)
1 renew failure(s), 0 parse failure(s)

IMPORTANT NOTES:
 - The following errors were reported by the server:

   Domain: <domain>
   Type:   unauthorized
   Detail: Invalid response from
   http://<domain>/.well-known/acme-challenge/a0GEz736YTMbYjSPyZtWd7tXG8fPNeonHcU0zpNRsto:
   "<!DOCTYPE html>
   <html class="ng-csp" data-placeholder-focus="false" lang="en" >
           <head data-requesttoken="OdfXMUAY7BeoAR4BksbCzx"

   To fix these errors, please make sure that your domain name was
   entered correctly and the DNS A record(s) for that domain
   contain(s) the right IP address.

This is my nginx site configuration:

server {
	listen 80 default_server;
	listen [::]:80 default_server;
	server_name <domain>;
	return 301 https://$server_name$request_uri;
}

server {
	listen 443 ssl;
	server_name <domain>;
	
	ssl_certificate /etc/letsencrypt/live/<domain>/fullchain.pem;
	ssl_certificate_key /etc/letsencrypt/live/<domain>/privkey.pem;
	
	# Add headers to serve security related headers
	# Before enabling Strict-Transport-Security headers please read into this
	# topic first.
	# add_header Strict-Transport-Security "max-age=15768000;
	# includeSubDomains; preload;";
	add_header X-Content-Type-Options nosniff;
	add_header X-Frame-Options "SAMEORIGIN";
	add_header X-XSS-Protection "1; mode=block";
	add_header X-Robots-Tag none;
	add_header X-Download-Options noopen;
	add_header X-Permitted-Cross-Domain-Policies none;

	# Path to the root of your installation
	root /srv/www/nextcloud;

	location = /robots.txt {
		allow all;
		log_not_found off;
		access_log off;
	}
	
	# The following 2 rules are only needed for the user_webfinger app.
	# Uncomment it if you're planning to use this app.
	#rewrite ^/.well-known/host-meta /public.php?service=host-meta last;
	#rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json
	# last;

	location = /.well-known/carddav {
		return 301 $scheme://$host/remote.php/dav;
	}
	location = /.well-known/caldav {
		return 301 $scheme://$host/remote.php/dav;
	}
	
	location /.well-known/acme-challenge { }
	
	# set max upload size
	client_max_body_size 512M;
	fastcgi_buffers 64 4K;

	# Disable gzip to avoid the removal of the ETag header
	gzip off;

	# Uncomment if your server is build with the ngx_pagespeed module
	# This module is currently not supported.
	#pagespeed off;

	error_page 403 /core/templates/403.php;
	error_page 404 /core/templates/404.php;

	location / {
		rewrite ^ /index.php$uri;
	}

	location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)/ {
		deny all;
	}
	location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) {
		deny all;
	}
	
	location ~ ^/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|ocs-provider/.+|core/templates/40[34])\.php(?:$|/) {
		include fastcgi_params;
		fastcgi_split_path_info ^(.+\.php)(/.*)$;
		fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
		fastcgi_param PATH_INFO $fastcgi_path_info;
		fastcgi_param HTTPS on;
		#Avoid sending the security headers twice
		fastcgi_param modHeadersAvailable true;
		fastcgi_param front_controller_active true;
		fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
		fastcgi_intercept_errors on;
	}

	location ~ ^/(?:updater|ocs-provider)(?:$|/) {
		try_files $uri/ =404;
		index index.php;
	}

	# Adding the cache control header for js and css files
	# Make sure it is BELOW the PHP block
	location ~* \.(?:css|js)$ {
		try_files $uri /index.php$uri$is_args$args;
		add_header Cache-Control "public, max-age=7200";
		# Add headers to serve security related headers (It is intended to
		# have those duplicated to the ones above)
		# Before enabling Strict-Transport-Security headers please read into
		# this topic first.
		# add_header Strict-Transport-Security "max-age=15768000;
		#  includeSubDomains; preload;";
		add_header X-Content-Type-Options nosniff;
		add_header X-Frame-Options "SAMEORIGIN";
		add_header X-XSS-Protection "1; mode=block";
		add_header X-Robots-Tag none;
		add_header X-Download-Options noopen;
		add_header X-Permitted-Cross-Domain-Policies none;
		# Optional: Don't log access to assets
		access_log off;
	}

	location ~* \.(?:svg|gif|png|html|ttf|woff|ico|jpg|jpeg)$ {
		try_files $uri /index.php$uri$is_args$args;
		# Optional: Don't log access to other assets
		access_log off;
	}
}

Replaced all occurences of my actual domain with <domain>. Can PM actual domain if required.

My site is currently working with the certificate. Expires in a few days.

Try something more like:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name <domain>
location /.well-known/acme-challenge/ {
access_log /var/log/nginx/acme_access.log;
error_log /var/log/nginx/acme_error.log;
root /var/lib/letsencrypt/acme/;
}
location / {
return 301 https://$server_name$request_uri;
}
}

Hi,
Thanks for the reply. Didn’t work, sady. Got a slightly different error. (404)

Saving debug log to /var/log/letsencrypt/letsencrypt.log

-------------------------------------------------------------------------------
Processing /etc/letsencrypt/renewal/<domain>.conf
-------------------------------------------------------------------------------
Cert is due for renewal, auto-renewing...
Starting new HTTPS connection (1): acme-staging.api.letsencrypt.org
Renewing an existing certificate
Performing the following challenges:
http-01 challenge for <domain>
Waiting for verification...
Cleaning up challenges
Attempting to renew cert from /etc/letsencrypt/renewal/<domain>.conf produced an unexpected error: Failed authorization procedure. <domain> (http-01): urn:acme:error:unauthorized :: The client lacks sufficient authorization :: Invalid response from http://<domain>/.well-known/acme-challenge/tWKrAScTmAmRXvQezHQq4-yG-PUNA_rCMOEG3kIG0Rs: "<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>". Skipping.
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates below have not been saved.)

All renewal attempts failed. The following certs could not be renewed:
  /etc/letsencrypt/live/<domain>/fullchain.pem (failure)
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates above have not been saved.)
1 renew failure(s), 0 parse failure(s)

IMPORTANT NOTES:
 - The following errors were reported by the server:

   Domain: <domain>
   Type:   unauthorized
   Detail: Invalid response from
   http://<domain>/.well-known/acme-challenge/tWKrAScTmAmRXvQezHQq4-yG-PUNA_rCMOEG3kIG0Rs:
   "<html>
   <head><title>404 Not Found</title></head>
   <body bgcolor="white">
   <center><h1>404 Not Found</h1></center>
   <hr><center>"

   To fix these errors, please make sure that your domain name was
   entered correctly and the DNS A record(s) for that domain
   contain(s) the right IP address.

Here’s the permissions on my well known folder:
drwxr-xr-x 2 root root 4096 Jul 6 14:11 .well-known

I don’t really know wherein the error lies.

Hi @Lombra,

Do you have an AAAA record in DNS?

If you create a text file in .well-known/acme-challenge, can you access it over the web using a web browser?

No AAAA record.

I made /srv/www/nextcloud/.well-known/acme-challenge/test. Everyone has read permissions. Site returns 403 access forbidden for https://<domain>/.well-known/acme-challenge/test.

That blocks access to /.well-known/acme-challenge/.

It should work if it also has:

	location ^~ /.well-known/acme-challenge/ { }

Or the regular expression at issue could be changed or removed. Or this could be handled over HTTP, rather than redirecting /.well-known/acme-challenge/ requests to HTTPS.

What does Nginx’s error.log say?

1 Like

That seems to have done the trick. Thank you!

I mostly copied the configuration from some guide, and I already had location /.well-known/acme-challenge/ { }, which I thought would work. Adding ^~ fixed it. Don’t know if that will conflict with anything else, (don’t fully understand the nginx location directives) but certificate renewal works, at least.

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