Dockerization: Varnish, Nginx & try to hit the first cache
Tags: docker, varnish, nginx
Published: 2019-06-11 04:34:34

## Introduction

Varnish help to decreases directly request to the web server by cache response after first-time response, help your website perform better. You can make the configuration for caching-path, what you want to ignore, how to purge/ban cache.

I like Docker, I run my website on Docker, multiple services by Docker-Compose, I’m just a developer, no more knowledge about the system like a DevOps, I want to make it run by the simple way.

I would like to mention online NGINX and varnish. It’s mean NGINX will cover backend and connect to varnish to handle the response.

## Requisites

* Nginx has covered web and it’s still running before installing varnish
* Nginx and varnish must be on the same internal network

## Notes

* Nginx will run out with port 8080
* Varnish will run out with port 80
* Varnish can’t handle SSL. If you need to handle this protocol, this post can’t help you more
* Property build: `../nginx-server` includes NGINX configuration, you could use the image directly. It should be controlled on your side
Property build: `../varnish` includes varnish configuration. I will explain only this part

## Docker images

Varnish docker image: https://github.com/newsdev/docker-varnish (It has included the way to setting and run docker image, I just write more for docker-compose config)

Nginx: https://hub.docker.com/_/nginx/

## Settings

* Create `../varnish` folder
* Access to created folder and make `Dockerfile`

```bash
FROM newsdev/varnish:4.1.0
ENV VARNISH_MEMORY 100m
```

* Create `default.vcl` in the same folder, it’s varnish configuration

```bash
vcl 4.0;
backend default {
  .host = "nginx-server";
  .port = "80";
}

# If you don't include below, header Age in response to client always be 0

sub vcl_deliver {
  # Display hit/miss info
  if (obj.hits > 0) {
    set resp.http.V-Cache = "HIT";
  }
  else {
    set resp.http.V-Cache = "MISS";
  }
  set resp.http.Access-Control-Allow-Origin = "*";
  set resp.http.Access-Control-Allow-Headers = "Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Mx-ReqToken,X-Requested-With";
  set resp.http.Allow = "GET, POST";
  set resp.http.Access-Control-Allow-Credentials = "true";
  set resp.http.Access-Control-Allow-Methods = "GET, POST, PUT, DELETE, OPTIONS, PATCH";
  set resp.http.Access-Control-Expose-Headers = "X-Pagination-Total, X-Pagination-Page, X-Pagination-Limit";
}
sub vcl_backend_response {
  if (beresp.status == 200) {
    unset beresp.http.Cache-Control;
    set beresp.http.Cache-Control = "public; max-age=200";
    set beresp.ttl = 200s;
  }
  set beresp.http.Served-By = beresp.backend.name;
  set beresp.http.V-Cache-TTL = beresp.ttl;
  set beresp.http.V-Cache-Grace = beresp.grace;
}

```

* Modify service’s configuration for `docker-compose.yml`

```yml
version: '2'

networks:
  localnetwork:
    driver: bridge
    ipam:
      driver: default
      config:
        - subnet: 162.11.1.0/24
          gateway: 162.11.1.1
services:

  nginx-server:
    container_name: nginx-server
    build: ../nginx-server
    networks:
      - localnetwork
    ports:
      - "8080:80"
  varnish:
    build: ../varnish
    container_name: varnish
    networks:
      - localnetwork
    ports:
      - "80:80"
    depends_on:
      - nginx-server

```

* Build & run Docker

```bash
docker-compose build
docker-compose up -d
```

* Access URLs and check the headers

```bash
http://docker-host-ip:8080/users/{user_id} #Routing to your method, always no cache
http://docker-host-ip/users/{user_id} #Through Varnish first

```

* Hit varnish caching URL, and see the `Age` value in the response headers:

```bash
Age = 0, Cache wasn’t HIT (known as MISS)
Age != 0, Cache was HIT (you’re successful)
```

## Helpful commands

```bash
# View varnish cache his/miss
docker exec -it varnish bash
varnishncsa -F "%m %U%q ---- %{Varnish:handling}x"
```