Failed authorization procedure for domain

Hi,

I use a nginx proxy for a couple of containers running webapps. One of the domain fails to renew the certificate:

 /opt/letsencrypt/certbot-auto certonly --dry-run -a webroot --webroot-path=/usr/share/nginx/html -d example.com
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for example.com
Using the webroot path /usr/share/nginx/html for all unmatched domains.
Waiting for verification...
Cleaning up challenges
Failed authorization procedure. example.com (http-01): urn:acme:error:unauthorized :: The client lacks sufficient authorization :: Invalid response from http://example.com/.well-known/acme-challenge/SbTnE8YKY7CWnrjqyRRfAHYSfQm-r265js_qdST5o9M: "<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/D"

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

   Domain: example.com
   Type:   unauthorized
   Detail: Invalid response from
   http://example.com/.well-known/acme-challenge/SbTnE8YKY7CWnrjqyRRfAHYSfQm-r265js_qdST5o9M:
   "<?xml version="1.0" encoding="UTF-8"?>
   <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
     "http://www.w3.org/TR/xhtml1/D"

   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.

and I don´t know why. The other domains are working perfectly as they us the same webroot path.

Here is the config for the domain:

renew_before_expiry = 30 days

cert = /etc/letsencrypt/live/example.com/cert.pem
privkey = /etc/letsencrypt/live/example.com/privkey.pem
chain = /etc/letsencrypt/live/example.com/chain.pem
fullchain = /etc/letsencrypt/live/example.com/fullchain.pem
version = 0.13.0
archive_dir = /etc/letsencrypt/archive/example.com

# Options and defaults used in the renewal process
[renewalparams]
installer = None
authenticator = webroot
rsa_key_size = 4096
account = 0xxxxxxxxxxxxxxxxxx
post_hook = service nginx reload
[[webroot_map]]
example.com = /usr/share/nginx/html
www.example.com = /usr/share/nginx/html

and here the nginx config:

## example.com ##
server {
    listen       5.19.xxx.xx:80;
    server_name  example.com www.example.com;
    access_log  /var/log/nginx/example.com.access.log;
    error_log  /var/log/nginx/example.com.error.log;
    index  index.html index.htm;
    include /etc/nginx/snippets/letsencrypt-acme-challenge.conf;

    ## send request back to container ##
    location / {
    return 301 https://$server_name$request_uri;
  }
}
server {
    listen     5.19.xxx.xx:443;
    server_name  example.com www.example.com;
    ssl on;
    ssl_session_timeout 24h;
    ssl_ciphers AES256+EECDH:AES256+EDH:!aNULL;
    ssl_prefer_server_ciphers on;
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.4.4 8.8.8.8 valid=300s;
    resolver_timeout 10s;
    spdy_keepalive_timeout 300;
    spdy_headers_comp 9;
    add_header Strict-Transport-Security max-age=63072000;
    add_header X-Frame-Options DENY;
    add_header X-Content-Type-Options nosniff;
    ssl_trusted_certificate /var/lib/certs/ocsp.trust;
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    ssl_session_cache shared:SSL:10m;
    ssl_protocols  TLSv1 TLSv1.1 TLSv1.2;  # don’t use SSLv3 ref: POODLE

    access_log  /var/log/nginx/ssl.example.com.access.log;
    error_log  /var/log/nginx/ssl.example.com.log;
    root   /usr/share/nginx/html;
    index  index.html index.htm;

    client_max_body_size 30M;

    ## send request back to container ##
    location / {
    limit_req      zone=one burst=10 nodelay;
     proxy_pass  http://container10/;
     proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
     proxy_redirect off;
     proxy_buffering off;
     proxy_set_header        Host            $host;
     proxy_set_header        X-Real-IP       $remote_addr;
     proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
     proxy_set_header        X-Forwarded-Proto $scheme;
   }
}
# End example.com ##


cat /etc/nginx/snippets/letsencrypt-acme-challenge.conf
#############################################################################
# Configuration file for Let's Encrypt ACME Challenge location
# This file is already included in listen_xxx.conf files.
# Do NOT include it separately!
#############################################################################
#
# This config enables to access /.well-known/acme-challenge/xxxxxxxxxxx
# on all our sites (HTTP), including all subdomains.
# This is required by ACME Challenge (webroot authentication).
# You can check that this location is working by placing ping.txt here:
# /var/www/letsencrypt/.well-known/acme-challenge/ping.txt
# And pointing your browser to:
# http://xxx.domain.tld/.well-known/acme-challenge/ping.txt
#
# Sources:
# https://community.letsencrypt.org/t/howto-easy-cert-generation-and-renewal-with-nginx/3491
#
#############################################################################

# Rule for legitimate ACME Challenge requests (like /.well-known/acme-challenge/xxxxxxxxx)
# We use ^~ here, so that we don't check other regexes (for speed-up). We actually MUST cancel
# other regex checks, because in our other config files have regex rule that denies access to files with dotted names.
location ^~ /.well-known/acme-challenge/ {
    # Set correct content type. According to this:
    # https://community.letsencrypt.org/t/using-the-webroot-domain-verification-method/1445/29
    # Current specification requires "text/plain" or no content header at all.
    # It seems that "text/plain" is a safe option.
    default_type "text/plain";

    # This directory must be the same as in /etc/letsencrypt/cli.ini
    # as "webroot-path" parameter. Also don't forget to set "authenticator" parameter
    # there to "webroot".
    # Do NOT use alias, use root! Target directory is located here:
    # /var/www/common/letsencrypt/.well-known/acme-challenge/
    root         /usr/share/nginx/html;
    try_files $uri /$1;
}

# Hide /acme-challenge subdirectory and return 404 on all requests.
# It is somewhat more secure than letting Nginx return 403.
# Ending slash is important!
location = /.well-known/acme-challenge/ {
    return 404;
}

I can see that the directory acme-challenge and challenge files being created. Still can´t figure out why this doesnt work for this domain only.
Any hints are much appreciated. Thank you

Hi @Mechanix,

Do you have an IPv6 address for this domain?

Have you tried making your own test files under /.well-known/acme-challenge and seeing if you can access them in a browser?

Hi @schoen,

well, acme-challenge is created only during the renewal process and gets removed afterwards. But I´ve created the directory manually and I can access the file (test.html) without being redirected.

It seems to be a parsing/encoding issue:

"<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/D"

Hi @Mechanix,

The certificate authority is quoting back what it received from the server, which might be the beginning of the HTML code for a 404 Not Found page or something. Normally what it receives in this case should be a tiny text file that was created by Certbot as part of the validation process.

So, you’re saying that if you put a file /usr/share/nginx/html/.well-known/acme-challenge/test.txt, you’ll see the contents of that same file at both http://example.com/.well-known/acme-challenge/test.txt and http://www.example.com/.well-known/acme-challenge/test.txt?

And do you have an IPv6 address advertised for this host?

HI,

yes, if I create the directory /usr/share/nginx/html/.well-known/acme-challenge/ I can see the tiny text file. If I create a index.html file I can access it both from www. and TLD

This is so weird.

Hi @Mechanix,

I’m afraid I’ll have to ask you a third time if you have an IPv6 address advertised for this server, via an AAAA record in DNS. I can’t check for myself because I don’t know what your domain name is, so I’m relying on you to check.

Hi @schoen,

yes, AAAA records are present, sorry.

It is very common that a site lacks IPv6 connectivity, or is not configured to respond to IPv6 requests, even though it appears to work in a browser. This condition will cause the Let’s Encrypt validation to fail with an error like the one that you saw.

Thank you for your reply. I will delete those AAAA entries in the DNS and check again. Thank you

Thank you very much. That was it!

BTW it would be more helpful if the error handling would be more precise about why the renewal process is failing.

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