87

After many hours getting nginx to serve single files such as robots.txt (hint: clear your browser cache each time), I wound up with two different ways, one using the alias directive, and one using the root directive, like so:

location /robots.txt { alias /home/www/static/robots.txt; }
location /robots.txt { root /home/www/static/;  }

Is there any functional difference between the two? Or security issues? Any conflicts with other directives? (Both seemed fine with another /static location). Or any reason to pick one over the other?

Note - I didn't use both at the same time :) Rather I tried each, one at a time, and both worked. I'm not asking how they both interact together in the same file, but which one would be better to use.

Cyclops
  • 1,139
  • 2
  • 9
  • 13

4 Answers4

89

Well, these two directives are slightly functional different because you do not use exact match in the latter case. So, /robots.txt1111 will match your second location too.
location =/robots.txt { root /home/www/static/; } is an exact functional equivalent of your first directive.

Alex
  • 7,789
  • 4
  • 36
  • 51
59

Yes, there is a difference: With "alias" you can .. well alias to another file name, like

location /robots.txt { alias /home/www/static/any-filename.txt; }

whereas

location /robots.txt { root /home/www/static/; }

forces you to name your file on the server also robots.txt. I use the first option since I like to name my robots files on my server as tld.domain.subdomain-robots.txt; e.g

location /robots.txt { alias /home/www/static/ch.notex.static-robots.txt; }
Hasan Karahan
  • 591
  • 4
  • 2
7

I think it's worth explicitly laying out that nginx is operating on prefixes and not files per se. In the first case,

location /robots.txt { alias /home/www/static/robots.txt; }

nginx replaces the string prefix /robots.txt in the URL path with /home/www/static/robots.txt and then uses the result as a filesystem path. Represented as pseudocode, this would be something like:

if urlPath.startsWith("/robots.txt") {
    fsPath := "/home/www/static/robots.txt" + urlPath.stripPrefix("/robots.txt")
    serveFile(fsPath)
}

So /robots.txt is served from /home/www/static/robots.txt because /robots.txt stripped of the /robots.txt prefix is the empty string, and appending the empty string to /home/www/static/robots.txt leaves it unchanged. But, /robots.txt1 would be served from /home/www/static/robots.txt1 and /robots.txt/foobar would be served from /home/www/static/robots.txt/foobar. Those files may not exist, causing nginx to send a 404 response, and it's likely that robots.txt is not a directory anyway, but nginx doesn't know that in advance, and this is all based on string prefixes and not what appears to be a file or directory by the absence or presence of a trailing slash.

Whereas, in the second case,

location /robots.txt { root /home/www/static/; }

nginx inserts the string /home/www/static/ at the beginning of the URL path and then uses the result as a file system path. In pseudocode, this would be something like:

if urlPath.startsWith("/robots.txt") {
    fsPath := "/home/www/static/" + urlPath
    serveFile(fsPath)
}

This has the exact same result as the first case, but for a different reason. There's no prefix stripping, but since every URI path has to contain the prefix /robots.txt, then the file system paths will always start with /home/www/static//robots.txt which is equivalent to /home/www/static/robots.txt.

Of course, the pseudocode doesn't quite tell the whole story, as e.g. nginx won't blindly use raw URL paths like /../../../etc/passwd, the try_files directive changes the behavior of root/alias, and there are constraints on where alias can be used.

kbolino
  • 332
  • 2
  • 9
0

There is a difference, when the alias is for a whole directory.

    location ^~ /data/ { alias /home/www/static/data/; }

will work, while

    location ^~ /data/ { root /home/www/static/data/; }

won't do. This would have to be

    location ^~ /data/ { root /home/www/static/; }

(Easy to confuse)

BurninLeo
  • 860
  • 2
  • 11
  • 28