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
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.
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
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
}
}
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!