Running Varnish on Fly

The goal: run Varnish in a Fly container as a caching proxy in front of another Fly application.

I ended up switching to Cloudflare for running a Varnish-style cache in front of my Fly application (purely to reduce the number of moving parts I needed to maintain), but I'm publishing my notes on how I got Varnish working here in case I need them in the future.

The Dockerfile

Fly apps run Docker containers. Here's the minimal Dockerfile that worked for me:

FROM varnish

COPY default.vcl /etc/varnish/

USER varnish

    "varnishd", "-F", \
    "-f", "/etc/varnish/default.vcl", \
    "-a", "http=:8000,HTTP", \
    "-s", "malloc,256M", \
    "-T", "none" \


The default.vcl file is the Varnish configuration file. Here's the one I used:

vcl 4.1;

backend default {
  .host = "";
  .port = "80";

sub vcl_recv {
    unset req.http.x-cache;

sub vcl_hit {
    set req.http.x-cache = "hit";

sub vcl_miss {
    set req.http.x-cache = "miss";

sub vcl_pass {
    set req.http.x-cache = "pass";

sub vcl_pipe {
    set req.http.x-cache = "pipe uncacheable";

sub vcl_synth {
    set req.http.x-cache = "synth synth";
    set resp.http.x-cache = req.http.x-cache;

sub vcl_deliver {
    if (obj.uncacheable) {
        set req.http.x-cache = req.http.x-cache + " uncacheable" ;
    } else {
        set req.http.x-cache = req.http.x-cache + " cached" ;
    set resp.http.x-cache = req.http.x-cache;


The Fly configuration file for the application:

app = "my-varnish-app"
primary_region = "lax"
kill_signal = "SIGINT"
kill_timeout = "5s"

  internal_port = 8000
  protocol = "tcp"

    hard_limit = 25
    soft_limit = 20

    handlers = ["http"]
    port = 80

    handlers = ["tls", "http"]
    port = 443

    interval = 10000
    timeout = 2000
    grace_period = "10s"

I'm using internal_port = 8000 here because I ran Varnish using -a "http=:8000,HTTP" in the ENTRYPOINT in the Dockerfile.

Deploying the application

With all of the above files in a folder, the deploy command looks like this:

flyctl deploy

The result ends up running at, and will serve pages from the underlying app - only caching them if those pages include a cache-control: s-maxage=15 header or similar.

Further reading

I pieced this together mainly with help from the information in this 4 year old forum thread, plus searching around for more recent Varnish configuration examples.

Created 2024-01-08T15:31:00-08:00 · Edit