I want to simultaneously optimize my site for HTTP/2 and HTTP/1.x. For HTTP/2 (and SPDY), since there are no additional round-trips for requests, I'd like to serve my CSS and JS files separately, to gain the benefit of independently caching each file. However, if I only did that, HTTP/1.x clients would suffer from additional round-trips; so for them, I'd like to serve my CSS and JS files concatenated.
Ideally, HTTP/2 users would be served this HTML:
<html>
<head>
<link rel="stylesheet" href="stylesheet-1.css">
<link rel="stylesheet" href="stylesheet-2.css">
</head>
<body>
<script src="script-1.js"></script>
<script src="script-2.js"></script>
</body>
</html>
And HTTP/1.x users would be served this HTML:
<html>
<head>
<link rel="stylesheet" href="all-stylesheets.css">
</head>
<body>
<script src="all-scripts.js"></script>
</body>
</html>
Is it possible to configure nginx to serve different HTML files depending on the client's protocol?
Yes, you can do so via the $server_protocol
variable. I would usually recommend to interpolate file locations by variable expansion. But in this case I fear this would leave you open to injection attacks as the content of this variable seems to be copied verbatim from the request line.
There is a solution by exploiting the ngx_http_map_module, though. Assuming your site sits in /srv/www
:
map $server_protocol $version {
default "1.1";
"HTTP/2.0" "2.0";
# extra case for any SPDY version
"~SPDY/" "2.0";
}
server {
listen [::]:80;
# The line below requires a working SSL configuration!
listen [::]:443 ssl http2;
server_name example.com
root /srv/www/http-1.1/htdocs;
location / {
root /srv/www/http-$version/htdocs;
try_files $uri $uri/ @fallback;
}
# fallback for HTTP/1.1 files. If this fails as well, we get a 404.
location @fallback {
try_files $uri $uri/ =404;
}
}
This would serve all requests out of /srv/www/http-2.0/htdocs
for HTTP/2.0 requests and out of /srv/www/http-1.1/htdocs
for all others. If a resource specially crafted for HTTP/2.0 cannot be found, the coresponding file for HTTP/1.1 is being served as a fallback.