What I'm trying to do is have a server block such that requests for my domain without a subdomain specified successfully serves any existing file with the uri prefix /.well-known/acme-challenge/, but gives a 404 for anything else.

    server {
    listen       443 ssl;
    listen       80;
    server_name  example.com;
    # Satisfy acme verification for both ports 443 and 80
    location /.well-known/acme-challenge/ {
        alias /usr/share/nginx/acme-challenges/;
        try_files $uri =404;
        return 200;
    location / {
        return 404;

What I'm finding is that if file /usr/share/nginx/acme-challenges/foo exists and is readable by the nginx process, then for request http://example.com/.well-known/acme-challenge/foo, foogets downloaded successfully - but I get a 404 status code and the default nginx error page for it. Initially, I did not have the return 200; line after the try_files because I thought that if the try_files succeeded, no other location block would be involved. I tried adding that to "make sure" the other location block would not execute, but it didn't help.

I'm sure the other location block is causing the 404, because if I change its contents to return 200; then I get the successful download and no body (whatever was displayed, e.g. the google home page remains in place when I type the request in the address bar).

I can't make any sense of this. The docs note that try_files can cause an internal redirect when a fallback uri is selected, but not when the initial file succeeds!

  • With more testing, I found that I could get what I want by deleting the return 200 from the first location block, and deleting the second location block entirely. And surely that's the best thing to do since it's simpler. But I sure would like to understand why the config in the question behaved the way it did! – sootsnoot Mar 10 '19 at 21:46
  • It would probably work correctly if you remove the try_files and return 200 statements. alias and try_files have some strange side-effects and return 200 is just plain strange. – Richard Smith Mar 10 '19 at 22:40
  • @RichardSmith Well, I explained why I put the return 200 there, just to see if it made a difference; it wasn't there originally. And my comment noted that removing both that and the second location block seemed to work okay. But you have a interesting/good point in that the try_files (at least as written with a second argument of =404) doesn't seem to be useful since without the directive at all it would look for the uri under the root, and if not there issue a 404 by default. But I think the "root" of the problem (related to the alias directive) is that I didn't have any root directive! – sootsnoot Mar 11 '19 at 0:17
  • The choice of directory /usr/share/nginx/acme-challenges is also quite strange. Are you following some bizarre Internet tutorial, or possibly using a Debian-based distribution? – Michael Hampton Mar 11 '19 at 0:49
  • I don't know about bizarre, but I was more-or-less following this. For our staging server, I don't want to pay for an SSL certificate, and the status of the myriad of really funky opaque wrappers for the letsencrypt acme server is mind-boggling. I picked acme-tiny because it 's simple enough to understand (sort of), and just generates the certificate with mucking with nginx configuration. We have a bunch of test servers on subdomains of a test domain. – sootsnoot Mar 11 '19 at 1:05

My guess is that the following would work:

location ~ /.well-known/acme-challenge(/.+)$ {
    root /usr/share/nginx/acme-challenges;
    try_files $1 =404;

This way we avoid using alias with try_files. We simply capture the filename in location and use the captured filename in try_files.

| improve this answer | |
  • If I can find the time, I can play with this just for fun. But as I said in comments above, try_files with a first argument that resolves to the desired pathname using the using the uri portion of the request (whether the full path is derived from a root directive or an alias directive), with a second and final argument of =404 is completely redundant, since that's the default behavior in the absence of the try_files anyway. My suspicion is that in my original config, I had no root directive at all, and if your config works it would be because it supplies a root... – sootsnoot Mar 12 '19 at 1:47
  • Basically, alias "overrides" the root directive, so it's plausible that you'd get bad behavior if you had no root directive at all. – sootsnoot Mar 12 '19 at 1:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.