nginx-proxy / acme-companion

Automated ACME SSL certificate generation for nginx-proxy
MIT License
7.39k stars 820 forks source link

Unable to generate standalone certs with ipv6 enabled #710

Open Byh0ki opened 3 years ago

Byh0ki commented 3 years ago

Hello,

I was trying to generate a cert for a standalone service but it wasn't working for some reasons. After a little digging, I found that trying to reach http://example.com/.well-known/acme-challenge/ was not working during the cert generation loop (after a manual call to /app/signal_le_service) even if the file standalone-cert-example.com.conf was in /etc/nginx/conf.d/. I tried to replicate the issue with a copy of the previously generated file and found out that it was missing the line listen [::]:80;(maybe on purpose ?). I'm currently on a dual stack server and if I correctly understood the error message I got from the companion[1], Let's Encrypt will perform the challenge validation over IPv6 if my domain's DNS entry has both A and AAAA fields. I added the proper line and everything worked fine.

I don't know if it's a good idea to add the line listen [::]:80; by default in the add_standalone_configuration function ? Or maybe we could find a way to add it dynamically ?

https://github.com/nginx-proxy/docker-letsencrypt-nginx-proxy-companion/blob/711c56acc160ea921cbc5797b5dc39d28df044bc/app/functions.sh#L115

[1] CA marked some of the authorizations as invalid, which likely means it could not access http://example.com/.well-known/acme-challenge/X. Did you set correct path in -d example.com:path or --default_root? Are all your domains accessible from the internet? Please check your domains' DNS entries, your host's network/firewall setup and your webserver config. If a domain's DNS entry has both A and AAAA fields set up, some CAs such as Let's Encrypt will perform the challenge validation over IPv6. If your DNS provider does not answer correctly to CAA records request, Let's Encrypt won't issue a certificate for your domain (see https://letsencrypt.org/docs/caa/).

Thanks,

Byh0ki

buchdag commented 3 years ago

@Byh0ki sorry for the very late reply

nginx-proxy is doing this on nginx.tmpl :

{{ if $enable_ipv6 }}
listen [::]:{{ $external_https_port }} ssl http2;
{{ end }}

I haven't experimented with real IPv6 enabled Docker setup yet (as in I relied on the fact that Docker proxy IPv6 to IPv4 by default, like a lot of people) and I'm not sure what would be the implication of adding listen [::]:80; by default.

Now might be a good time to test because Docker recently broke that default behaviour of proxying IPv6 requests to IPv4, and hasn't fixed it yet.

Byh0ki commented 3 years ago

Hello @buchdag, I use a quick fix for the moment so it's ok.

Yes, it's working on nginx-proxy end but it's not working for the standalone configs because they're not generated by docker-gen. Currently, I rely on letsencrypt-nginx-proxy-companion for the certificates generation with the function add_standalone_configuration (so effectively adding the nginx conf for location ^~ /.well-known/acme-challenge/to nginx) on this vhost. I then generate the full nginx conf that need existing certificate to work.

I have disabled userland-proxy in docker for a while because docker-proxy is a userland proxy and it loses the source IP so it's not a great way of doing IPv6 with Docker. Instead, I use a "hack" that mirror IPv4 forward and nat tables to the IPv6 tables. It's not the best because doing NAT with IPv6 seems so wrong but at least it allows a dual stack docker setup quite painlessly. Here the daemon I use: docker-ipv6nat.

-- Byh0ki

buchdag commented 3 years ago

Correct me if I'm wrong but I guess the two options for the problem at hand would be to either detect if nginx-proxy has IPv6 enabled or use our own ENABLE_IPV6 environment variable, then add the directive to listen over IPv6 on the standalone config if needed.

Byh0ki commented 3 years ago

Both solutions are good but the first one might be better because we would have the same behavior between the two applications.