Nginx is a great web server, Varnish is a great cache, both are great reverse proxy servers.
If you're only using Nginx for URL rewriting, redirection & error handling, you don't really need Nginx. Varnish can do this just as good.
VCL template
The basic VCL configuration I would recommend is the following: https://www.varnish-software.com/developers/tutorials/example-vcl-template/
It's Varnish Software's recommended non-framework-specific VCL. It covers the following items:
- Stripping of campaign parameters from the URL
- Sorting query strings
- Header cleanup
- Static file caching
- Backend health checking
- Edge Side Include parsing
- Setting the
X-Forwarded-Proto
header
- Stripping off tracking cookies
- Create protocol-aware cache variations
URL rewriting
If you want to perform URL rewriting, you can write if-statements in VCL and reset the URL via set req.url = "..."
. You can also perform find/replace using the regsuball()
function and use regular expressions.
See https://www.varnish-software.com/developers/tutorials/varnish-configuration-language-vcl for a basic VCL tutorial.
Here's a VCL interpretation of the 2 rewrite rules in your Nginx config:
sub vcl_recv {
if(req.url ~ "^(.+)/$") {
return(synth(301,regsuball(req.url,"^(.+)/$","\1")));
}
if(req.url ~ "^/(.*)(\.html|index)(\?|$)") {
return(synth(301,regsuball(req.url,"^/(.*)(\.html|index)(\?|$)","/\1")));
}
}
sub vcl_synth {
if(resp.status == 301) {
set resp.http.Location = resp.reason;
set resp.reason = "Moved Permanently";
set resp.body = "Redirecting.";
return(deliver);
}
}
This example code will redirect /test/
to /test
and /test.html
to /test
, just like in your Nginx config.
Error handling
Errors coming from the backend are handled in VCL's vcl_backend_error
subroutine and can be customized.
You also have the ability to generate your own errors in Varnish based on an incoming request. You do this by returning return(synth(INT status, STRING reason);
in your VCL code. We already did this in the URL redirection example.
Customizing the output of synthetic responses is similar to backend errors and happens in the vcl_synth
subroutine.
Here's an example how you can modify the output template of backend & synthetic errors. The example uses an HTML template: https://www.varnish-software.com/developers/tutorials/vcl-synthetic-output-template-file/
This should give you a clear indication on how to handle errors coming from your NodeJS app.
Keep Nginx in the setup or not?
Based on how you're describing the situation, you don't really need Nginx. All the caching and reverse proxy logic can easily be done in Varnish.
However there are 2 reasons that would justify the use of Nginx in this project:
- TLS handling
- Caching large volumes of static data
Let's talk about TLS first: the open source version of Varnish currently doesn't support native TLS. While the commercial version does, but for the open source version of Varnish, you need to terminate TLS.
We developed our own TLS proxy. It's called Hitch and works really well with Varnish. See https://www.varnish-software.com/developers/tutorials/terminate-tls-varnish-hitch/ for a tutorial.
But one could argue that if you're already committed to using Nginx, you might as well use it to terminate the TLS session before connecting to Varnish.
The other reason could be static data. Don't get me wrong: Varnish is great at caching static data and might even be faster than Nginx at it. However, in Varnish caching of large volumes of static data might eat away from your caching space.
In Varnish you need to assign how much memory will be used for caching. If you only have 1GB of memory assigned and have 2GB of static files to cache, your cache may end up completely full. That's not a big issue, because the Least Recently Used algorithm will automatically clear space by removing long tail content. But if that is not acceptable, Nginx can still be used.
If your static file collection is 1GB, but your cache is bigger, you don't really need to add Nginx.