Incorrect documentation
https://poste.io/doc/faq suggest using .well-known from nginx-proxy-manager container, but there is no .well-known folders there.
# docker exec -ti nginx-proxy-manager bash
bash-5.0# find / -name .well-known -print
bash-5.0#
The faq also refers to jwilder/nginx-proxy
but it is now called jwilder/nginx-proxy
-manager, and has Lets Encrypt embedded, so no companion container is used now.
Given the nginx-proxy-manager will take are of the user-faced certificate, would it not be easier to just mount the folder with the certificates and allow users to self-sign the TLS certificates which would allow for 10 year certs…
Comments (22)
-
-
reporter The /data/letsencrypt-acme-challenge is empty here, so is /data/letsencrypt-workdir. /data/letsencrypt has a number of files and directories - keys, certs, config files etc. but no .well-known files.
I’m using the jlesage/nginx-proxy-manager:latest image.
# docker exec -ti nginx-proxy-manager bash bash-5.0# cd /data/letsencrypt-acme-challenge/ bash-5.0# pwd /data/letsencrypt-acme-challenge bash-5.0# ls -al total 8 drwxr-xr-x 2 app app 4096 May 5 00:25 . drwxr-xr-x 9 app app 4096 May 6 09:51 .. bash-5.0#
What could be the problem?
-
.well-known (letsencrypt-acme-challenge in this container) is supposed to be empty unless there’s an active cert request being processed. Nothing is wrong. You have to map poste.io’s .well-known to that folder so it can use it.
-
reporter Hm ok, but how does poste.io know when NPM makes a certificate request?
-
it doesn’t. The documentation in poste.io is telling you to map .well-known so that poste.io itself can use it from System Settings > TLS Certificates > Issue free letsencrypt.org certificate.
-
reporter Ok now I understand.
Anyway, I tried mounting the volumes as you suggested, i.e:
volumes: - /data/poste.io/data:/data - /data/nginx-proxy-manager/config/letsencrypt-acme-challenge:/opt/www/.well-known/acme-challenge
Now when I go to poste.io admin interface and attempt to create a TLS cert it takes a bit longer than before, and a new file appears in /data/nginx-proxy-manager/config/letsencrypt-acme-challenge, so something seems to go ok, but the API log still throws an error:
[2021-05-07 23:43:58] LEScript.INFO: Getting list of URLs for API [2021-05-07 23:44:02] LEScript.INFO: Requesting new nonce for client communication [2021-05-07 23:44:07] LEScript.INFO: Account already registered. Continuing. [2021-05-07 23:44:07] LEScript.INFO: Sending registration to letsencrypt server [2021-05-07 23:44:07] LEScript.INFO: Sending signed request to https://acme-v02.api.letsencrypt.org/acme/new-acct [2021-05-07 23:44:12] LEScript.INFO: Account: https://acme-v02.api.letsencrypt.org/acme/acct/111248833 [2021-05-07 23:44:12] LEScript.INFO: Starting certificate generation process for domains [2021-05-07 23:44:12] LEScript.INFO: Requesting challenge for mail.robust.net [2021-05-07 23:44:12] LEScript.INFO: Sending signed request to https://acme-v02.api.letsencrypt.org/acme/new-order [2021-05-07 23:44:16] LEScript.INFO: Sending signed request to https://acme-v02.api.letsencrypt.org/acme/authz-v3/12934704942 [2021-05-07 23:44:21] LEScript.INFO: Got challenge token for mail.robust.net [2021-05-07 23:44:21] LEScript.INFO: Token for mail.robust.net saved at /opt/www//.well-known/acme-challenge/uJDM3Pk7MvThfom2X2e0AWCfW-d_avsDo4ZCdmN70v0 and should be available at http://mail.robust.net/.well-known/acme-challenge/uJDM3Pk7MvThfom2X2e0AWCfW-d_avsDo4ZCdmN70v0 [2021-05-07 23:44:21] LEScript.INFO: Sending request to challenge [2021-05-07 23:44:21] LEScript.INFO: Sending signed request to https://acme-v02.api.letsencrypt.org/acme/chall-v3/12934704942/ODqORw [2021-05-07 23:44:25] LEScript.INFO: Verification pending, sleeping 1s [2021-05-07 23:44:26] LEScript.INFO: Sending signed request to https://acme-v02.api.letsencrypt.org/acme/chall-v3/12934704942/ODqORw [2021-05-07 23:44:31] LEScript.ERROR: 400 { "type": "urn:ietf:params:acme:error:malformed", "detail": "Unable to update challenge :: authorization must be pending", "status": 400 } [2021-05-07 23:44:31] LEScript.ERROR: #0 /opt/admin/vendor/analogic/lescript/Lescript.php(544): Analogic\ACME\Client->curl('POST', 'https://acme-v0...', '{"protected":"e...') [2021-05-07 23:44:31] LEScript.ERROR: #1 /opt/admin/vendor/analogic/lescript/Lescript.php(422): Analogic\ACME\Client->post('https://acme-v0...', '{"protected":"e...') [2021-05-07 23:44:31] LEScript.ERROR: #2 /opt/admin/vendor/analogic/lescript/Lescript.php(165): Analogic\ACME\Lescript->signedRequest('https://acme-v0...', Array) [2021-05-07 23:44:31] LEScript.ERROR: #3 /opt/admin/src/AppBundle/Handler/LeHandler.php(62): Analogic\ACME\Lescript->signDomains(Array) [2021-05-07 23:44:31] LEScript.ERROR: #4 /opt/admin/src/AppBundle/Controller/LeController.php(71): AppBundle\Handler\LeHandler->renew(true) [2021-05-07 23:44:31] LEScript.ERROR: #5 /opt/admin/vendor/symfony/symfony/src/Symfony/Component/HttpKernel/HttpKernel.php(151): AppBundle\Controller\LeController->issueAction(Object(Symfony\Component\HttpFoundation\Request)) [2021-05-07 23:44:31] LEScript.ERROR: #6 /opt/admin/vendor/symfony/symfony/src/Symfony/Component/HttpKernel/HttpKernel.php(68): Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object(Symfony\Component\HttpFoundation\Request), 1) [2021-05-07 23:44:31] LEScript.ERROR: #7 /opt/admin/vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Kernel.php(200): Symfony\Component\HttpKernel\HttpKernel->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true) [2021-05-07 23:44:31] LEScript.ERROR: #8 /opt/admin/web/app.php(16): Symfony\Component\HttpKernel\Kernel->handle(Object(Symfony\Component\HttpFoundation\Request)) [2021-05-07 23:44:31] LEScript.ERROR: #9 {main}
-
That’s more interesting for sure - looks like you did everything right and it’s attempting to communicate with LetsEncrypt. Given that only 5 seconds go by before it tries to verify twice, and the error is
"Unable to update challenge :: authorization must be pending", "status": 400
that seems to be a timeout. Maybe it’s not waiting long enough for a reply or LetsEncrypt is busy? -
reporter I just tried again:
[2021-05-08 10:33:39] LEScript.INFO: Getting list of URLs for API [2021-05-08 10:33:44] LEScript.INFO: Requesting new nonce for client communication [2021-05-08 10:33:48] LEScript.INFO: Account already registered. Continuing. [2021-05-08 10:33:48] LEScript.INFO: Sending registration to letsencrypt server [2021-05-08 10:33:48] LEScript.INFO: Sending signed request to https://acme-v02.api.letsencrypt.org/acme/new-acct [2021-05-08 10:33:53] LEScript.INFO: Account: https://acme-v02.api.letsencrypt.org/acme/acct/111248833 [2021-05-08 10:33:53] LEScript.INFO: Starting certificate generation process for domains [2021-05-08 10:33:53] LEScript.INFO: Requesting challenge for mail.robust.net [2021-05-08 10:33:53] LEScript.INFO: Sending signed request to https://acme-v02.api.letsencrypt.org/acme/new-order [2021-05-08 10:33:58] LEScript.INFO: Sending signed request to https://acme-v02.api.letsencrypt.org/acme/authz-v3/12946908172 [2021-05-08 10:34:02] LEScript.INFO: Got challenge token for mail.robust.net [2021-05-08 10:34:02] LEScript.INFO: Token for mail.robust.net saved at /opt/www//.well-known/acme-challenge/-YmlGOFtVE52JmqRJuUNMp-68fwaCjcqS4aAfAnUVCQ and should be available at http://mail.robust.net/.well-known/acme-challenge/-YmlGOFtVE52JmqRJuUNMp-68fwaCjcqS4aAfAnUVCQ [2021-05-08 10:34:02] LEScript.INFO: Sending request to challenge [2021-05-08 10:34:02] LEScript.INFO: Sending signed request to https://acme-v02.api.letsencrypt.org/acme/chall-v3/12946908172/wtc4MA [2021-05-08 10:34:07] LEScript.INFO: Verification pending, sleeping 1s [2021-05-08 10:34:08] LEScript.INFO: Sending signed request to https://acme-v02.api.letsencrypt.org/acme/chall-v3/12946908172/wtc4MA [2021-05-08 10:34:12] LEScript.ERROR: 400 { "type": "urn:ietf:params:acme:error:malformed", "detail": "Unable to update challenge :: authorization must be pending", "status": 400 } [2021-05-08 10:34:12] LEScript.ERROR: #0 /opt/admin/vendor/analogic/lescript/Lescript.php(544): Analogic\ACME\Client->curl('POST', 'https://acme-v0...', '{"protected":"e...') [2021-05-08 10:34:12] LEScript.ERROR: #1 /opt/admin/vendor/analogic/lescript/Lescript.php(422): Analogic\ACME\Client->post('https://acme-v0...', '{"protected":"e...') [2021-05-08 10:34:12] LEScript.ERROR: #2 /opt/admin/vendor/analogic/lescript/Lescript.php(165): Analogic\ACME\Lescript->signedRequest('https://acme-v0...', Array) [2021-05-08 10:34:12] LEScript.ERROR: #3 /opt/admin/src/AppBundle/Handler/LeHandler.php(62): Analogic\ACME\Lescript->signDomains(Array) [2021-05-08 10:34:12] LEScript.ERROR: #4 /opt/admin/src/AppBundle/Controller/LeController.php(71): AppBundle\Handler\LeHandler->renew(true) [2021-05-08 10:34:12] LEScript.ERROR: #5 /opt/admin/vendor/symfony/symfony/src/Symfony/Component/HttpKernel/HttpKernel.php(151): AppBundle\Controller\LeController->issueAction(Object(Symfony\Component\HttpFoundation\Request)) [2021-05-08 10:34:12] LEScript.ERROR: #6 /opt/admin/vendor/symfony/symfony/src/Symfony/Component/HttpKernel/HttpKernel.php(68): Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object(Symfony\Component\HttpFoundation\Request), 1) [2021-05-08 10:34:12] LEScript.ERROR: #7 /opt/admin/vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Kernel.php(200): Symfony\Component\HttpKernel\HttpKernel->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true) [2021-05-08 10:34:12] LEScript.ERROR: #8 /opt/admin/web/app.php(16): Symfony\Component\HttpKernel\Kernel->handle(Object(Symfony\Component\HttpFoundation\Request)) [2021-05-08 10:34:12] LEScript.ERROR: #9 {main}
… and I noticed, going to the link referenced -
should be available at http://mail.robust.net/.well-known/acme-challenge/-YmlGOFtVE52JmqRJuUNMp-68fwaCjcqS4aAfAnUVCQ
throws an error 404 Not Found by the proxy manager so I suppose it’s not surprising the challenge fails?mail.robust.net is pointing directly to http://poste:80 on the internal docker network (i.e. not redirecting to a sub folder or anything). Is that ok?
-
reporter A bit more testing:
I created an index.html in /opt/www/.well-known/acme-challenge but going to http://mail.robust.net/.well-known/acme-challenge/index.html threw a 404 Not Found.I then moved it up to .well-known – and now it’s found.
So
https://mail.robust.net/.well-known/acme-challenge/index.html → not found
https://mail.robust.net/.well-known/index.html → found
I noticed the acme-challenge folder is mode 777 so perhaps it was restricted due to lax permissions but changing it to 755 threw same error.
So checking the /var/log/nginx/access_log in the poste.io container, I get an entry every time I go to https://mail.robust.net/.well-known/index.html but nothing when I go to https://mail.robust.net/.well-known/acme-challenge/index.html. So it seems like nginx doesn’t even get the request for files under acme-challenge? Would that be something configured in poste.io’s nginx config, or in nginx-proxy-managers nginx config? I feel it’s too specific to have been caused by nginx-proxy-manager. On the other hand, why should either of them block access to acme-challenge?
-
reporter Sorry, so to clarify:
The challenge files are present under /opt/www/.well-known/acme-challenge, but nginx don’t show them.
-
Try changing your map of
/data/nginx-proxy-manager/config/letsencrypt-acme-challenge:/opt/www/.well-known/acme-challenge
→/data/nginx-proxy-manager/config/letsencrypt-acme-challenge:/opt/www/.well-known/
and seeing if that changes anything?
-
reporter volumes: - /data/poste.io/data:/data - /data/nginx-proxy-manager/config/letsencrypt-acme-challenge:/opt/www/.well-known
But still same error:
[2021-05-08 17:09:24] LEScript.INFO: Getting list of URLs for API [2021-05-08 17:09:28] LEScript.INFO: Requesting new nonce for client communication [2021-05-08 17:09:33] LEScript.INFO: Account already registered. Continuing. [2021-05-08 17:09:33] LEScript.INFO: Sending registration to letsencrypt server [2021-05-08 17:09:33] LEScript.INFO: Sending signed request to https://acme-v02.api.letsencrypt.org/acme/new-acct [2021-05-08 17:09:37] LEScript.INFO: Account: https://acme-v02.api.letsencrypt.org/acme/acct/111202360 [2021-05-08 17:09:37] LEScript.INFO: Starting certificate generation process for domains [2021-05-08 17:09:37] LEScript.INFO: Requesting challenge for mail.robust.net [2021-05-08 17:09:37] LEScript.INFO: Sending signed request to https://acme-v02.api.letsencrypt.org/acme/new-order [2021-05-08 17:09:42] LEScript.INFO: Sending signed request to https://acme-v02.api.letsencrypt.org/acme/authz-v3/12953723697 [2021-05-08 17:09:47] LEScript.INFO: Got challenge token for mail.robust.net [2021-05-08 17:09:47] LEScript.INFO: Token for mail.robust.net saved at /opt/www//.well-known/acme-challenge/vqBQ_1B8N4RnAL9fDvpswVyOr40IfUWJMBMRVxRF1nk and should be available at http://mail.robust.net/.well-known/acme-challenge/vqBQ_1B8N4RnAL9fDvpswVyOr40IfUWJMBMRVxRF1nk [2021-05-08 17:09:47] LEScript.INFO: Sending request to challenge [2021-05-08 17:09:47] LEScript.INFO: Sending signed request to https://acme-v02.api.letsencrypt.org/acme/chall-v3/12953723697/G6JaHA [2021-05-08 17:09:51] LEScript.INFO: Verification pending, sleeping 1s [2021-05-08 17:09:52] LEScript.INFO: Sending signed request to https://acme-v02.api.letsencrypt.org/acme/chall-v3/12953723697/G6JaHA [2021-05-08 17:09:57] LEScript.ERROR: 400 { "type": "urn:ietf:params:acme:error:malformed", "detail": "Unable to update challenge :: authorization must be pending", "status": 400 } [2021-05-08 17:09:57] LEScript.ERROR: #0 /opt/admin/vendor/analogic/lescript/Lescript.php(544): Analogic\ACME\Client->curl('POST', 'https://acme-v0...', '{"protected":"e...') [2021-05-08 17:09:57] LEScript.ERROR: #1 /opt/admin/vendor/analogic/lescript/Lescript.php(422): Analogic\ACME\Client->post('https://acme-v0...', '{"protected":"e...') [2021-05-08 17:09:57] LEScript.ERROR: #2 /opt/admin/vendor/analogic/lescript/Lescript.php(165): Analogic\ACME\Lescript->signedRequest('https://acme-v0...', Array) [2021-05-08 17:09:57] LEScript.ERROR: #3 /opt/admin/src/AppBundle/Handler/LeHandler.php(62): Analogic\ACME\Lescript->signDomains(Array) [2021-05-08 17:09:57] LEScript.ERROR: #4 /opt/admin/src/AppBundle/Controller/LeController.php(71): AppBundle\Handler\LeHandler->renew(true) [2021-05-08 17:09:57] LEScript.ERROR: #5 /opt/admin/vendor/symfony/symfony/src/Symfony/Component/HttpKernel/HttpKernel.php(151): AppBundle\Controller\LeController->issueAction(Object(Symfony\Component\HttpFoundation\Request)) [2021-05-08 17:09:57] LEScript.ERROR: #6 /opt/admin/vendor/symfony/symfony/src/Symfony/Component/HttpKernel/HttpKernel.php(68): Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object(Symfony\Component\HttpFoundation\Request), 1) [2021-05-08 17:09:57] LEScript.ERROR: #7 /opt/admin/vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Kernel.php(200): Symfony\Component\HttpKernel\HttpKernel->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true) [2021-05-08 17:09:57] LEScript.ERROR: #8 /opt/admin/web/app.php(16): Symfony\Component\HttpKernel\Kernel->handle(Object(Symfony\Component\HttpFoundation\Request)) [2021-05-08 17:09:57] LEScript.ERROR: #9 {main}
Anyway, I think the mapping was correct before, the challenge is in the folder where it should be. The problem was that the webserver for some reason wasn’t able to get to that folder.
-
reporter So, what do you think - why isn’t the webserver allowed to read from that directory?
-
Beats me - sounds like a permissions or mapping error tho. But, your entire premise is wrong because https://hub.docker.com/r/jwilder/nginx-proxy is not what you’re using which is https://hub.docker.com/r/jc21/nginx-proxy-manager and not clearly the same kind of mapping as jwilder’s…
-
reporter Actually I use neither, but https://hub.docker.com/r/jlesage/nginx-proxy-manager. I think they all use the same nginx-proxy-manager code, they just packet it differently - like jc21 use a separate mysql container for data storage. It looks more like the poste.io webserver for some reason isn’t allowed to read from that folder, probably due to configuration.
Is there any way to get any debugging information out of the webserver in poste.io? Running “docker-compose logs -f” while trying a TLS cert renew produce nothing…
-
Jlesage's is based on jc21 but neither is the same as nginx-proxy. I just spun up jlesage here and will see if I can get anything different on my end.
-
oh I got it - your URL for the letsencrypt acme-challenge folder is being passed (correctly) by nginx-proxy-manager to the poste.io server. The thing is, that location doesn’t exist on the server, it exists on nginx-proxy-manager only. I bet if you did a curl from the command line of the server poste.io is running on using localhost:port/.well-known/acme-challenge/<token> it would work. Just tried it on mine and the response wasn’t a 404. So basically we need to figure out how to not let nginx-proxy-manager to intercept traffic to .well-known for subdomains.
-
Poste.io isn’t the problem.
In the nginx-proxy-manager:
# cat /etc/nginx/conf.d/include/letsencrypt-acme-challenge.conf # Hide /acme-challenge subdirectory and return 404 on all requests. # It is somewhat more secure than letting Nginx return 403. # Ending slash is important! location = /.well-known/acme-challenge/ { return 404; }
-
https://github.com/jc21/nginx-proxy-manager/issues/210
What if instead you have nginx-proxy-manager pull the key for you from its interface, and then mapped the certificates in poste.io’s data directory ssl subfolder (ca.crt, server.crt, and server.key) to their respective files in nginx-proxy-manager data directory/letsencrypt/archive/npm-<id>/ fullchain1.pem, cert1.pem, and privkey1.pem, respectively?
-
reporter Actually one of the first things I tried was just brute copying the keys from nginx-proxy-manager to poste.io, but that didn’t work at all. I don’t know exactly why not, but trying to read mail then just threw an error- hence my question in the op
-
Copying the keys works if you rename them correctly and have the right permissions.. Tried it here, poste.io seems happy. I would close this Issue out.
-
reporter Yes, I can confirm it works for me by copying or linking the certs. Symlinks does not work though, so it’s possible for a careless poste.io admin to break the proxy-manager certs. A little unsafe, but at least it works.
ln /data/nginx-proxy-manager/config/letsencrypt/archive/npm-7/fullchain1.pem /data/poste.io/data/ssl/ca.crt ln /data/nginx-proxy-manager/config/letsencrypt/archive/npm-7/cert1.pem /data/poste.io/data/ssl/server.crt ln /data/nginx-proxy-manager/config/letsencrypt/archive/npm-7/privkey1.pem /data/poste.io/data/ssl/server.key
To activate this I also had to restart the poste.io container. Isn’t there a less invasive reload possibility?
- Log in to comment
.well-known is exposed in nginx-proxy-manager as /<data folder>/letsencrypt-acme-challenge. You can see this in the nginx.conf for nginx-proxy-manager which refers to that folder as a proxy location. You’d have to map this folder into poste.io container with the proper permissions. One issue poste.io has is unpredictable UID/GID, so it requires some loose permissions on that folder to read/write to.