I have this nginx.conf that simply redirects http to htttps. Now for first runs of acme-client, I assume the redirection to https will be a problem given there is no cert nor nginx server block for the new https domain. Does acme-client and letsencrypt have some secret sauce to handle this situation?
Since this will be an infrequent situation, I set up the nginx.conf file with lines to comment out and enable, which is hopefully self-evident.
Comments? Tips? Am I over thinking this? File follows:
user www;
#user nobody;
worker_processes 1;
# This default error log path is compiled-in to make sure configuration parsing
# errors are logged somewhere, especially during unattended boot when stderr
# isn't normally logged anywhere. This path will be touched on every nginx
# start regardless of error log location configured here. See
# https://trac.nginx.org/nginx/ticket/147 for more info.
#
#error_log /var/log/nginx/error.log;
#
#pid logs/nginx.pid;
events {
worker_connections 512;
}
http {
include 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 logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
gzip on;
# This "server kicks the user from http to https #
server {
listen 80;
server_name lazygranch.site www.lazygranch.site;
#access_log logs/host.access.log main;
######## When running acme for the first time, comment out this redirect####
return 301 https://www.lazygranch.site$request_uri;
######## and enable (remove #) this "location" #########
#location /.well-known/acme-challenge/ {
# proxy_redirect off;
# default_type "text/plain";
# alias /usr/local/www/acme/;
# allow all;
}
# HTTPS server
#
server {
listen 443 ssl http2;
server_name lazygranch.site www.lazygranch.site ;
ssl_certificate /usr/local/etc/ssl/acme/lazygranch.site/fullchain.pem;
ssl_certificate_key /usr/local/etc/ssl/acme/private/lazygranch.site/privkey.pem;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location /.well-known/acme-challenge/ {
proxy_redirect off;
default_type "text/plain";
alias /usr/local/www/acme/;
allow all;
}
location / {
root /usr/local/www/nginx/lazygranch.site/public_html;
index index.html index.htm;
}
}
}
I get where your going with this, but has this approach worked with renewals?
Do you feel uncomfortable leaving the .well-known/acme-challenge requests in http and redirecting all other requests to https?
First time trying this reply to email thing. Here goes.
I still need to debug the renewal script. But I meditated on this chicken and egg problem for a while, read some similar posts but not exactly my question, and figured I’d consult the “hive.” That is, I knew I would have a http to https redirect in the final product, so I wanted to understand the issues.
I worked on setting up some logical trap to catch the acme-client request to a new nginx server, only to realize the nginx.conf would need editing anyway, so no use trying to be clever.
You can keep the http to https redirection in the conf from day 1.
If you make the exceptions for the .well-known/* (challenges) requests.
If you control the entire server…
I’ve had success in Apache2 with this global setting:
Alias /.well-known/acme-challenge/ /local/folder/acme-challenge/
forcing all vhosts challenges into just one folder
I will go on the nginx list and see if that is possible. Still I would need to take care of http versus https.
Is there any advantage to renewing certs under https? If not, maybe a fancier redirection could be set up to never redirect the acme-client challenge to https.
Yes you will still need to redirect http to https if you don’t want any http traffic.
That is its’ own issue.
The problem is without proper consideration, after forcing https the http acme-challenges may fail.
Having the ability to exclude only the challenges from https redirection seems to satisfy both requirements.
1) http://www.domain.com/.well-known/acme-challenge/yadayada goes to the
acme directory.
2) https://www.domain.com/.well-known/acme-challenge/yadayada gets converted
to http://www.domain.com/.well-known/acme-challenge/yadayada then goes to
the acme directory
3) http//www.domain.com/notwellknown becomes
https://www.domain.com/notwellknown
4) https://www.domain.com/notwellknown is processed normally as https
I haven’t tested this with the client yet since I don’t want to be up all night. You can see I used a 307 return for the acme https to http. I didn’t want the browser to remember the redirect.
user www;
#user nobody;
worker_processes 1;
# This default error log path is compiled-in to make sure configuration parsing
# errors are logged somewhere, especially during unattended boot when stderr
# isn't normally logged anywhere. This path will be touched on every nginx
# start regardless of error log location configured here. See
# https://trac.nginx.org/nginx/ticket/147 for more info.
#
#error_log /var/log/nginx/error.log;
#
#pid logs/nginx.pid;
events {
worker_connections 512;
}
http {
include 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 logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
gzip on;
# This "server" kicks the user from http to https unless an acme challenge#
server {
listen 80;
server_name lazygranch.site www.lazygranch.site;
#access_log logs/host.access.log main;
# select all port 80 acme requests o
location /.well-known/acme-challenge/ {
proxy_redirect off;
default_type "text/plain";
alias /usr/local/www/acme/;
allow all;
}
#at this point, the goal is just to convert http to https
location / {
return 301 https://www.lazygranch.site$request_uri;
}
}
# HTTPS server
#
server {
listen 443 ssl http2;
server_name lazygranch.site www.lazygranch.site ;
ssl_certificate /usr/local/etc/ssl/acme/lazygranch.site/fullchain.pem;
ssl_certificate_key /usr/local/etc/ssl/acme/private/lazygranch.site/privkey.pem;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
#The assumption here is the acme challege has run successfully at least once
#since the sys admin has written the code to handle this particular domain under port 443.
#However the cert could have issues, so better to switch to port 80
#But we can't lose the the challege code number
location /.well-known/acme-challenge/ {
return 307 http://www.lazygranch.site$request_uri ;
}
#otherwise normal processing
location / {
root /usr/local/www/nginx/lazygranch.site/public_html;
index index.html index.htm;
}
}
}
I didn’t get a 404. I think it works. However there is an issue with the acme-challenge data coming from browser cache. I added an expires -1 to the “location”, but that didn’t force a fresh download.
I logged all my testing here. No use clogging up the forum since I think the nginx.conf still needs a tweek to get around the cache issue. https://pastebin.com/NgUm6ZEH
You should get switched to plain http. If your cache is clear, I will eventually see a 200 response on my server. You can tell me the exact time you clicked on the link and I will post the response minus your IP address.
In the event there is an issue with the cert, I rather have the challenge go to the http. Apparently letsencrypt has three modes (challenges?). One is DNS, which I didn’t see offered but I saw referenced in posts. The other two being https and http. I ran across some post where https was causing a renewal issue. Since letencrypt works with http, I figured I would make that the default.
Also note that if I set up an automatic http to https for the websites in general, I needed to prevent the challenge from being redirected to https, which on the first run wouldn’t even exist.
Basically I’m covering my bases here since this is supposedly to be all automatic.
I doubt the letsencrypt challenge even does a browser cache, but might as well learn how to force fresh downloads as a useful skill. I can do it in a header, but not sure how to do it for files in general.
The request to get new or renew cert can specify which method (http|https|dns) you prefer.
So, redirecting any protocol to any other simply reduces your available choices.
If the sites needs to be https then redirect all traffic to https; but exclude challenge requests from redirection. So that you have that option open.
The idea is you decide which method you want the challenge to be and the site should always accept it that way.
Yes, redirecting can, and should, work but why should you have to redirect anything? when you could just request a challenge in whichever way you want.
Or even request it twice (once in http and then immediately after in https - the chance of success is doubled)
It isn’t clear to me given the instructions on that FreeBSD reference that there is a first run command or procedure. The instruction was to just run the weekly script by hand.
ACME_FLAGS="-v -e -m -b -n -N"
cat "${DOMAINSFILE}" | while read domain line ; do
set +e # RC=2 when time to expire > 30 days
acme-client ${ACME_FLAGS} ${domain} ${line}
RC=$?
set -e
[ $RC -ne 0 -a $RC -ne 2 ] && exit $RC
done
To try to expand a little bit on @rg305's observation about this, there are the three methods you mentioned, but the method that is used on a particular occasion is chosen by the client that you run. The certificate authority doesn't simply try them at random or in some order, but rather according to what your client says it's chosen to use.
Only the HTTP-01 method (which initially makes a connection to HTTP on port 80) is willing to follow HTTP redirects to retry the validation at another URL. (This may be an HTTP or HTTPS URL on the same server or on a different server, including with an arbitrarily specified port.) However, the initial connection will always be in HTTP using port 80, and must be answered with some valid reply, either the requested file contents or an HTTP redirect message.
The TLS-SNI-01 method (which initially makes a connection using TLS on port 443) does not really use HTTP in any meaningful way and is not willing to follow redirects. It expects a particular custom certificate to be presented immediately. If this certificate isn't presented, the validation fails. This means, for example, that if you have a CDN or firewall terminating HTTPS connections on behalf of your server, this validation method can't be used, regardless of what kind of HTTP redirects you might have set up. If the CDN or firewall responds with anything other than the expected custom certificate, that's the end of the process.
I did something novel known as RTMF, well technically RTF Manual page. For acme-client, http port 80 is the default. You still need the nginx.conf location trap to prevent http to https conversion, but the nginx.conf code to kick https back to http for the challenge shouldn’t be needed.
Odd that the manual suggests a daily check for cert renewal. Given the 30 day grace period, weekly should be enough.
We suggest once a day, partly because certificates can be revoked. Also, some sites have lots of certificates and should be renewing them gradually over time, rather than all on the same day. Also, we thought knowing about any renewal problems with a 30-day grace period would be valuable, particularly because people who might be responsible for fixing the problems could be on vacation at some point.