Search
Varnish Controller

Routing Decisions

Introduction

This tutorial covers examples and a practical look into the controllers routing decisions: ASN, CIDR and Geolocation. More information regarding these routing decisions can be found here.

Note: From version 5.1 of the controller, multiple routing decisions can be configured as a reject type. As a reject type, the tag ID do not have to be defined.

Environment

This tutorial is dependent on: HTTP Routing and assumes that the environment described there is installed and ready.

CIDR

This is a practical example of setting up CIDR(classless-inter-domain-routing) based routing. More information regarding CIDR can be found here.

Configure the CIDR Decision

  1. Create a CIDR route.
# Every CIDR needs a corresponding Tag ID. The format is `<CIDR>:<TagID>`. Multiple
# CIDR's can be added with the format of: `<CIDR-1>:<TagID>,<CIDR-2>:<TagID>,..`
$ vcli cidrroutes add cidrRoute --cidr-to-tag=17.5.0.0/16:1 --subdecision=leastutilized
+----+---------------+--------------------------------+---------------------+
| ID |     Name      |          CIDR-To-Tags          |   Subdecision       |
+----+---------------+--------------------------------+---------------------+
|  1 | cidrRoute     | 17.5.0.0/16:1(prod)            | LeastUtilized       |
+----+---------------+--------------------------------+---------------------+
  1. Update the routing rule.
$ vcli rr update 1 --lookup-order=cidr:1
+----+---------+------+------+-------+---------------+
| ID |  Name   | DNS  | HTTP | Order | Debug Headers |
+----+---------+------+------+-------+---------------+
|  1 | Routing | true | true | cidr:1 | true         |
+----+---------+------+------+-------+---------------+
  1. Verify that the request redirects based on CIDR.
$ curl -v http://172.31.0.203:8900 -H "Host: mysite.example.com" -H "X-forwarded-for: 17.5.14.1"
< HTTP/1.1 302 Found
< Server: Varnish Request Router/5.1.0
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Methods: GET
< X-Router-Name: router1
< X-Router-LookupTime: 10.578µs
< X-Router-ClientIP: 17.5.0.0
< X-Router-RouteType: cidr:1
< X-Router-RouteMatch: 17.5.0.0/16(CIDR)
< X-Router-Endpoint: 0-agent2
< X-Router-Trace: [cidr:1]
< X-Router-Subdecision: Leastutilized
< Location: http://172.31.0.202:8081/mysite.example.com/

RegExp

This is a practical example of setting up RegExp (Regular Expression) based routing. More information regarding RegExp can be found here.

Configure the RegExp Decision

  1. Create a RegExp route
# All User-Agent's containing curl should be routed to agents with tag ID 1
$ vcli regexp add test --regexp User-Agent:\".\*curl.\*\":1
+----+------+--------+-----------------------------+-------------+----------------+---------+
| ID | Name | Reject |            RegExps          | Subdecision |  Organization  | Creator |
+----+------+--------+-----------------------------+-------------+----------------+---------+
|  1 | test | false  | User-Agent:.*curl.*:1(prod) | Healthy     | [System Admin] | test(1) |
+----+------+--------+-----------------------------+-------------+----------------+---------+
  1. Update the routing rule
$ vcli rr update 1 --lookup-order=regexp:1
  1. Verify using curl
$ curl -v http://172.31.0.203:8900 -H "Host: mysite.example.com" -H "X-forwarded-for: 17.5.14.1"
< HTTP/1.1 302 Found
< Server: Varnish Request Router/5.1.0
< Date: Tue, 07 Feb 2023 14:55:10 GMT
< Content-Length: 0
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Methods: GET,HEAD
< Location: http://172.25.255.44:6081/mysite.example.com/
< X-Router-Name: router1
< X-Router-LookupTime: 14.326µs
< X-Router-ClientIP: 17.5.14.1
< X-Router-RouteType: regexp:1
< X-Router-RouteMatch: user-agent:.*curl.*(RegExp)
< X-Router-Endpoint: 0-agent2
< X-Router-Trace: [regexp:1]
< X-Router-Subdecision: Healthy

Reject

This is a practical example of setting up reject based routing. More information regarding reject routing can be found here.

  1. Create a RegExp route (to be used for rejection)
# Create a regexp rule that will be used as a reject, to reject all curl users.
# NOTE: Since we configure it as a reject, we don't need a tag ID.
$ vcli regexp add test --reject --regexp User-Agent:\".\*curl.\*\"
+----+------+--------+---------------------+-------------+----------------+---------+
| ID | Name | Reject |       RegExps       | Subdecision |  Organization  | Creator |
+----+------+--------+---------------------+-------------+----------------+---------+
|  1 | test | true   | User-Agent:.*curl.* | N/A         | [System Admin] | test(1) |
+----+------+--------+---------------------+-------------+----------------+---------+
  1. Create a Reject route
# Here we reference our previously created regexp with its ID (regexp:1)
# Respond with HTTP Status Code 503
$ vcli reject add test --decision regexp:1 --http-resp-code 503
+----+------+-----------------+----------------+----------+----------------+---------+
| ID | Name | Reject All HTTP | Reject All DNS | Decision |  Organization  | Creator |
+----+------+-----------------+----------------+----------+----------------+---------+
|  1 | test | false           | false          | RegExp:1 | [System Admin] | test(1) |
+----+------+-----------------+----------------+----------+----------------+---------+
  1. Update the routing rule
$ vcli rr update 1 --lookup-order=reject:1
  1. Verify
$ curl -v http://172.31.0.203:8900 -H "Host: mysite.example.com" -H "X-forwarded-for: 17.5.14.1"
< HTTP/1.1 503 Service Unavailable
< Server: Varnish Request Router/5.1.0
< Date: Tue, 07 Feb 2023 15:07:53 GMT
< Content-Length: 0
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Methods: GET,HEAD
< X-Router-Name: router1
< X-Router-LookupTime: 12.568µs
< X-Router-ClientIP: 17.5.14.1
< X-Router-RouteType: reject:1
< X-Router-RouteMatch: .*curl.*(RegExp - REJECT)
< X-Router-Trace: [reject:1]

ASN

This is a practical example of setting up ASN(Autonomous System Number) based routing. More information regarding ASNs can be found here.

Requirements

  • MMDB ASN database for lookups. Details can be found here.

MMDB ASN Database

The MMDB ASN database needs to be added to the router container. The path could be either a file path or an URL, which makes it possible to have the MMDB on a remote service. the file can by updated or changed in runtime and will be re-read on configured intervals, see File watcher.

  1. Shutdown the router container.
$ docker stop router1
  1. Start router1 with the path to the MMDB.
# <path-to-asn-mmdb> Can be either a file path or an URL.
$ docker-compose run -d -e VARNISH_CONTROLLER_ROUTER_NAME=myASNRouter -e VARNISH_CONTROLLER_MMDB_ASN_FILE="<path-to-asn-mmdb>" router1

Configure the ASN Decision

  1. Create an ASN route.
# Every ASN needs a corresponding Tag ID. The format is `<ASN>:<TagID>`.
# Multiple ASN's can be added with the format of: `<ASN-1>:<TagID>,<ASN-2>:<TagID>,..`
# This example uses 237 as an ASN, a different ASN might be needed depending on the ISP.
$ vcli asnroutes add asnRoute --asn-to-tag=237:1 --subdecision=leastutilized
+----+---------------+--------------------------------+---------------------+
| ID |     Name      |          ASN-To-Tags           |   Subdecision       |
+----+---------------+--------------------------------+---------------------+
|  1 | asnRoute      | 237:1(prod)                    | LeastUtilized       |
+----+---------------+--------------------------------+---------------------+
  1. Update the routing rule.
$ vcli rr update 1 --lookup-order=asn:1
+----+---------+------+------+-------+---------------+
| ID |  Name   | DNS  | HTTP | Order | Debug Headers |
+----+---------+------+------+-------+---------------+
|  1 | Routing | true | true | asn:1 | true          |
+----+---------+------+------+-------+---------------+
  1. Verify that the request directs based on ASN
$ curl -v http://172.31.0.203:8900 -H "Host: mysite.example.com" -H "X-forwarded-for: 35.128.0.0"
< HTTP/1.1 302 Found
< Server: Varnish Request Router/5.1.0
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Methods: GET
< X-Router-Name: router1
< X-Router-LookupTime: 38.808µs
< X-Router-ClientIP: 35.128.0.0
< X-Router-RouteType: asn:1
< X-Router-RouteMatch: 237(ASN)
< X-Router-Endpoint: 0-agent1
< X-Router-Trace: [asn:1]
< X-Router-SubDecisionType: Leastutilized
< Location: http://172.31.0.202:8081/mysite.example.com/

Geolocation

Geolocation routing makes it possible to configure routing based on clients geolocation. Each geolocation configured is connected to a tag and the client will be routed to one of the endpoints within the tag. More information regarding the Geolocation decision can be found here.

Requirements

  • MMDB GeoIP City database for geolocation lookups. Details can be found here.
  • CSV GeoIP City database for location reference. Details can be found here.

MMDB Database

The MMDB database needs to be added to the router container. The path could be either a file path or an URL, which makes it possible to have the mmdb on a remote service. The file can by updated or changed in runtime and will be re-read at configured intervals, see File watcher.

  1. Start by adding mmdb to the environment.
$ docker stop router
  1. Start router with the mmdb file.
# <path-to-mmdb> Can be either a file path or an URL.
$ docker-compose run -d -e VARNISH_CONTROLLER_ROUTER_NAME=myASNRouter -e VARNISH_CONTROLLER_MMDB_FILE="<path-to-mmdb>" brainz

CSV Database

For ensuring correctness when adding Geolocation routing the brainz instances needs a corresponding CSV version of the MMDB database, this ensures also that geolocations with non-unique naming such as London, which exists in multiple locations will be routed correctly, because it matches on Geoname ID.

The CSV GeoIP database needs to be added to the brainz container. The path could be either a file path or URL, which makes it possible to have the CSV on a remote service. The file can be updated or changed in runtime and will be re-read at configured intervals. See File CSV watcher.

  1. Add the CSV to the environment.
$ docker stop brainz
  1. Start brainz with the CSV version.
# <path-to-mmdb-csv> Can be either a file path or an URL.
$ docker-compose run -d -e VARNISH_CONTROLLER_BRAINZ_NAME=myBrainz -e VARNISH_CONTROLLER_MMDB_FILE_CSV="<path-to-mmdb-csv>" brainz

Configure the Geolocation Decision

  1. Lookup which geolocations that exists(This depends on the CSV file loaded into the controller).
$ vcli geos suggestions europe
+-------------+-------------+-------------+----------------+------------+------------+
| Suggestions |    Type     | Subdivision |    Country     | Continent  | Geoname ID |
+-------------+-------------+-------------+----------------+------------+------------+
| Europe      | Continent   |             |                | Europe     |    6255148 |
+-------------+-------------+-------------+----------------+------------+------------+
  1. Create a Geolocation route.
# This assumes that the client IP resolves to Europe from the MMDB. Use a location
# that will match the requests going through the router in your environment.

$ vcli geolocationroutes add geolocationRoute --geolocation-to-tag="Europe:1" --subdecision=leastutilized
+----+--------------------+-------------------------+---------------+
| ID |        Name        |   Geolocation-To-Tags   |  Subdecision  |
+----+--------------------+-------------------------+---------------+
|  1 | geolocationRoute   | Europe(6255148):1(prod) | LeastUtilized |
+----+--------------------+-------------------------+---------------+
  1. Update the routing rule.
$ vcli rr update 1 --lookup-order=geolocation:1
+----+-------+------+------+---------------+
| ID | Name  | DNS  | HTTP |     Order     |
+----+-------+------+------+---------------+
|  1 | video | true | true | geolocation:1 |
+----+-------+------+------+---------------+
  1. Verify that the request directs based on Geolocation
$ curl -v http://172.31.0.203:8900 -H "Host: mysite.example.com"
< HTTP/1.1 302 Found
< Server: Varnish Request Router/5.1.0
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Methods: GET
< X-Router-Name: router1
< X-Router-LookupTime: 38.456µs
< X-Router-ClientIP: 2.125.160.216
< X-Router-RouteType: geolocation:1
< X-Router-RouteMatch: Europe(Continent)
< X-Router-Endpoint: 0-agent1
< X-Router-Trace: [geolocation:1]
< X-Router-SubDecisionType: Leastutilized
< Location: http://172.31.0.201:8081/mysite.example.com/

Cleanup

The docker-compose will create volumes for storing database and other configuration data. These can be cleaned up if you want to start from scratch.

# Stop environment
docker-compose down
# Remove volumes
docker volume rm router_example_dbdata router_example_varnish router_example_vcontroller