Can I set set req.backend.host dynamically


#1

Hi, Im wondering if I can set the host field of the “backend” structure during script execution - and if the value I set it to can come from a combination of a string + header values?

For example:

set req.http.enviroment = // some code to parse the environment from the hostname e.g., "staging"
set req.backend = Canonical_Backend;
set req.backend.host = req.http.environment “.” req.http.host “.backend”; // set backend’s “host” field dynamically based on headers and a string value

The reason I want to do this is because I have 10 backends in any one of 4 “environments”. The environments are staging, qa, production and dev. That is 40 backends to deal with. The VCL code for each and all of these environments is almost the same so I would like to write the code once (one vcl script) and use in all environments.

In my case, the backend can be determined based on the req.http.url and the “environment”. So for example, one backend could be “staging.cms.example.com” and another would be “qa.cms.example.com” and yet another is “production.admin.example.com” etc. Instead of hardcoding all 40 backends in my VCL I would just create 1 and then substitute the actual value for the “host” field on-the-fly at request processing time.


Updating the backend definitions in VCL at runtime
VCL: Can we craft and send a HTTP request to an Auth server?
#2

Hi mpapper

Yes, you can change the Host header depending on the request. However, when you have one Fastly service serving different origins or domains you need to bear in mind:

  1. Any change to the service will affect requests for all of the origins or domains. This may be fine for one.example.com and two.example.com, but may not be what you want for dev, staging and www.example.com

  2. If you are serving different content for the same URL you’d need to set the Vary header to let the cache to store different versions based on a specific header. In the case you’ve mentioned you will be OK as the default cache key is composed of the Host header + the path/query string, but if you were to change that algorithm to take another header into consideration you’d need to use Vary.

Alternatively an easier way to set up the backends than using the UI may be to use the API instead:

https://docs.fastly.com/api/config#backend

https://docs.fastly.com/api/config#condition

That might be something to consider.


#3

Thanks Jason for the response. I want to be sure though: I’m not changing the host header I’m changing the backend’s data structure - the host field in particular. This way I would have just one backend in my custom VCL and switch the backend.host value for each and every request (that is not cached) based on my rules for deciding on the proxying to the backend. In my case I have 10 different backends (per each of qa, staging and production) to deal with and thought it would be easier to have just 1 backend in my VCL code and chnage its .host value dependent on the request.

I take your point about one.example.com and two.example.com versus using the same VCL for qa, staging and production domains. I think I need a way to test my VCL in qa/staging before putting into production and would want to keep each of these in separate “services”.


#4

I have the same problem, anyone knows how to resolve mpapper question?


#5

To be clear here, there are two hostnames to consider. The one attached to the definition of an origin is there to allow us to resolve an IP address to which we send origin fetches. The second hostname is the value of the Host: header that we send to that server in the fetch.

The first of those, the hostname for IP lookup, is not something you can change dynamically, but you can configure more than one of them. The Host header that is sent to the backend IS dynamically configurable - it’s just a string variable.

So, this means that while it is NOT possible to reach out to an arbitrary backend server based on a full URL specified in the request, like this:

set req.backend = req.http.X-Backend-Host;  // This doesn't work

You CAN do any of the following:

  1. If all potential backend hostnames would resolve to the same set of IPs, eg if your backends are all on Heroku (in the same Heroku region) or behind some other router that deals with lots of hostnames, then you can safely define one backend using any one of your backend host names, and then change the req.http.host header to tell Heroku’s router which of your backend apps you want to send the request to.

  2. If you have programmatic control over the DNS for your backends, you can change the IP addresses we connect to by changing the address to which your backend hostnames resolve. This will have a latency dictated by your DNS records’ TTLs, and we may impose a minimum TTL too. Some customers do use this to swap out backends without changing their VCL, but it’s more common to do it with multiple backends defined in VCL.

  3. We offer ‘dynamic servers’: https://docs.fastly.com/guides/dynamic-servers/creating-and-using-server-entries-with-dynamic-servers. These allow you to change the definition of a backend, including the hostname used for address resolution, without activating a new version of your configuration. BUT this won’t affect any in-flight requests.


#6

Hi, I’ve got the same problem as mpapper, I need to change req.backend.host dynamically from VCL without an API call.

I tried with 127.0.0.1 as the only backend and generating a synth in vcl_deliver followed by a restart, hoping that fastly will take that synth as input, but It doesn’t work as expected. Fastly retain only the req var between restarts.

May someone reply to mpapper question? :roll_eyes: