Nginx : Serve JPG images from different root and l

2019-04-07 16:34发布

I have 3 different stockage area : "avatars" , "articles", "trends" where I store my images.

I want to "link" the URL "/trends/123.jpg" to trends folder , "/avatars/23.jpg" to avatar and so on.

Configuration 1:

server
{
    listen 8089;
    server_name localhost;

    root /var/www;

    location /trends/
    {
            alias  /var/storage/hottrend/;
    }

    location ~* ^.+\.(jpeg|gif|png|jpg)
    {
            add_header Cache-control "public";
            access_log   off;
            expires      90d;
    }
}

Configuration 1 : "GET /trends/123.jpg" never match /trends/ location, why ?

Configuration 2:

server
{
    listen 8089;
    server_name localhost;

    root /var/www;

    location ~ ^/trends/(.*)\.jpg$
    {
            rewrite ^/trends/(.*)$ /$1 break;

            root  /var/storage/hottrend;
    }

    location ~* ^.+\.(jpeg|gif|png|jpg)
    {
            add_header Cache-control "public";
            access_log   off;
            expires      90d;
    }
}

Configuration 2: The last rule with the caching stuff is not matched. What is the best approach to server JPG files from different location/root ?

标签: nginx
3条回答
爷的心禁止访问
2楼-- · 2019-04-07 16:53

The two configurations have different but related problems. The two issues are:

  1. the order in locations are matched; and
  2. what happens when a location is matched.

I'll first explain how it works, and then I'll address your configurations.

How it works

Location matching

You can find the details on this nginx wiki page, but I have always found the wording to be confusing. (It mixes implementation details in the description of behaviour.) What it means is that locations are matched in the following order:

  1. exact matches like location = /robots.txt
  2. eager non-regex prefixes like location ^~ /trends/
  3. regex matches like location ~* \.(jpg|png), or case-sensitive location ~ \.(jpg|png)
  4. lazy non-regex prefixes like location /trends/ or location /

If multiple regular expressions match, then the first match beats the others. If multiple non-regex prefix match, I think it selects the most specific match -- I'll check this and update.

Location behaviour

A matching location is responsible for serving the designated content. It is also responsible for providing cache-control headers and so on. You can have a location that matches particular URL patterns to apply specific headers, but that location must also serve the content. If it cannot serve the content, you will most likely get an 404 error -- it won't look for other matching locations.

Lastly, be extra careful if you have a rewrite within a location. An internal redirect can happen earlier than some directives, in which case, those directive may not apply before the redirect causes the locations to be searched again.

Configuration 1

Your trends location is a lazy non-regex prefix, so it would only match if the regex location fails to match. You can fix this by using an eager non-regex match, such as

location ^~ /trends {
    ...
}

However, doing so will highlight the other configuration problem.

Configuration 2

You have two locations that could potentially match jpg files. Only one will succeed. If the first matches, then the cache control of the second location won't be applied. If the second matches, then the alias won't take effect.

The fix is to make sure that all directives needed are applied within the location that matches. You can either be explicit in one file, such as

location ^~ /trends
{
    alias /var/storage/hottrend;

    add_header Cache-control "public";
    access_log   off;
    expires      90d;
}

location ~* ^.+\.(jpeg|gif|png|jpg)
{
    add_header Cache-control "public";
    access_log   off;
    expires      90d;
}

The neater solution for managing directives that must be applied to several locations is to factor those details into another file, and then include it at both locations. (Mohammad AbuShady did so in his example.) Something like this:

# Inside your main .conf
location ^~ /trends
{
    alias /var/storage/hottrend;
    include image-headers.conf;
}

location ~* ^.+\.(jpeg|gif|png|jpg)
{
    include image-headers.conf;
}

# Inside image-headers.conf
add_header Cache-control "public";
access_log   off;
expires      90d;
查看更多
男人必须洒脱
3楼-- · 2019-04-07 16:56

well I don't usually use alias but I think this is a good example to use alias for, you can put your caching settings inside /etc/nginx/image_caching.conf. If trends is only used for images i would not try to complicate the regex and assume that it always has images

location /trends {
    alias /var/storage/trends;
    include /etc/nginx/image_caching.conf;
}

And for your example config, you should have not added /trends inside root /var/storage/trends; because it's already used in the location, so i think it would show 404 becuase it's looking for /var/storage/trends/trends/123.jpg

查看更多
三岁会撩人
4楼-- · 2019-04-07 17:01

Nginx checks locations defined as regular expressions in the order in which they appear in the configuration file and uses the location with the first matching expression.

Therefore, you should make sure location ~\.jpg$ appears before any other locations defined as regular expressions

查看更多
登录 后发表回答