acmesh-official / acme.sh

A pure Unix shell script implementing ACME client protocol
https://acme.sh
GNU General Public License v3.0
38.53k stars 4.9k forks source link

--nginx fails if original server config is a rewrite #1115

Open wizonesolutions opened 6 years ago

wizonesolutions commented 6 years ago

Steps to reproduce

server {
  listen 80;
  server_name example.com;
  rewrite ^ https://$server_name$request_uri? permanent;
}

Workaround: If you instead for example return "some text";, that is to say static content, then the rewritten conf file works fine. acme.sh does seem to do the replacement properly in both cases, but perhaps it is not using a strong enough reload command in --nginx to overpower rewrite? I'm not really sure why it fails, but I know that when I took the rewrite out of the original conf, it worked properly...

Just submitting this in case anyone wants to try to reproduce it.

LomotHo commented 6 years ago

the same problem

LomotHo commented 6 years ago

Now I get a way to solve it, just don't use the rewrite, and let Javascript to do the redirect.

server {
    listen 80;
    server_name www.xxxxxx.com;
    # rewrite ^(.*)$  https://$host$1 permanent;
    root /var/www/www.xxxxxx.com;
    include /etc/nginx/default.d/*.conf;

    location / {
        index index.html;
    }
}

index.html for 80 port

<html>
<script type="text/javascript">
var targetProtocol = "https:";
if (window.location.protocol != targetProtocol)
 window.location.href = targetProtocol +
  window.location.href.substring(window.location.protocol.length);
</script>
</html>
wizonesolutions commented 6 years ago

I'm using Ansible so I just change back to a rewrite after the cert is generated successfully. Works ok

  1. nov. 2017 18:42 je oseba "lomot" notifications@github.com napisala:

Now I get a way to solve it, just don't use the rewrite, and let Javascript to do the redirect.

server { listen 80; server_name www.xxxxxx.com;

rewrite ^(.*)$ https://$host$1 permanent;

root /var/www/www.xxxxxx.com;
include /etc/nginx/default.d/*.conf;

location / {
  index index.html;
}

}

index.html for 80 port

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/Neilpang/acme.sh/issues/1115#issuecomment-345001521, or mute the thread https://github.com/notifications/unsubscribe-auth/AAVANI1ts6KXwc9xHN-hVrsFejNlTj61ks5s3HQhgaJpZM4QghUC .

LomotHo commented 6 years ago

but you will meet the same problem when the certificate is expired, I have just met this. with the rewrite, the acme.sh can't get a new certificate automatically

wizonesolutions commented 6 years ago

True. Maybe the hooks could help. Store a non-rewrite version, swap it in pre and out post.

  1. nov. 2017 03:44 je oseba "lomot" notifications@github.com napisala:

but you will meet the same problem when the certificate is expired, I have just met this. with the rewrite, the acme.sh can't get a new certificate automatically

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/Neilpang/acme.sh/issues/1115#issuecomment-345129311, or mute the thread https://github.com/notifications/unsubscribe-auth/AAVANNO5aDQ920v2J9obrT_esgWsZ4Gfks5s3PMJgaJpZM4QghUC .

FernandoMiguel commented 6 years ago

You are making this far more complex than it needs to be.

If you already have a cert, you can use tls01 instead of http so validation happens on port 443

If you don't have a cert or have one and prefer validation to happen on port 80, all you need is a location block on your vhost for /.well-known/acme-challenge

FernandoMiguel commented 6 years ago

Here are a few examples https://gist.github.com/cecilemuller/a26737699a7e70a7093d4dc115915de8 https://community.letsencrypt.org/t/how-to-nginx-configuration-to-enable-acme-challenge-support-on-all-http-virtual-hosts/5622

wizonesolutions commented 6 years ago

What is the proper --issue command to tell acme.sh to use http-01 for issuance and tls-01 for renewal?

How do I add a proper location block when the verification token it looks for changes? This is a reverse proxy. There is no docroot.

Sure, one can use standalone (and turn off the whole web server for a bit whenever acme.sh decides to set up the cron job), but this issue is about a bug in the nginx plugin.

  1. nov. 2017 09:06 je oseba "Fernando Miguel" notifications@github.com napisala:

Here are a few examples https://gist.github.com/cecilemuller/a26737699a7e70a7093d4dc115915de8 https://community.letsencrypt.org/t/how-to-nginx-configurati on-to-enable-acme-challenge-support-on-all-http-virtual-hosts/5622

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/Neilpang/acme.sh/issues/1115#issuecomment-345173183, or mute the thread https://github.com/notifications/unsubscribe-auth/AAVANP5VnWERsvyzk-lSse7G_DILdly4ks5s3T52gaJpZM4QghUC .

FernandoMiguel commented 6 years ago

yeah, there's always the option of issuing as standalone, by disabling nginx, and then issuing a new one with TLS01

there is no automation for that.

wizonesolutions commented 6 years ago

I went ahead and just switched to using webroot. I moved my rewrite to location / and added a separate location /.well-known/acme-challenge/ that I aliased to a specific directory on the machine. I pass that directory in -w. I'll leave this open as a bug ticket though.

Ref: https://www.rmedgar.com/blog/using-acme-sh-with-nginx

I didn't do the include thing since I'm using Ansible and can do it with a variable there, but it's basically the same except for also having an https rewrite for non-/.well-known/acme-challenge/ paths.

drlauridsen commented 4 years ago

I know this is a very old thread, but just had the same issue with a 301 https redirect and using --nginx for cert creation. It probably fails, because the script for the temporary nginx.conf mod ends up adding the acme challenge after the redirect eg

server {
    server_name example.com
    return 301 $scheme://www.example.com$request_uri
}

becomes

server {
    server_name example.com
    return 301 $scheme://www.example.com$request_uri
    location = /.well-known/acme-challenge/challengeurl{default_type text/plain;return 200 challengeresponse;}
}

Solution was simply putting the redirect inside a location

server {
    server_name example.com
    location / {    return 301 $scheme://www.example.com$request_uri }
}

credit for this simple solution goes to https://community.letsencrypt.org/t/authorization-fails-for-nginx-with-server-block-redirecting-non-www-to-www/103619

juslintek commented 1 year ago

Hi, same issue in 2023. It add something like that:

#ACME_NGINX_START
location ~ "^/\.well-known/acme-challenge/([-_a-zA-Z0-9]+)$" {
  default_type text/plain;
  return 200 "$1.um-kdPjwG6fqLDAMavVp27uEsnRNRDH3TKtAjGHTkNo";
}
#NGINX_START

to my server configs:

server {
    listen 80;
    listen [::]:80;

    server_name cockpit.domain.com;
#ACME_NGINX_START
location ~ "^/\.well-known/acme-challenge/([-_a-zA-Z0-9]+)$" {
  default_type text/plain;
  return 200 "$1.um-kdPjwG6fqLDAMavVp27uEsnRNRDH3TKtAjGHTkNo";
}
#NGINX_START

    error_log /var/log/nginx/cockpit.error.log warn;
    access_log /var/log/nginx/cockpit.access.log main;

    return 301 https://$host$request_uri;
}

And 80 access logs how this:

91.199.212.132 - - [20/May/2023:11:38:58 +0000] "GET /.well-known/acme-challenge/-MzF-Pdckuj5CVN4_UqgiLQvQplLTlNnZe7Z6s8RHkI HTTP/1.1" 301 178 "-" "acme.zerossl.com/v2/DV90" "-"
91.199.212.132 - - [20/May/2023:11:39:01 +0000] "GET /.well-known/acme-challenge/-MzF-Pdckuj5CVN4_UqgiLQvQplLTlNnZe7Z6s8RHkI HTTP/1.1" 301 178 "-" "acme.zerossl.com/v2/DV90" "-"

It should work, because regex kind of passes, but it is skipped... Maybe nginx version has something to do with it. Mine is:

/var/log/nginx# nginx -V
nginx version: nginx/1.18.0 (Ubuntu)
built with OpenSSL 3.0.2 15 Mar 2022
TLS SNI support enabled
configure arguments: --with-cc-opt='-g -O2 -ffile-prefix-map=/build/nginx-d8gVax/nginx-1.18.0=. -flto=auto -ffat-lto-objects -flto=auto -ffat-lto-objects -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-Bsymbolic-functions -flto=auto -ffat-lto-objects -flto=auto -Wl,-z,relro -Wl,-z,now -fPIC' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-compat --with-debug --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --add-dynamic-module=/build/nginx-d8gVax/nginx-1.18.0/debian/modules/http-geoip2 --with-http_addition_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_sub_module

I assume its forward slash escape issue in regex context, but will try to find where it adds that stuff and hardcode it to escape path forward slashes with backward ones.

UPDATE: Seems like something else, either requests are made before reload happens or something else. Or reload does not even help.

UPDATE 2: If I remove ssl configs and return 301 https://$host$request_uri; statement for domain it works... Seems like something else is getting messed up or it is a race condition thing. First try it fails, on consecutive it succeeds, because updates are in memory.

UPDATE 3: Seems that problem is cause only by: return 301 https://$host$request_uri;