Allow internal redirect to URI x, but deny external request for x?
Hello! I'm using nginx 1.12.2 on RHEL 7, and I've got a FastCGI web app that uses a deployment structure which uses an atomic symlink change for an atomic app deploy, and I'm wishing to be able to do an internal redirect in nginx to URL x, but deny an external request to the same URL x so that I don't serve the same content at more than one URL. Is there a way to do that? For example, given the external request URI /my-app/index.html I want to do an internal redirect to /my-app/current/index.html but deny an external request for that same URI /my-app/current/index.html because I don't want to serve the app from two different URLs (e.g., /my-app/ and /my-app/current/). The app structure on disk is like the Capistrano structure https://capistranorb.com/documentation/getting-started/structure/ That is, it's like /srv/www/my-app current -> releases/1.0.2 releases 1.0.0 1.0.1 1.0.2 "current" is a symlink. In my nginx config, I've changed $document_root to $realpath_root in the appropriate FastCGI parameters, and have the following locations: location /my-app/ { rewrite ^/my-app/(?!current/)(.*)$ /my-app/current/$1 last; index index.php; } location /my-app/current/ { return 404; } location /my-app/releases/ { return 404; } location ~ ^/my-app/.*?[^/]\.php(?:/|$) { include php-fpm-realpath.conf; } Given an external request for a URI that starts with /my-app/ this returns 404 after the internal redirect. If I remove the two locations that return 404, then it serves the app, but it also allows external requests such as /my-app/current/ which I don't want to allow since that's a duplicate of /my-app/ I initially tried using the alias directive which I thought was a better fit for what I wanted to do location /my-app/ { alias /srv/www/my-app/current/; index index.php; } location /my-app/current/ { return 404; } location /my-app/releases/ { return 404; } location ~ ^/my-app/(.*?[^/]\.php(?:/.*|$)) { alias /srv/www/my-app/current/$1; include php-fpm-realpath.conf; } But that didn't seem to work with the nginx FastCGI implementation. Thank you! Lewis ___ nginx mailing list nginx@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx
Re: Allow internal redirect to URI x, but deny external request for x?
On 08/30, J. Lewis Muir wrote: > I'm wondering if the fastcgi_split_path_info function or the if > directive is what's emitting the file op message in the error log which > would mean that one or both of $realpath_root or $fastcgi_script_name > are not set to what I expect. (?) Adding return 200 "document_root: $document_root\nfastcgi_script_name: $fastcgi_script_name\n"; to the location like this location ~ ^/my-app/(.*?[^/]\.php(?:/.*|$)) { alias /srv/www/my-app/current/$1; return 200 "realpath_root: $realpath_root\nfastcgi_script_name: $fastcgi_script_name\n"; } yields the following: $ curl http://localhost/my-app/ realpath_root: /srv/www/my-app/releases/1.0.2/index.php fastcgi_script_name: /my-app/index.php So, that doesn't seem right! I was expecting them to be something like: realpath_root: /srv/www/my-app/releases/1.0.2 fastcgi_script_name: /index.php Puzzled, Lewis ___ nginx mailing list nginx@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx
Re: Allow internal redirect to URI x, but deny external request for x?
On 08/30, J. Lewis Muir wrote: > I initially tried using the alias directive which I thought was a better > fit for what I wanted to do > > location /my-app/ { > alias /srv/www/my-app/current/; > index index.php; > } > > location /my-app/current/ { > return 404; > } > > location /my-app/releases/ { > return 404; > } > > location ~ ^/my-app/(.*?[^/]\.php(?:/.*|$)) { > alias /srv/www/my-app/current/$1; > include php-fpm-realpath.conf; > } > > But that didn't seem to work with the nginx FastCGI implementation. What exactly didn't work when I tried the alias directive, based on the error log, seems to be that somewhere there's a file op on /srv/www/my-app/releases/1.0.2/index.php/my-app/index.php which is a wrong path; it should be /srv/www/my-app/releases/1.0.2/index.php In my php-fpm-realpath.conf, I have fastcgi_split_path_info ^(.+?\.php)(/.*)$; if (!-f $realpath_root$fastcgi_script_name) { return 404; } ... fastcgi_param DOCUMENT_ROOT $realpath_root; fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; ... I'm wondering if the fastcgi_split_path_info function or the if directive is what's emitting the file op message in the error log which would mean that one or both of $realpath_root or $fastcgi_script_name are not set to what I expect. (?) Here are the relevant lines from the error log with the debug option: test location: "/my-app/" test location: ~ "^/my-app/(.*?[^/]\.php(?:/.*|$))" using configuration "/my-app/" open index "/srv/www/my-app/current/index.php" internal redirect: "/my-app/index.php?" rewrite phase: 1 test location: "/my-app/" test location: ~ "^/my-app/(.*?[^/]\.php(?:/.*|$))" using configuration "^/my-app/(.*?[^/]\.php(?:/.*|$))" rewrite phase: 3 http script complex value http script copy: "/srv/www/my-app/current/" http script capture: "index.php" http script copy: "/srv/www/my-app/current/" http script capture: "index.php" http script var: "/srv/www/my-app/releases/1.0.2/index.php" http script var: "/my-app/index.php" http script copy: "" http script var: "/my-app/index.php" http script copy: "" http script file op 0001 "/srv/www/my-app/releases/1.0.2/index.php/my-app/index.php" http script if http finalize request: 404, "/my-app/index.php?" a:1, c:2 http special response: 404, "/my-app/index.php?" http set discard body xslt filter header HTTP/1.1 404 Not Found Thank you! Lewis ___ nginx mailing list nginx@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx
Re: Allow internal redirect to URI x, but deny external request for x?
On 08/30, J. Lewis Muir wrote: > On 08/30, J. Lewis Muir wrote: > > I'm wondering if the fastcgi_split_path_info function or the if > > directive is what's emitting the file op message in the error log which > > would mean that one or both of $realpath_root or $fastcgi_script_name > > are not set to what I expect. (?) > > Adding > > return 200 "document_root: $document_root\nfastcgi_script_name: > $fastcgi_script_name\n"; > > to the location like this > > location ~ ^/my-app/(.*?[^/]\.php(?:/.*|$)) { > alias /srv/www/my-app/current/$1; > return 200 "realpath_root: $realpath_root\nfastcgi_script_name: > $fastcgi_script_name\n"; > } Hmm, I think I need to call fastcgi_split_path_info first, so now I did location ~ ^/my-app/(.*?[^/]\.php(?:/.*|$)) { alias /srv/www/my-app/current/$1; fastcgi_split_path_info ^(.+?\.php)(/.*)$; return 200 "realpath_root: $realpath_root\nfastcgi_script_name: $fastcgi_script_name\nfastcgi_path_info: $fastcgi_path_info\n"; } which yields the following: $ curl http://localhost/my-app/ realpath_root: /srv/www/my-app/releases/1.0.2/index.php fastcgi_script_name: /my-app/index.php fastcgi_path_info: That doesn't seem right. Still puzzled, Lewis ___ nginx mailing list nginx@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx
Re: Allow internal redirect to URI x, but deny external request for x?
On 08/31, Francis Daly wrote: > On Sat, Aug 31, 2019 at 12:21:40AM +0100, Francis Daly wrote: > > Hi there, > > A few further thoughts here... > > > It sounds like your desires are for requests: > > > > * starts with /my-app/current/ -> reject > > * starts with /my-app/releases/ -> reject > > * matches /my-app/something.php, or /myapp/something.php/anything -> > > Typo there -- should be "/my-app/". Yeah, no problem; I knew what you meant. > But note that the "/my-app/" in the request and the "/my-app/" on the > filesystem do not need to the same. (And also: the filesystem /my-app/ > for the php files and the filesystem /my-app/ for other files do not > need to be the same; if you want to keep your "static" and "processed" > content separate.) Got it. > > fastcgi-process the file /srv/www/my-app/current/something.php > > * matches /my-app/something -> just send the file > > /srv/www/my-app/current/something > > > > Is that correct? If so -- do exactly that. > > > > For example (but mostly untested): > > > > == > > location ^~ /my-app/current/ { return 200 "nothing to see at > > /current/\n"; } > > location ^~ /my-app/releases/ { return 200 "nothing to see at > > /releases/\n"; } > > location ^~ /my-app/ { > > location ~ \.php($|/) { > > fastcgi_split_path_info ^/my-app(/.*php)(.*); > > If there might be more than one "php" in the request, that will split on > "the last one". Perhaps you want to split on "the first one followed by > slash". In that case, adjust the regex: > > fastcgi_split_path_info ^/my-app(/.*?php)($|/.*); Yes, I ended up doing something like that: fastcgi_split_path_info ^/synchweb(/.+?\.php)(/.*)?$; I think you'd want the "\." in yours before the "php", and then I think the only meaningful difference between ours would be that yours would match /my-app/.php while mine would not because I used ".+?" to match one or more reluctantly where you used ".*?" to match zero or more reluctantly. I was aware of https://www.nginx.com/resources/wiki/start/topics/examples/phpfcgi/ which has a location of location ~ [^/]\.php(/|$) { and a fastcgi_split_path_info of fastcgi_split_path_info ^(.+?\.php)(/.*)$; I've always wondered exactly what the idea was with starting that location regex with "[^/]", though. Why require the ".php" to be preceded by a character other than "/"? That means it would match a request of /foo.php but not /.php Is it because that's considered an invalid PHP file name? Is it because some PHP web apps uses a directory named ".php" as a private directory that should not be served? I don't know. > > root /srv/www/my-app/current/; > > You did also show a "if (!-f" config, which is "404 if the matching php > file is not present". That can be: > > try_files $fastcgi_script_name =404; > > because we have root and the variable set correctly here. Ah, I see! Thank you for pointing that out! I like that better. > > include fastcgi.conf; > > Possibly the only bits of that file that you care about are: > > fastcgi_param PATH_INFO $fastcgi_path_info; > fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; > > so you could just use those lines directly. Yes, I could, but I was trying to make my php-fpm-realpath.conf reusable for other apps which is why I was keeping those lines in it. And, I think I mentioned this earlier, but I changed them to use $realpath_root instead of $document_root because of the symlinks and my desire to support an atomic app deploy with no downtime and no nginx reload. Thanks again! Lewis ___ nginx mailing list nginx@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx
Re: Allow internal redirect to URI x, but deny external request for x?
On 08/30, Ian Hobson wrote: > Hi Lewis, > > On 30/08/19 18:33, J. Lewis Muir wrote: > > Hello! > > > > I'm using nginx 1.12.2 on RHEL 7, and I've got a FastCGI web app that > > uses a deployment structure which uses an atomic symlink change for an > > atomic app deploy, and I'm wishing to be able to do an internal redirect > > in nginx to URL x, but deny an external request to the same URL x so > > that I don't serve the same content at more than one URL. Is there a > > way to do that? > > > You could place the different versions away from the root so they cannot be > obtained from the web. Then they can be served by setting up a symlink to > the desired version. > > This can be changed using "ln -sfn version/dir serving/root" and then > restarting nginx to pick up the new version. > > By not using redirects, this method should be more efficient. > > Regards > > Ian Hi, Ian! Thank you for the suggestion! That's an interesting idea, and that would avoid needing to exclude those URIs from being served and I think avoid needing to change the document root and maybe some other things. I toyed around with some designs and came up with four; I think I like the third one best, but I'm not sure, maybe the fourth one is better. = Design #1 Web app root: /srv/www/app/my-app current -> releases/1.0.2 releases 1.0.0 1.0.1 1.0.2 nginx server document root: /srv/www/host/localhost my-app -> /srv/www/app/my-app/current Comments: This tries to share apps between virtual hosts. It provides no way for different virtual hosts to serve the same app but with the app configured differently. Also, all virtual hosts have to serve the same version of the app. = Design #2 Web app root: /srv/www/app/my-app 1.0.0 1.0.1 1.0.2 nginx server document root: /srv/www/host/localhost my-app -> /srv/www/app/my-app/1.0.2 Comments: Similar to design #1 except now the virtual hosts can server different versions of the app, but for a given version, the app is still configured in the exact same way for all virtual hosts. = Design #3 Web app root: /srv/www/localhost/app my-app 1.0.0 1.0.1 1.0.2 nginx server document root: /srv/www/localhost/root my-app -> ../app/my-app/1.0.2 Comments: I like this because now each virtual host has its own set of deployed apps, so the apps can be configured specifically for that particular virtual host. = Design #4 Web app root: /srv/www/localhost/app my-app current -> releases/1.0.2 releases 1.0.0 1.0.1 1.0.2 nginx server document root: /srv/www/localhost/root my-app -> ../app/my-app/current Comments: Similar to design #3 but moves where the "current" symlink lives. So, the deployed version of the app is controlled under the web app root rather under the nginx server document root. Maybe this is a little better because the nginx config reference to "my-app" can be sure to be correct and can be changed if desired, and be unrelated to which version of the app is deployed via the "current" symlink in the web app root. The downside is two symlinks (i.e., a symlink to a symlink) as opposed to one. Regards, Lewis ___ nginx mailing list nginx@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx
Re: Allow internal redirect to URI x, but deny external request for x?
On 08/31, Francis Daly wrote: > On Fri, Aug 30, 2019 at 04:59:36PM -0500, J. Lewis Muir wrote: > > Hi there, > > > I was wishing for a way to specify a new root but with a modified > > request URI. So, I tried the alias directive, and I assumed that > > $document_root and $realpath_root would refer to the aliased document > > root, but obviously that can't be since nginx has no way of knowing what > > the aliased document root should be when all it has is a location alias > > which is the full path to the resource. Sorry for the trouble. > > It sounds like your desires are for requests: > > * starts with /my-app/current/ -> reject > * starts with /my-app/releases/ -> reject > * matches /my-app/something.php, or /myapp/something.php/anything -> > fastcgi-process the file /srv/www/my-app/current/something.php > * matches /my-app/something -> just send the file > /srv/www/my-app/current/something > > Is that correct? If so -- do exactly that. Yes! > For example (but mostly untested): > > == > location ^~ /my-app/current/ { return 200 "nothing to see at /current/\n"; } > location ^~ /my-app/releases/ { return 200 "nothing to see at > /releases/\n"; } > location ^~ /my-app/ { > location ~ \.php($|/) { > fastcgi_split_path_info ^/my-app(/.*php)(.*); > root /srv/www/my-app/current/; > include fastcgi.conf; > fastcgi_pass unix:php.sock; > } > alias /srv/www/my-app/current/; > } > == Wow! I had given up on getting this approach to work. Honestly, I don't think I would have thought of your solution. Brilliant! I tried it, and it worked after making a few tweaks! Here's what worked: location ^~ /my-app/current/ { return 404; } location ^~ /my-app/releases/ { return 404; } location ^~ /my-app/ { index index.php; location ~ [^/]\.php(?:/|$) { root /srv/www/my-app/current; fastcgi_split_path_info ^/my-app(/.+?\.php)(/.*)?$; include php-fpm-realpath.conf; } alias /srv/www/my-app/current/; } I changed the root directive to come before the fastcgi_split_path_info, but that was just aesthetic; it worked fine the other way too. Previously, I had the fastcgi_split_path_info call in php-fpm-realpath.conf along with the following file-exists check after it: if (!-f $realpath_root$fastcgi_script_name) { return 404; } But I moved the fastcgi_split_path_info call out of php-fpm-realpath.conf so that I could use the custom regex like in your suggestion. So, your solution solved my problem! Thank you! On a related note, while considering those return-404s for /my-app/current/ and /my-app/releases/, I realized that those could, in theory, conflict with the URIs of a web app if the web app actually used those same URIs. For example, maybe the web app is a GitLab-type app and a URI of /my-app/releases/ might very well be part of the app's URI set for displaying software releases or something. This has nothing to do with your solution and everything to do with my initial design choice that I was trying to achieve, and it's something I hadn't considered before. For my current app, it doesn't use those URIs, so it's not a problem, but as a general scheme, it's not perfect. I think one solution would be to move the app root directory to a different name so that it can't conflict. For example, have it live at /srv/www/my-app-deployment or something like that. Then I could just return a 404 for any request on that, e.g.: location ^~ /my-app-deployment/ { return 404; } Thanks again! Lewis ___ nginx mailing list nginx@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx
Re: Allow internal redirect to URI x, but deny external request for x?
On 08/30, Francis Daly wrote: > On Fri, Aug 30, 2019 at 01:58:23PM -0500, J. Lewis Muir wrote: > > Hi there, > > > location ~ ^/my-app/(.*?[^/]\.php(?:/.*|$)) { > > alias /srv/www/my-app/current/$1; > > fastcgi_split_path_info ^(.+?\.php)(/.*)$; > > return 200 "realpath_root: $realpath_root\nfastcgi_script_name: > > $fastcgi_script_name\nfastcgi_path_info: $fastcgi_path_info\n"; > > } > > > > which yields the following: > > > > $ curl http://localhost/my-app/ > > realpath_root: /srv/www/my-app/releases/1.0.2/index.php > > fastcgi_script_name: /my-app/index.php > > fastcgi_path_info: > > > > That doesn't seem right. > > Why not? > > http://nginx.org/r/$realpath_root says is it the current root or alias > value, resolving symlinks. > > The request was /my-app/, the current request is /my-app/index.php, > and you have alias'ed that to /srv/www/my-app/current/index.php Yes, you're absolutely right. This is where I went wrong. I was initially wishing to use the root directive location ~ ^/my-app/(.*?[^/]\.php(?:/.*|$)) { root /srv/www/my-app/current; include php-fpm-realpath.conf; } but then the URI would be appended to that, so for a request of /my-app/index.php it would result in /srv/www/my-app/current/my-app/index.php which wasn't what I wanted; instead I wanted /srv/www/my-app/current/index.php I was wishing for a way to specify a new root but with a modified request URI. So, I tried the alias directive, and I assumed that $document_root and $realpath_root would refer to the aliased document root, but obviously that can't be since nginx has no way of knowing what the aliased document root should be when all it has is a location alias which is the full path to the resource. Sorry for the trouble. > http://nginx.org/r/$fastcgi_script_name (and what follows) describes > the other variables. > > The request is /my-app/index.php and your fastcgi_split_path_info sets > $fastcgi_script_name to "everything up to .php" and $fastcgi_path_info to > "everything after .php", so long as .php is followed by / -- which it > isn't, so both are unchanged from their defaults of "the uri" and "empty". > > (I'm somewhat guessing about the last part there; a test can probably > demonstrate whether it is incorrect.) Yep, I'm sure you're right here as well. Sorry for the trouble; I just totally missed how this worked. Thank you for your help! Lewis ___ nginx mailing list nginx@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx
Re: Allow internal redirect to URI x, but deny external request for x?
On 09/02, Francis Daly wrote: > nginx does not "do" php. nginx does not care what your fastcgi server > will do with the key/value pairs that it sends. nginx cares that the > fastcgi server gives a valid response to the request that nginx makes. > > Typically, your fastcgi server will use the value associated with > SCRIPT_FILENAME as "the name of the file to execute". If your fastcgi > server fails to find / read / execute that file, it will return its own > error indication. > > (So your "if", or the more common "try_files", is just an early-out, > to sometimes avoid involving the fastcgi server. It may happen that the > file is present when nginx looks for it, but is absent when the fastcgi > server looks for it -- so that case does have to be handled anyway.) > > In this case, if $document_root is /srv/www/my-app/current/ and > $realpath_root is /srv/www/my-app/releases/1.0.2/, and the script > name is test.php, then with one config, nginx would send the string > "/srv/www/my-app/current/test.php", and with the other config nginx > would send the string "/srv/www/my-app/releases/1.0.2/test.php". > > (That is "pathname1" vs "pathname2".) Understood. > So if "one request" involves the fastcgi server reading > "/srv/www/my-app/current/test.php", and then reading a bunch of other > files in the same directory -- then I guess that unfortunate timing > could lead to it reading some files from releases/1.0.1 and some from > releases/1.0.2. (Assuming that it opens the directory afresh each time -- > which can't be ruled out.) Right, that's what I was trying to avoid by using $realpath_root. I assumed that $realpath_root was set at the beginning of the location processing. That way, I could be guaranteed that it would not change for the duration of the request handling within nginx. And since nginx would give that value (i.e., the path with the symlinks resolved) to the FastCGI server, the FastCGI server would be using that same path for the whole request and wouldn't know anything about the "current" symlink that can change at any moment. But perhaps that's an invalid assumption, and the path is resolved every time $realpath_root is expanded as a variable? I hope not, but that would be really important to understand. > But if "the app" involves a http request to part1.php and then a http > request to part2.php (or: a second http request to part1.php), I don't > think that the symlink+realpath thing will prevent those two requests > going to different release versions. Hmm, good point. I'm not sure how to do a seamless web app update deploy, then. Maybe it's not possible without additional constraints. I'm assuming the app is hosted on a single nginx server. Although, I'd be curious how this is typically solved for a multiple-server case as well (e.g., a load balancer with multiple identical instances of the web app running on two or more servers). The idea is to have no downtime. I suppose I could encode the app version in the URI (e.g., /my-app/1.0.2) or in the request header. I've seen REST APIs versioned in the URI or in the request header, but I'm not sure web apps do that. Or I could try to ensure that my web app updates are *always* backward compatible if they are to keep using the same URI. I could do that for any web apps I write, but I can't control that for any that I don't write and am just deploying. Another idea I previously toyed with was to deploy the web app in a directory structure similar to the symlink+realpath approach but without the symlink; the path to the app root is versioned. In the nginx config, use the versioned path to the app root (e.g., /srv/www/my-app/releases/1.0.2). To deploy a new version of the app, install to a new versioned app root (e.g., /srv/www/my-app/releases/1.0.3), change the app root in the nginx config, and cause nginx to reload the config. Note that I'm intentionally keeping the file system path versioned so that the path changes when a new version is deployed to avoid the need to flush any caching that might be going on at the FastCGI server or elsewhere. Will there be downtime for a split second when the config is reloaded? What will happen? Will nginx refuse connections? Will it accept connections but just not respond while it's reloading the config? But this approach has the same issue that you pointed out for the symlink+realpath approach in that I don't see a way to prevent the case where the app involves an HTTP request to part1.php that goes to one release and then an HTTP request to part2.php that goes to the updated release if the deploy happens at just the right (wrong) time. What's the best strategy for deploying a new version of an app, then? Expect that all app updates are backward compatible? Expect that the app passes around a version identifier with each request that the app will use to detect when the version has changed and force the user to log in again or something? Version the URI? Thanks! Lewis
Re: Allow internal redirect to URI x, but deny external request for x?
On 09/03, J. Lewis Muir wrote: > On 09/02, Francis Daly wrote: > > But if "the app" involves a http request to part1.php and then a http > > request to part2.php (or: a second http request to part1.php), I don't > > think that the symlink+realpath thing will prevent those two requests > > going to different release versions. > > Hmm, good point. > > I'm not sure how to do a seamless web app update deploy, then. Maybe > it's not possible without additional constraints. After searching the web and failing to find anything addressing this (maybe it's out there, but I couldn't find it), I'm inclined to believe that there are roughly two choices: either the web app maintains backward compatibility in its request API, or it doesn't. The web app that maintains backward compatibility in its request API will work with the symlink+realpath approach, assuming the FastCGI server either does no caching or caches based on the file path. (The path-based caching works because the path changes when an app update is deployed because the version is encoded in the path.) Note, however, that even for an app that maintains backward compatibility like this, rolling back a deploy to a previous release would not work unless it was a patch update (as defined in the Semantic Versioning scheme). For example, you could safely roll back from 1.0.3 to 1.0.2, but not from 1.1.0 to 1.0.3, and not from 2.0.0 to 1.2.3. The web app that does *not* maintain backward compatibility in its request API will *not* work with the symlink+realpath approach. It might work by chance depending on the timing of the deploy, the timing of the requests, and which requests were in flight at the time of the deploy. Or you could orchestrate the deploy to shut down the nginx server, wait for an amount of time deemed to be the maximum time that should ever elapse between the "part1.php" request and the "part2.php" request (which may be impossible to determine, or may be infinite) such that all "part2.php" requests will happen and fail because they couldn't connect to the nginx server, deploy the app update, and then start the nginx server again. This approach will never be 100% correct. I'd love to be enlightened on other choices, but this is my understanding as of now, and I think I'll proceed with the symlink+realpath approach under the expectation that the web apps I deploy maintain backward compatibility in their request API, or they might just break for some users when I deploy an update in which case I might choose my deploy time to be the time of least demand on average. Regards, Lewis ___ nginx mailing list nginx@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx
Re: Allow internal redirect to URI x, but deny external request for x?
On 08/30, j94305 wrote: > I've been following this, and I would take a slightly different approach. > > 1. Serve all apps under /{app}/releases/{version}/{path} as you have them > organized in the deployment structure in the file system. > > 2. Forget about symbolic links and other makeshift versioning/defaulting in > the file system. > > 3. Use a keyval mapping to handle redirections (307) of > /{app}/current/{stuff} to /{app}/releases/{currentVersion}/{stuff}, where > the keyval mapping provides {app} => {currentVersion}. You can update an > manage this during deployment. Sorry, I forgot about your post! Thank you for your suggestions! Is this a keyval? https://nginx.org/en/docs/http/ngx_http_keyval_module.html > We usually include this in a CI/CD pipeline after deployment to dynamically > switch to the last version (using a curl request to the NGINX API). If you > can't use keyvals, use a static map and dynamically generate that "map" > directive's mapping. Restart NGINX to reflect changes. Keyvals let you do > this on the fly. Is this a static map? https://nginx.org/en/docs/http/ngx_http_map_module.html And by "dynamically generate" do you mean generate the map directive as a config file that would be included from the main config and then cause nginx to reload its config? > The major advantage of this approach is with updates. You are most likely > going to run into issues with browser or proxy caching if you provide > different versions of files/apps under the same path. By having a canonical > form that respects the version structure, you are avoiding this altogether. > Yet, you have the flexibility to run hotfixes (replace existing files in an > existing version without creating a new one), or experimental versions > (which won't update the "current" pointer). Interesting. What I was trying to do with $realpath_root, I thought was similar to what you're describing. However, when you mention browser or proxy caching, then I'm not sure. Are you suggesting serving from a different URI for each version of the app? If not, then I don't understand how your proposal behaves differently than the symlink+realpath idea. (But this may be because you wrote this on Aug 30, and the symlink+realpath idea had not been clearly stated yet.) > I would try to keep the complexity low. Agreed! However, changing a symlink (albeit with some nginx config changes to use $realpath_root and such) is pretty simple to me, so it's a little harder for me to see using a keyval or a static map as keeping the complexity low. But if I understand your proposal correctly, it would be more straightforward in terms of not needing to use symlinks at all and not needing to worry about $realpath_root vs. $document_root. Instead, you just use variables, and to update the variables, you just use the API if using a keyval, or cause nginx to reload its config if using the static map. Thank you for the suggestions! Regards, Lewis ___ nginx mailing list nginx@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx
Re: Allow internal redirect to URI x, but deny external request for x?
On 08/31, Francis Daly wrote: > On Sat, Aug 31, 2019 at 09:10:09AM -0500, J. Lewis Muir wrote: > > On 08/31, Francis Daly wrote: > > Hi there, > > > > * starts with /my-app/current/ -> reject > > > * starts with /my-app/releases/ -> reject > > Actually -- those two "rejects" should not be needed. > > The app probably should not be installed in the general nginx document > root directory. The "alias" mentioning the "app/current" directory means > that that is the only part that nginx will try to serve files from. The > "root" mentioning the "app/current" directory means that that is the only > part that nginx will look in (try_files) and mention to the fastcgi server > (fastcgi_param). > > So the "app/releases" directory will not be web-accessible; and the > "app/current" directory will only be accessible by the explicit url that > you define. > > So the full config should be of the form > > location ^~ /app-url/ { > alias /active-app-dir/; > location ~ \.php(/|$) { > root /active-app-dir; > fastcgi_split_path_info ^/app-url(/.*?php)($|/.*); > try_files $fastcgi_script_name =404; > include fastcgi.conf; > fastcgi_pass unix:php.sock; > } > } I can't believe this! Another great insight! Thank you! I haven't tried it, but yes, that looks way better, and your observation about not needing the two rejects puts to rest my incorrect belief that there was a URI namespace problem with the app directory structure (i.e., with the "/current/" and "/releases/" URI components). And yes, I will move the app root out of the nginx document root to avoid the unnecessary risk of an nginx misconfiguration. > Adjust regexes based on what you want. > > "app-url" can be "my-app". "/active-app-dir" can be "/opt/app/releases/3" > or "/opt/my-app/current" or anything else. Got it. > > Previously, I had the fastcgi_split_path_info call in > > php-fpm-realpath.conf along with the following file-exists check after > > Using "realpath" should not affect nginx at all. nginx invites the > fastcgi server to use pathname2 instead of pathname1; so the fastcgi > server is the only thing that should care. Hmm, I might not be understanding this. The rationale of using $realpath_root instead of $document_root was to make it so that a new version of the web app could be deployed atomically at any time by changing the "current" symlink, meaning that, for example, if the "current" symlink were changed right in the middle of a request being handled in PHP, it wouldn't be possible for one part of the request to execute in PHP in the old version of the app and another part to execute in the new version. By using $realpath_root, the idea was to ensure that for any given request being handled in PHP, it would execute in its entirety in the same version of the web app. That's why I was doing in php-fpm-realpath.conf if (!-f $realpath_root$fastcgi_script_name) { return 404; } and fastcgi_param DOCUMENT_ROOT $realpath_root; fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; So, does that make sense, or am I still not understanding this? I don't know what you mean by "nginx invites the fastcgi server to use pathname2 instead of pathname1." What are pathname1 and pathname2? > > For my current app, it doesn't use those URIs, so it's not a problem, > > but as a general scheme, it's not perfect. I think one solution would > > be to move the app root directory to a different name so that it can't > > conflict. For example, have it live at > > > > /srv/www/my-app-deployment > > As above -- that shouldn't matter. If the app is not deployed in the web > server document root, only the specific alias/root directory is accessible, > and the entire url-space below that is available. Understood. > (And you can have one url prefix /my-app/, and a separate url prefix > /my-app-prev/, which uses the next most recent version. Restrict access > to that location{} to your source IP address, and you can do regression > testing between the two.) > > > or something like that. Then I could just return a 404 for any request > > on that, e.g.: > > > > location ^~ /my-app-deployment/ { > > return 404; > > } > > If you don't want nginx to serve content from the my-app-deployment > directory, it is probably easier for it to be somewhere other than > /srv/www. > > It is hard to misconfigure nginx in that case. Agreed; I will move it out of there. Thank you! Lewis ___ nginx mailing list nginx@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx
Re: Allow internal redirect to URI x, but deny external request for x?
On 09/04, Jürgen Wagner (DVT) wrote: > This is the effect you get by having the HTTP equivalent of a symbolic link > in the NGINX (visible to the browser), not in the file system (which is > opaque to users). The file system link will (over time) serve different > contents under the same URL, so in fact, addressing changes with every > deployment. The suggested approach keeps URL addressing constant and just > changes the entry pointer on a new deployment. > > I agree that this is not the solution that first comes to ones mind, but it > does solve a number of nasty versioning issues we have run into over time. > Your mileage may vary :-) Thank you for the further explanation! Indeed it seems like a compelling solution! What about web search engine indexing; do you do anything to avoid search engines indexing the versioned URLs? I suppose that if you only publish the unversioned entry-point URLs, search engines will respect that? (Maybe wishful thinking.) Or will they follow a 307 redirect and index those URLs? For example, it would seem undesirable to do a web search for "my-app" and get a list of, say, the "index.php" for each version (e.g., "/my-app/releases/1.0.0/index.php", "/my-app/releases/1.0.1/index.php", "/my-app/releases/1.0.2/index.php", etc.). So, perhaps you use a "/robots.txt" to exclude "/my-app/releases/"? DuckDuckGo seems to respect "/robots.txt" for controlling what gets indexed https://help.duckduckgo.com/duckduckgo-help-pages/results/duckduckbot/ But Google says "/robots.txt" is not for keeping a web page out of their index https://support.google.com/webmasters/answer/6062608 and that you should use a "noindex" directive instead. So maybe you use both a "/robots.txt" and the robots meta tag with content="noindex" in the served resources or perhaps "X-Robots-Tag: noindex" in the HTTP header response? Regards, Lewis ___ nginx mailing list nginx@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx
Re: Allow internal redirect to URI x, but deny external request for x?
On 09/04, Jürgen Wagner (DVT) wrote: > Now, you want to be able to say what is the "current" version and reflect > this in the URL namespace as well. In the file system, that's a symbolic > link. In the URL namespace of NGINX, that could be a redirection (status > code 307). Both approaches would work. For the redirection you need a > location Got it! Thank you! So this approach versions the URI. > /{app}/current > > which redirects any request for paths starting with this to the actual > version you want to serve: > > /{app}/releases/{latestVersion} > > This can be achieved with a dynamically-generated stub you include in a > "map" directive (requiring NGINX reload in case of changes) or a "keyval" > map that can be changed via the NGINX API on the fly as you need it (not > requiring reloads). The mapping will get the app name and determine the path > of the latest version where the redirection should go to. Got it. > The issue about browser and proxy caches: if over time you serve multiple > versions of an app from the same URLs, browsers (or proxies) may consider > their cached version of some files current enough not to feel motivated > refetching them. In some cases, you would end up with some files loaded into > the browser being of an old version, some already a newer one. This can be > avoided entirely by giving each version of the app a distinct canonical > prefix that will never be re-used. The "current" redirection is simply a > pointer to the right location for the latest version, but as it is an > external redirection, the browser will ultimately load the app from the > official "releases" path with the version number in it. Wouldn't the 307 redirection mean that for *every* request, nginx has to issue a 307 and then the client has to request the versioned URI which nginx then has to server; so a double-request for every resource? I agree that this approach solves the browser and proxy cache problem, though. How does this solve the request-chain problem where "part1.php" executes in one version of the app, but then "part2.php" executes in the updated version because the updated version was deployed in between? I presume it doesn't, which is OK, but I want to make sure I understand. Do you know of any mainstream web apps that are deployed this way (i.e., 307 redirect to versioned URI)? Thank you! Lewis ___ nginx mailing list nginx@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx
Why 301 permanent redirect with appended slash?
Hello, all! I have a minimal nginx.conf with one server block that sets the root directory and one location with a prefix string of "/foo/", and for a request of "/foo", it returns a 301 permanent redirect to "/foo/". Why? I expected it to return 404 or similar. I also tried a prefix string of "/foo", but that also results in the same 301. Here's the server block (entire nginx.conf at end of message): server { listen 127.0.0.1:80; listen [::1]:80; server_name localhost "" 127.0.0.1 [::1]; root/srv/www/localhost; location /foo/ { } } And here's the curl invocation: $ curl -I 'http://localhost/foo' HTTP/1.1 301 Moved Permanently Server: nginx/1.12.2 Date: Tue, 30 Jul 2019 21:54:44 GMT Content-Type: text/html Content-Length: 185 Location: http://localhost/foo/ Connection: keep-alive I've read in https://nginx.org/en/docs/http/ngx_http_core_module.html#location where it says If a location is defined by a prefix string that ends with the slash character, and requests are processed by one of proxy_pass, fastcgi_pass, uwsgi_pass, scgi_pass, memcached_pass, or grpc_pass, then the special processing is performed. In response to a request with URI equal to this string, but without the trailing slash, a permanent redirect with the code 301 will be returned to the requested URI with the slash appended. But in my case, I don't believe the request is being processed by any of those *_pass directives. Thank you! Lewis Complete nginx.conf user nginx; worker_processes auto; error_log /var/log/nginx/error.log; pid /run/nginx.pid; events { worker_connections 1024; } http { 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 /var/log/nginx/access.log main; sendfileon; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; include /etc/nginx/mime.types; default_type application/octet-stream; server { listen 127.0.0.1:80; listen [::1]:80; server_name localhost "" 127.0.0.1 [::1]; root/srv/www/localhost; location /foo/ { } } } ___ nginx mailing list nginx@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx
Implicit root location?
Hello, all! I have a minimal nginx.conf with one server block that sets the root directory but has *no* location directives, yet for a request of "/", it serves "/index.html". Why? With no locations specified, I expected it to return 404 or similar for any request. Here's the server block (entire nginx.conf at end of message): server { listen 127.0.0.1:80; listen [::1]:80; server_name localhost "" 127.0.0.1 [::1]; root/srv/www/localhost; } Here's the contents of /srv/www/localhost: $ ls -al /srv/www/localhost total 4 drwxr-xr-x. 2 root root 24 Jul 30 15:50 . drwxr-xr-x. 3 root root 23 Jun 26 21:34 .. -rw-r--r--. 1 root root 140 Jun 26 22:22 index.html And here's the curl invocation: $ curl 'http://localhost/' localhost localhost I know that the default index directive is index index.html; That explains how it knows to try index.html, but what makes it try the root when there are no location directives? Is there an implicit location directive? There is no default listed for the location directive: https://nginx.org/en/docs/http/ngx_http_core_module.html#location And I couldn't find this behavior stated in "How nginx processes a request:" https://nginx.org/en/docs/http/request_processing.html Thank you! Lewis Complete nginx.conf user nginx; worker_processes auto; error_log /var/log/nginx/error.log; pid /run/nginx.pid; events { worker_connections 1024; } http { 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 /var/log/nginx/access.log main; sendfileon; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; include /etc/nginx/mime.types; default_type application/octet-stream; server { listen 127.0.0.1:80; listen [::1]:80; server_name localhost "" 127.0.0.1 [::1]; root/srv/www/localhost; } } ___ nginx mailing list nginx@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx
Re: Why 301 permanent redirect with appended slash?
On 07/31, Francis Daly wrote: > On Tue, Jul 30, 2019 at 05:12:01PM -0500, J. Lewis Muir wrote: > > Hi there, > > > I have a minimal nginx.conf with one server block that sets the root > > directory and one location with a prefix string of "/foo/", and for a > > request of "/foo", it returns a 301 permanent redirect to "/foo/". Why? > > I expected it to return 404 or similar. I also tried a prefix string of > > "/foo", but that also results in the same 301. > > I get a 301 if the directory "foo" exists; and a 404 if it does not. > > Do you get something different? No, I get exactly what you described. Sorry, I failed to state in my initial email that the directory "foo" exists (as well as the file "foo/index.html" which probably doesn't matter here). > > But in my case, I don't believe the request is being processed by any of > > those *_pass directives. > > If you request "/directory", and "directory" exists, then the filesystem > handler will issue a 301 to "/directory/", which I think is what you > are seeing. Indeed. > As in: your request for "/foo" does not match any location{}, and so is > handled at server-level, which runs the filesystem handler and returns > 200 if the file "foo" exists, 301 if the directory "foo" exists, and > 404 otherwise. Yes, thank you very much for the explanation! That all makes sense. I couldn't find this behavior documented anywhere; is it documented somewhere that I've missed? > Change your config to be > > location /foo/ { return 200 "location /foo/\n"; } > > and you will see when that location is used. Nice; that's useful for testing! > If your config has > > location /foo {} > > then a similar consideration applies, except the request "/foo" is now > handled in that location which, per the above configuration, uses the > filesystem handler. Understood. Thanks! Lewis ___ nginx mailing list nginx@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx
Re: RHEL Yum repo instructions don't work on RHEL 7
On 10/02, Konstantin Pavlov wrote: > Yep, that seems like the easiest solution. I've put Client, Workstation > and Server symlinks for respectable major releases to both stable and > mainline repos - I'd appreciate if you try again and let me know if that > fixes the issue for you. I confirm that using the $releasever Yum variable in the baseurl key value as given in the nginx documentation works now. Thanks! Lewis ___ nginx mailing list nginx@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx
RHEL Yum repo instructions don't work on RHEL 7
Hello! I'd like to report a problem with the RHEL/CentOS instructions at https://nginx.org/en/linux_packages.html#RHEL-CentOS They don't work on RHEL 7. When I attempt to install the nginx package as root with yum install nginx I get an HTTP 404 error: http://nginx.org/packages/centos/7Workstation/x86_64/repodata/repomd.xml: [Errno 14] HTTP Error 404 - Not Found The problem seems to be the use of the $releasever Yum variable in the baseurl key of the nginx.repo spec: baseurl=http://nginx.org/packages/centos/$releasever/$basearch/ On my RHEL 7 machine, that variable is evaluating to 7Workstation Looking at http://nginx.org/packages/centos/ the nginx repo is expecting $releasever to evaluate to just the release number without the variant/edition text. So, if in nginx.repo I change baseurl=http://nginx.org/packages/centos/$releasever/$basearch/ to baseurl=http://nginx.org/packages/centos/7/$basearch/ it works. There's more info at https://access.redhat.com/solutions/1256473 I have a default /etc/yum.conf and it does not have a line that sets the distroverpkg key. I think something in the documentation or the nginx repo needs to be changed. One fix would be to list the release version number explicitly in the baseurl key value like I did above. And just say in the documentation that you have to set the number to the version that matches your installed version of RHEL/CentOS. Another fix would be to add symlinks or redirects or whatever at http://nginx.org/packages/centos/ that would make the $releasever work. For example: 7Workstation -> 7 7Server -> 7 I don't know whether there are other release variants/editions. At some point, "Client" was a variant/edition, I think, but it seems like these are changing a fair amount from major release to major release, so it may be a moving target. And maybe there are other better fixes that I'm not aware of. Thanks! Lewis ___ nginx mailing list nginx@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx
Re: How to do location /test/place?id=2
On 10/18, P.V.Anthony wrote: > On 18/10/19 5:26 am, Jeff Dyke wrote: > > I know this is not an answer to your question, but it begs another, > > mainly due to the if statement. How many of these are you going to > > have? https://www.nginx.com/resources/wiki/start/topics/depth/ifisevil/ > > > > You've likely considered this, but if not wanted to throw it out there. > > Even if you are moving domains, could you create a separate route that > > you could key off rather than arg_id? > > Oh no. I was not aware of the "if" danger. Thank you for bringing that up. > > I am not able to change the application. Is there another way without using > "if"? The "if" behavior is weird, so it's good to avoid it if you can, but sometimes it really is the only way to do something. And at the top of that "If Is Evil" page it says: The only 100% safe things which may be done inside "if" in a location context are: * return ...; * rewrite ... last; And in your example, you were doing a return inside an "if" which is noted as being safe in a location context. Lewis ___ nginx mailing list nginx@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx
Static content and Front Controller pattern under same base URI
Hello, nginxers! What's the best way to server static content as well as dynamic content that uses the Front Controller pattern under the same base URI? I'm dealing with a web app partially written in PHP that expects to serve static content as well as dynamic PHP content, using the Front Controller pattern, both under the same base URI. It expects to serve static content if the file or directory exists. But if the file or directory does not exist, it expects request rewriting according to the Front Controller pattern like this: Request Rewritten Request /foo/ /foo/index.php /foo/bar /foo/index.php/bar /foo/bar/baz /foo/index.php/bar/baz The following config works correctly: location = /foo { return 301 $uri/$is_args$args; } location /foo/ { alias /srv/www/localhost/app/foo/1.0.0/; index index.php; try_files $uri $uri/ @foo_front_controller; } location ~ ^/foo/.*?[^/]\.php(?:/|$) { error_page 418 = @foo_front_controller; return 418; } location @foo_front_controller { rewrite ^/foo(?!/index\.php)(/.+)$ /foo/index.php$1 last; root /srv/www/localhost/app/foo/1.0.0; fastcgi_split_path_info ^/foo(/.+?\.php)(/.*)?$; include php-fpm.conf; fastcgi_param REQUEST_URI $fastcgi_script_name$fastcgi_path_info$is_args$args; } I'm not a big fan of the location that sets the 418 error_page to the @foo_front_controller named location, but I don't know of any other way to essentially do a "return @foo_front_controller". Is there a better way? The whole point of the @foo_front_controller named location is so that I can have one block that defines the Front Controller logic, and then use it in both the "/foo/" location block in the try_files directive as the fallback for when the file or directory does not exist and in the location block right below it for requests that are for .php files. Is this a good approach, or is there a better way? Example content and requests are shown below. Thank you! Lewis $ ls -al /srv/www/localhost/app/foo/1.0.0 total 8 drwxr-xr-x 2 root root 38 Oct 17 17:04 . drwxr-xr-x 3 root root 19 Oct 17 16:37 .. -rw-r--r-- 1 root root 209 Oct 17 17:04 index.php -rw-r--r-- 1 root root 21 Oct 17 16:44 msg.txt $ cat /srv/www/localhost/app/foo/1.0.0/index.php hello, world hello, world' . "\n"; ?> REQUEST_URI: ' . $_SERVER['REQUEST_URI'] . '' . "\n"; ?> $ cat /srv/www/localhost/app/foo/1.0.0/msg.txt Use the Force, Luke. $ curl http://localhost/foo/ hello, world hello, world REQUEST_URI: /index.php $ curl http://localhost/foo/index.php hello, world hello, world REQUEST_URI: /index.php $ curl http://localhost/foo/bar hello, world hello, world REQUEST_URI: /index.php/bar $ curl http://localhost/foo/bar/baz hello, world hello, world REQUEST_URI: /index.php/bar/baz $ curl http://localhost/foo/msg.txt Use the Force, Luke. $ curl http://localhost/foo/msg-quux.txt hello, world hello, world REQUEST_URI: /index.php/msg-quux.txt ___ nginx mailing list nginx@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx
Re: IOS keep asking password with nginx auth_basic
On 10/17, tiendungitd wrote: > any idea about this issue? Are you serving over HTTPS? Are you positive that you are *not* serving any content over HTTP from HTTPS? Can you create an MCVE (minimal, complete, and verifiable example) for a ".txt" file over HTTP? For a ".txt" file over HTTPS? For a ".ivp" file over HTTP? For a ".ivp" file over HTTPS? In your Pastebin access log, I see occurrences of "$1" in your requests. Is that intentional, or is that a bug? What Content-Type header field are you sending in your response to the request for a resource ending in ".ivp"? Can you try adding a user name and password for the website on the iPad under Settings > Passwords & Accounts > Website & App Passwords? What happens if you try Firefox and Google Chrome on the iPad? Do they work? Lewis ___ nginx mailing list nginx@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx
Re: How to do location /test/place?id=2
On 10/18, P.V.Anthony wrote: > Currently have the following url, > > https://old.example.com/test/place?id=1 > https://old.example.com/test/place?id=2 > https://old.example.com/test/place?id=3 > > Need to redirect only id=2 to another url. > > Did the following and it works for id=2. Need id=1 and id=3 to continue > normally without change. > > location = /test/place { > if ($args = "id=2") { >return 301 https://new.example.com/test/place?$args; > } > } You might want to use $arg_id here (i.e., the $arg_ variable for the argument). Otherwise, it won't work if any other arguments are given. > Or is there a way to do the following? That would be ideal. > > location = /test/place?id=2 { > return 301 https://new.example.com/test/place?id=2 > } I don't think that's allowed. > Unfortunately the above does not work. What is missing? What doesn't work? I would think your > location = /test/place { block would work, although not as shown, but I assume you just left out the part that normally handles the request. It would handle the requests for id=1 and id=3 as before, and it's just the id=2 case that gets redirected, right? Lewis ___ nginx mailing list nginx@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx
Re: PR_END_OF_FILE_ERROR after kernel update
On 10/04, Ken Wright wrote: > Okay, I rebooted the server then tried testing the cert. SSL Labs > reports no secure protocols supported. Once again, I'm lost. I know I > set up the server to use LetsEncrypt certs, and I've checked them; > they're there. I tried disabling the server's firewall and testing > again, only to get the same message. Can you check your nginx server logs? Can you check that the same content can be served over plain HTTP? Can you check that all of your nginx and Let's Encrypt configuration files are still intact? Can you check that your file systems are not full? Can you share a curl command that shows your output that others could use to compare to your output? Lewis ___ nginx mailing list nginx@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx