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.
Several routing decisions can be configured as a reject type. As a reject type, the tag ID do not have to be defined.
This tutorial is dependent on: HTTP Routing and assumes that the environment described there is installed and ready.
This is a practical example of setting up CIDR(classless-inter-domain-routing) based routing. More information regarding CIDR can be found here.
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 |
+----+---------------+--------------------------------+---------------------+
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 |
+----+---------+------+------+-------+---------------+
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/
This is a practical example of setting up RegExp (Regular Expression) based routing. More information regarding RegExp can be found here.
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) |
+----+------+--------+-----------------------------+-------------+----------------+---------+
Update the routing rule
vcli rr update 1 --lookup-order=regexp: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
This is a practical example of setting up reject based routing. More information regarding reject routing can be found here.
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) |
+----+------+--------+---------------------+-------------+----------------+---------+
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) |
+----+------+-----------------+----------------+----------+----------------+---------+
Update the routing rule
vcli rr update 1 --lookup-order=reject: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]
This is a practical example of setting up ASN(Autonomous System Number) based routing. More information regarding ASNs can be found here.
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.
Shutdown the router container.
docker stop router1
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
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 |
+----+---------------+--------------------------------+---------------------+
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 |
+----+---------+------+------+-------+---------------+
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 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.
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.
Start by adding mmdb to the environment.
docker stop router
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
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.
Add the CSV to the environment.
docker stop brainz
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
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 |
+-------------+-------------+-------------+----------------+------------+------------+
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 |
+----+--------------------+-------------------------+---------------+
Update the routing rule.
$ vcli rr update 1 --lookup-order=geolocation:1
+----+-------+------+------+---------------+
| ID | Name | DNS | HTTP | Order |
+----+-------+------+------+---------------+
| 1 | video | true | true | geolocation: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/
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