Varnish Cache config for Mastodon (rough)

If anyone else is running Mastodon alongside Varnish Cache, this is my initial stab at a configuration that’ll let Varnish handle the static assets, while also ensuring Websockets function and other dynamic stuff stays dynamic:

# Marker to tell the VCL compiler that this VCL has been adapted to the
# new 4.0 format.
vcl 4.0;

sub vcl_recv {

        # Watch for websocket connections and pipe those so they work
        if (req.http.upgrade ~ "(?i)websocket") {
                return (pipe);


        # Cache static locations, ignore all others
        if ( ~"") {
                if (!(req.url ~ "(^/assets/|^/emoji/|^/avatars/|^sounds/)" )) {
                        return (pass);


sub vcl_pipe {
       # Ensure HTTP upgrade requests are processed correctly
        if (req.http.upgrade) {
                set bereq.http.upgrade = req.http.upgrade;

sub vcl_deliver {
       # Optional - set http headers here instead of at the web server level
       # Uncomment & fill in as needed
        if ( ~ "" ) {
                set resp.http.Referrer-Policy = "strict-origin-when-cross-origin";
                set resp.http.Strict-Transport-Security = (your HSTS string here, if applicable)
                set resp.http.X-Content-Type-Options = "nosniff";
                set resp.http.X-XSS-Protection = "1; mode=block";
                set resp.http.X-Frame-Options = "DENY";
                set resp.http.Expect-CT = (your Expect-CT string here, if applicable);
                set resp.http.Content-Security-Policy = "frame-ancestors 'none';default-src 'none'; script-src 'self'; object-src 'self'; style-src 'self' 'sha256-deDIoPlRijnpfbTDYsK+8JmDfUBmpwpnb0L/SUV8NeU=' 'sha256-dsU/1vqKDGkqSAJVJCzaxo3alnWrTU/iQqFREt5QB+g='; img-src * data:; media-src 'self' data:; frame-src 'none'; font-src 'self' data:; connect-src 'self' wss://";
                set resp.http.Public-Key-Pins = {"pin-sha256="your pin(s) here, if applicable"; max-age=5270400"};

As noted, the last header bits are optional—I find it more convenient to set my response headers at the cache layer so that they’re all defined in one place for all my hosts instead of spread across multiple nginx config files, but that’s personal preference.