Serve index.html file if exists try_files + proxy_pass?

Lucas Rolff lucas at lucasrolff.com
Mon May 1 11:50:10 UTC 2017


Hi Francis,

Thanks for your reply.

A little about what I'm doing/trying to make work.

I use Minio (https://www.minio.io/) - which is a S3 compatible object 
storage server - it's a simple Go binary, that you pass an argument, 
simply a directory which you want to store your buckets and files in.

In my case, I've created a user called minio, with a homedir of /home/minio
I've configured nginx to run under the user "minio" as well, to ensure 
correct permissions.

Minio by default listens to 0.0.0.0:9000, and to simplify working with 
SSL certificates, I ended up putting nginx on the same machine, and all 
it does is basically a proxy_pass on localhost:9000

When I access https://minio.box.com/<bucket>/ Minio will generate an XML 
containin a list of objects within a specific bucket (as per S3 API 
standards).

Example: https://gist.github.com/lucasRolff/7a0afb95103f6c93d8bc448f5c1c35f4

Since I do not want to expose this bucket object list, I want to do so 
if a bucket has the file "index.html" that it will serve this, instead 
of showing the bucket object list.

Minio run from /home/minio with the directory /home/minio being the 
storage directory.
This means, when I create a bucket called "storage", the directory
/home/minio/storage will be created - within the storage directory, 
objects will be placed, as it was normal files, so if I decide to upload 
index.html, then I will be able to find the exact file, with that name 
at path /home/minio/storage/index.html

Now on nginx, if I have the domain https://minio.box.com/storage/ - what 
I want to load is /home/minio/storage/index.html if the file exists, 
else load the bucket object list

If I access https://minio.box.com/images/ - it should look for the file 
/home/minio/images/index.html and serve if existing else load the bucket 
object list (basically, just proxy_pass as normal).

Any other request I do such as 
https://minio.box.com/images/nginx-rocks.png should go to my upstream 
server (localhost:9000)

 > I also suspect that the correct solution is to just configure the 
upstream http server to serve the contents of index.html if it exists

If I could, I would have done that, but it returns a bucket object list 
as defined in the S3 API standard.

nginx itself can have a root /home/minio; defined - and the 'bucket' is 
just an actual folder on the file-system, with normal files.

The only problem I have is to serve index.html from within the current 
'bucket', so /images/ would load /home/minio/images/index.html

If I do try_files index.html @upstream;

Then try_files will base it on the root directive defined, in this case 
it would try look for /home/minio/index.html if I set the root directive 
to "/home/minio", correct?

I guess I could take try_files "${uri}index.html" @upstream; which would 
produce something like /home/minio/storage/index.html if you have 
/storage/ as the URI, but if URI is /storage/image1.png it would try to 
look for "/home/minio/storage/image1.pngindex.html" and for me that 
doesn't seem very efficient, since it would have to stat for a file on 
the file system for every request before actually going to my upstream.

I could maybe do:

location / {
   location ~ /$ {
     try_files "${uri}index.html" @upstream;

   }

   // continue normal code here
}

location @upstream {
   proxy_pass http://127.0.0.1:9000;
}

I'm not sure if the above made it more clear.

Best Regards,
Lucas R


Francis Daly wrote:
> On Sun, Apr 30, 2017 at 10:44:21AM +0000, Lucas Rolff wrote:
>
> Hi there,
>
>> I have a small scenario where I have a backend (s3 compatible storage), which by default generates a directory listing overview of the files stored.
>> I want to be able to serve an "index.html" file if the file exists, else just proxy_pass as normally.
>
> I think that it will be very useful to be utterly clear on the distinction
> between a file and a url here. If you can describe what you want to happen
> in exact terms, there is a much better chance that the configuration
> you want will be clear.
>
> A file is a thing available on the local nginx filesystem. Its full name
> will be some thing like /usr/local/nginx/html/one/two.
>
> A url is a thing available by proxy_pass:ing to a http server. (That's
> good enough for these purposes.) Its full name will be something like
> http://upstream/one/two.
>
> (The http server on upstream may have a direct mapping between urls it
> receives and files it knows about; that's because those files are on
> upstream's local filesystem. Similarly, nginx receives requests which
> are urls, and it may map them to files or to other urls. This can get
> confusing. That's why it is useful to be explicit.)
>
>> https://gist.github.com/lucasRolff/c7ea13305e9bff40eb6729246cd7eb39
>>
>> My nginx config for somewhat reason doesn't work – or maybe it's because I misunderstand how try_files actually work.
>
> try_files checks for the existence of a file. In the common case, the full
> name of the file that it checks is the concatenation of $document_root
> with the argument to try_files.
>
>> So I have URLs such as:
>>
>> minio.box.com/bucket1/
>> minio.box.com/bucket43253/
>>
>>
>> When I request these URL's I want nginx to check if index.html exists in the directory (it's an actual file on the filesystem) - if it does, serve this one, else go to @minio location.
>
> Can you be specific here, with a worked example?
>
> The request to nginx is for /one/two/. What do you want nginx to do? (If
> you mention the word "file", please use the full name of the file that
> you are interested in.)
>
> Then, a separate request to nginx is for /one/three. Same question.
>
>> For any other file within the directory, I will just go to @minio location so if I request unicorn.png it should go in @minio location as well.
>>
>> Is there any decent (non-evil) way of doing this?
>>
>> I assume I have to define the root directive to make try_files work, but what would I actually have to define, to make nginx use try_files for index.html *within* the specific bucket?
>
> nginx does not know about buckets. It knows about incoming requests,
> and it knows about files and directories.
>
>
> I *suspect* that you can do what you want with one "location ~ /$"
> inside your "location /"; but I'm not fully clear on what you want.
>
> I also suspect that the correct solution is to just configure the
> upstream http server to serve the contents of index.html if it exists,
> when it gets a request ending in / -- presumably there's a reason why
> that isn't done instead.
>
> Good luck with it,
>
> 	f

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.nginx.org/pipermail/nginx/attachments/20170501/09bc108a/attachment-0001.html>


More information about the nginx mailing list