Unable to renew LetsEncrypt certificate (HTTP-01 challenge failed)

Nearly three months ago I started up a web server for my website and purchased a domain. I have three Docker containers running, one for nginx (jonasal/nginx-certbot), one for a mysql database, and one for the Flask app. I recently received an email from LetsEncrypt to renew the certificate so I have attempted to run the renew command within the nginx container but I am encountering errors.

I have already tried:

  • Setting the permissions of the webroot path and the challenges location (www-data now has permissions to /var/www/letsencrypt/.well-known/acme-challenge)
  • Checking firewall permissions (port 80 is not blocked)
  • Checking DNS settings (my domain points to where the certbot is running)

Not sure what other approach to take, any help is appreciated!

My domain is: emilyllim.com

I ran this command: certbot renew -v (within my jonasal/nginx-certbot Docker container)

It produced this output:

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

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/myportfolio.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Certificate is due for renewal, auto-renewing...
Plugins selected: Authenticator webroot, Installer None
Renewing an existing certificate for emilyllim.com
Performing the following challenges:
http-01 challenge for emilyllim.com
Using the webroot path /var/www/letsencrypt for all unmatched domains.
Waiting for verification...
Challenge failed for domain emilyllim.com
http-01 challenge for emilyllim.com

Certbot failed to authenticate some domains (authenticator: webroot). The Certificate Authority reported these problems:
  Domain: emilyllim.com
  Type:   unauthorized
  Detail: 159.65.64.34: Invalid response from https://emilyllim.com/.well-known/acme-challenge/zx6bcyDvY-xiHIek-q1OowjzhEBGNWiHcQ0ftlwYOTk: "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <!-- Required meta tags -->\n    <meta charset=\"utf-8\" />\n    <meta\n      name=\"vie"

Hint: The Certificate Authority failed to download the temporary challenge files created by Certbot. Ensure that the listed domains serve their content from the provided --webroot-path/-w and that files created there can be downloaded from the internet.

Cleaning up challenges
Failed to renew certificate myportfolio with error: Some challenges have failed.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
All renewals failed. The following certificates could not be renewed:
  /etc/letsencrypt/live/myportfolio/fullchain.pem (failure)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1 renew failure(s), 0 parse failure(s)
Ask for help or search for solutions at https://community.letsencrypt.org. See the logfile /var/log/letsencrypt/letsencrypt.log or re-run Certbot with -v for more details.

My web server is (include version): nginx/1.25.3

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

My hosting provider, if applicable, is: DigitalOcean

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.7.4

Welcome @ell-site

The above error indicates a couple things. One is that you redirect the original HTTP ACME Challenge request to HTTPS. That is not harmful but it is better if you handle it right in HTTP.

The main problem is your response is supposed to be the challenge token placed by Certbot. Instead it looks like your home page.

This is probably something wrong in your nginx config. Can you show the entire output by running nginx -T ? Please add 3 backticks before and after the very long output to maintain formatting. Like:
```
output of: sudo nginx -T
```
capital T is essential as are backticks (not single quotes)
Edit: sudo probably not needed inside container

2 Likes

This is the output of nginx-T:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
# configuration file /etc/nginx/nginx.conf:

user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


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

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
}

# configuration file /etc/nginx/mime.types:

types {
    text/html                                        html htm shtml;
    text/css                                         css;
    text/xml                                         xml;
    image/gif                                        gif;
    image/jpeg                                       jpeg jpg;
    application/javascript                           js;
    application/atom+xml                             atom;
    application/rss+xml                              rss;

    text/mathml                                      mml;
    text/plain                                       txt;
    text/vnd.sun.j2me.app-descriptor                 jad;
    text/vnd.wap.wml                                 wml;
    text/x-component                                 htc;

    image/avif                                       avif;
    image/png                                        png;
    image/svg+xml                                    svg svgz;
    image/tiff                                       tif tiff;
    image/vnd.wap.wbmp                               wbmp;
    image/webp                                       webp;
    image/x-icon                                     ico;
    image/x-jng                                      jng;
    image/x-ms-bmp                                   bmp;

    font/woff                                        woff;
    font/woff2                                       woff2;

    application/java-archive                         jar war ear;
    application/json                                 json;
    application/mac-binhex40                         hqx;
    application/msword                               doc;
    application/pdf                                  pdf;
    application/postscript                           ps eps ai;
    application/rtf                                  rtf;
    application/vnd.apple.mpegurl                    m3u8;
    application/vnd.google-earth.kml+xml             kml;
    application/vnd.google-earth.kmz                 kmz;
    application/vnd.ms-excel                         xls;
    application/vnd.ms-fontobject                    eot;
    application/vnd.ms-powerpoint                    ppt;
    application/vnd.oasis.opendocument.graphics      odg;
    application/vnd.oasis.opendocument.presentation  odp;
    application/vnd.oasis.opendocument.spreadsheet   ods;
    application/vnd.oasis.opendocument.text          odt;
    application/vnd.openxmlformats-officedocument.presentationml.presentation
                                                     pptx;
    application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
                                                     xlsx;
    application/vnd.openxmlformats-officedocument.wordprocessingml.document
                                                     docx;
    application/vnd.wap.wmlc                         wmlc;
    application/wasm                                 wasm;
    application/x-7z-compressed                      7z;
    application/x-cocoa                              cco;
    application/x-java-archive-diff                  jardiff;
    application/x-java-jnlp-file                     jnlp;
    application/x-makeself                           run;
    application/x-perl                               pl pm;
    application/x-pilot                              prc pdb;
    application/x-rar-compressed                     rar;
    application/x-redhat-package-manager             rpm;
    application/x-sea                                sea;
    application/x-shockwave-flash                    swf;
    application/x-stuffit                            sit;
    application/x-tcl                                tcl tk;
    application/x-x509-ca-cert                       der pem crt;
    application/x-xpinstall                          xpi;
    application/xhtml+xml                            xhtml;
    application/xspf+xml                             xspf;
    application/zip                                  zip;

    application/octet-stream                         bin exe dll;
    application/octet-stream                         deb;
    application/octet-stream                         dmg;
    application/octet-stream                         iso img;
    application/octet-stream                         msi msp msm;

    audio/midi                                       mid midi kar;
    audio/mpeg                                       mp3;
    audio/ogg                                        ogg;
    audio/x-m4a                                      m4a;
    audio/x-realaudio                                ra;

    video/3gpp                                       3gpp 3gp;
    video/mp2t                                       ts;
    video/mp4                                        mp4;
    video/mpeg                                       mpeg mpg;
    video/quicktime                                  mov;
    video/webm                                       webm;
    video/x-flv                                      flv;
    video/x-m4v                                      m4v;
    video/x-mng                                      mng;
    video/x-ms-asf                                   asx asf;
    video/x-ms-wmv                                   wmv;
    video/x-msvideo                                  avi;
}

# configuration file /etc/nginx/conf.d/myportfolio.conf:
server {
    listen 80; # listen for HTTP traffic at 80
    server_name emilyllim.com;

    if ($host = emilyllim.com) {
        return 301 https://$host$request_uri; # redirect to HTTPS
    }
}

server {
    listen 443 ssl; # listen for HTTPS traffic at 443
    server_name emilyllim.com;

    location / { # reverse proxy traffic to myportfolio container 5000
        proxy_pass http://myportfolio:5000/;
    }

    # load the certificate files from LetsEncrypt (used by jonasal/nginx/certbot)
    ssl_certificate /etc/letsencrypt/live/myportfolio/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/myportfolio/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/myportfolio/chain.pem;
}

# configuration file /etc/nginx/conf.d/redirector.conf:
server {
    # Listen on plain old HTTP and catch all requests so they can be redirected
    # to HTTPS instead.
    listen 80 default_server reuseport;
    listen [::]:80 default_server reuseport;

    # Anything requesting this particular URL should be served content from
    # Certbot's folder so the HTTP-01 ACME challenges can be completed for the
    # HTTPS certificates.
    location '/.well-known/acme-challenge' {
        default_type "text/plain";
        root /var/www/letsencrypt;
    }

    # Everything else gets shunted over to HTTPS for each user defined
    # server to handle.
    location / {
        return 301 https://$http_host$request_uri;
    }
}

I see that HTTP requests are redirected to HTTPS in the config.

I am not sure what you mean by this and why it is not recommended.

1 Like

The above is the server block handling HTTP requests for that domain name.

Adding the below lines from your default server to the above server block should fix your problem

    # Anything requesting this particular URL should be served content from
    # Certbot's folder so the HTTP-01 ACME challenges can be completed for the
    # HTTPS certificates.
    location '/.well-known/acme-challenge' {
        default_type "text/plain";
        root /var/www/letsencrypt;
    }

What I mean is that LE Server sends an HTTP request for the challenge. You were replying to LE with a redirect. LE sends a second request using HTTPS (as that is what you redirected to) and your server then replied (wrongly so far).

It is best if you just return the correct result with the first HTTP request. Redirecting LE and making it do a second request is just wasteful. And more complicated for things to go wrong. Especially now that I see you proxy all requests in your HTTPS server block

3 Likes

Sorry, I made the correction in haste. I am not sure that the IF statement takes precedence over Location. So below is more typically how that is done:

# configuration file /etc/nginx/conf.d/myportfolio.conf:
server {
    listen 80; # listen for HTTP traffic at 80
    server_name emilyllim.com;

    location /.well-known/acme-challenge {
        default_type "text/plain";
        root /var/www/letsencrypt;
    }
    location / {
        return 301 https://$host$request_uri; # redirect to HTTPS
    }
}
3 Likes

I see. This makes sense and is much more clear than what I had before. I added your suggestions to the config and restarted the web server and it looks like the certificate automatically renewed. Thank you so much, I appreciate your help!

2 Likes

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