636

I need to serve my app through my app server at 8080, and my static files from a directory without touching the app server.

    # app server on port 8080
    # nginx listens on port 8123
    server {
            listen          8123;
            access_log      off;

            location /static/ {
                    # root /var/www/app/static/;
                    alias /var/www/app/static/;
                    autoindex off;
            }


            location / {
                    proxy_pass              http://127.0.0.1:8080;
                    proxy_set_header        Host             $host;
                    proxy_set_header        X-Real-IP        $remote_addr;
                    proxy_set_header        X-Forwarded-For  $proxy_add_x_forwarded_for;
            }
    }

Now, with this config, everything is working fine. Note that the root directive is commented out.

If I activate root and deactivate the alias, it stops working. However, when I remove the trailing /static/ from root, it starts working again.

Can someone explain what's going on?

treecoder
  • 43,129
  • 22
  • 67
  • 91

8 Answers8

1412

There is a very important difference between the root and the alias directives. This difference exists in the way the path specified in the root or the alias is processed.

root

  • the location part is appended to root part
  • final path = root + location

alias

  • the location part is replaced by the alias part
  • final path = alias

To illustrate:

Let's say we have the config

location /static/ {
    root /var/www/app/static/;
    autoindex off;
}

In this case the final path that Nginx will derive will be

/var/www/app/static/static

This is going to return 404 since there is no static/ within static/

This is because the location part is appended to the path specified in the root. Hence, with root, the correct way is

location /static/ {
    root /var/www/app/;
    autoindex off;
}

On the other hand, with alias, the location part gets dropped. So for the config

location /static/ {
    alias /var/www/app/static/;
    autoindex off;           ↑
}                            |
                             pay attention to this trailing slash

the final path will correctly be formed as

/var/www/app/static

In a way this makes sense. The alias just lets you define a new path to represent an existing "real" path. The location part is that new path, and so it gets replaced with the real path. Think of it as a symlink.

Root, on the other hand is not a new path, it contains some information that has to be collated with some other info to make the final path. And so, the location part is used, not dropped.

The case for trailing slash in alias

There is no definitive guideline about whether a trailing slash is mandatory per Nginx documentation, but a common observation by people here and elsewhere seems to indicate that it is.

A few more places have discussed this, not conclusively though.

https://serverfault.com/questions/376162/how-can-i-create-a-location-in-nginx-that-works-with-and-without-a-trailing-slas

https://serverfault.com/questions/375602/why-is-my-nginx-alias-not-working

treecoder
  • 43,129
  • 22
  • 67
  • 91
  • 147
    The trailing slash on the alias path is essential! – mafrosis Dec 16 '15 at 07:30
  • 9
    This is all great (it helped me fix my config issues), but I wonder what logging settings people could use to help diagnose these kinds of problems? Like, anything that would print to logs stuff like "received request for [...], matched by "location [...]" config block, searching directory [...]" – Pistos Jun 05 '18 at 17:18
  • 6
    @Pistos: put `log_format scripts '$document_root | $uri | > $request';` into `http` section and `access_log /var/log/nginx/scripts.log scripts;` into `server` section of nginx config.. – helvete Jun 06 '18 at 13:24
  • 1
    Thanks! Indeed the trailing slash is essential on the alias, otherwise i got `nginx: [emerg] invalid number of arguments in "alias" directive`, and the server went down during its restart. – FotisK Jul 18 '18 at 21:36
  • @mafrosis Why is it essential? – Bruce Sun Feb 25 '20 at 02:17
  • @mafrosis I was going crazy trying to understand why the heck my configuration wasn't working. IMHO the answer by treecoder is absolutely **NOT** complete without clarifying that you must put a trailing `/` otherwise alias will not work. – Bakuriu Apr 19 '20 at 11:26
  • Does the trailing slash you talk about have anything to with me getting a 404 on `/my/path` but a 200 on `/my/path/`? – OrangePot Oct 30 '20 at 18:39
  • Can you explain my observation [here](https://stackoverflow.com/questions/65651059/in-nginx-location-block-with-regex-match-the-entire-path-including-the-locatio), where the **entire path including the location part** is appended to the alias? – Avner Moshkovitz Jan 10 '21 at 07:58
156

as say as @treecoder

In case of the root directive, full path is appended to the root including the location part, whereas in case of the alias directive, only the portion of the path NOT including the location part is appended to the alias.

A picture is worth a thousand words

for root:

enter image description here

for alias:

enter image description here

Mahmoud Al-Qudsi
  • 28,357
  • 12
  • 85
  • 125
liuzhijun
  • 4,329
  • 3
  • 23
  • 27
44

In your case, you can use root directive, because $uri part of the location directive is the same with last root directive part.

Nginx documentation advices it as well:
When location matches the last part of the directive’s value:

location /images/ {
    alias /data/w3/images/;
}

it is better to use the root directive instead:

location /images/ {
    root /data/w3;
}

and root directive will append $uri to the path.

aioobe
  • 413,195
  • 112
  • 811
  • 826
antonbormotov
  • 1,821
  • 2
  • 20
  • 32
25

Just a quick addendum to @good_computer's very helpful answer, I wanted to replace to root of the URL with a folder, but only if it matched a subfolder containing static files (which I wanted to retain as part of the path).

For example if file requested is in /app/js or /app/css, look in /app/location/public/[that folder].

I got this to work using a regex.

 location ~ ^/app/((images/|stylesheets/|javascripts/).*)$ {
     alias /home/user/sites/app/public/$1;
     access_log off;
     expires max;
 }
meloncholy
  • 2,122
  • 18
  • 16
  • 3
    Thanks for this answer. I know this is 3 years later, but could anyone explain if there is a performance and/or security tradeoff between using alias versus root? – Mina May 28 '17 at 15:33
  • 3
    @Mina It's better to use root if you can. (There's a comment in the docs http://wiki.nginx.org/HttpCoreModule#alias ) – Matthew Wilcoxson Aug 16 '18 at 17:35
  • This is exactly what I came here for – alienfromouterspace Jul 07 '19 at 06:17
  • 1
    Both are safe, but be careful when using alias with location that doesn't end with / It is a vulnerability https://github.com/yandex/gixy/blob/master/docs/en/plugins/aliastraversal.md – Eduardo Sep 23 '21 at 18:49
8

alias is used to replace the location part path (LPP) in the request path, while the root is used to be prepended to the request path.

They are two ways to map the request path to the final file path.

alias could only be used in location block, and it will override the outside root.

alias and root cannot be used in location block together.

Yao Zhao
  • 4,373
  • 4
  • 22
  • 30
3
server {
    server_name xyz.com;
    root /home/ubuntu/project_folder/;

    client_max_body_size 10M;
    access_log  /var/log/nginx/project.access.log;
    error_log  /var/log/nginx/project.error.log;

    location /static {
        index index.html;
    }

    location /media {
        alias /home/ubuntu/project/media/;
    }
}

Server block to live the static page on nginx.

Tapish
  • 51
  • 3
  • Be careful when using alias with location that doesn't end with / It is a vulnerability https://github.com/yandex/gixy/blob/master/docs/en/plugins/aliastraversal.md Files from the project directory can be revealed using /media.. on request – Eduardo Sep 23 '21 at 18:46
3

Though my answer is not needed, But I think It is necessary to add this, root and alias works differently when is come to regex.

 location ~ /static/my.png$ {
     alias /var/www/static/;
     access_log off;
     expires max;
 }

In this case the regex match is not going to add with alias, nginx will search only /var/www/static/ not /var/www/static/my.png. You have to use regex capture.

 location ~ /static/my.png$ {
     root /var/www;
     access_log off;
     expires max;
 }

In this case the matched url going to add with root, nginx will search /var/www/static/my.png.

Jean-Philippe Caruana
  • 2,617
  • 4
  • 25
  • 47
2

In other words on keeping this brief: in case of root, location argument specified is part of filesystem's path and URI . On the other hand — for alias directive argument of location statement is part of URI only

So, alias is a different name that maps certain URI to certain path in the filesystem, whereas root appends location argument to the root path given as argument to root directive.