Nginx - root versus alias, for serving single files?

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.


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; }

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.