Shielding
When Fastly makes requests to your origin servers, those requests may come from any of our POPs, which act independently. However, if you wish, you may designate one POP location as a 'shield', collecting requests from across the Fastly network. In this arrangement, requests to your origin server will come only from the designated shield POP, and all other Fastly locations will forward requests to the shield.
Shielding has significant benefits:
- Reduces origin load: reduces the volume of requests from Fastly to your origin servers
- Improves cache hit ratio (CHR): increases the probability of end user requests resulting in a cache
HIT
(albeit potentially not from the first POP which handles the request) - Speeds up connections: reduces connection setup latency for
MISS
andPASS
requests that must be served from origin.
The latter of these is somewhat counter-intuitive, but takes advantage of the fact that all Fastly POPs always have a pool of open connections to all other Fastly POPs, over highly optimized routes. Minimizing the amount of physical distance to cover outside of the Fastly network reduces the time required for costly multi-roundtrip handshakes.
Enabling and disabling shielding
Shielding may be enabled when adding or editing an origin server, and may be selected per-origin. If your origin servers are in different locations, it may make sense to choose different shields for each origin server. You can enable shielding via the web interface, or set the shield
property of a Backend
object when you create or modify it using the API or CLI. For example:
$ fastly backend create --name=app_server --address=192.168.123.123 --shield=amsterdam-nl --service-id=9yqrXWr5kfqroswtmxgQDz --version=latestSUCCESS: Created backend app_server (service 9yqrXWr5kfqroswtmxgQDz version 1)
Each POP has a shield identifier. These are listed in the properties returned from the /pops
API endpoint. For example, our POP in Amsterdam has the name AMS
but a shield identifier of amsterdam-nl
. If you are using a cloud provider, see choosing a shield location.
Effects of shielding
Enabling shielding on a Fastly service will create side effects that should be considered carefully.
Double execution
Services using shielding will (in most cases) execute twice: once at the edge location and once at the shield location. However, if a request is received directly at the shield location, then it will send requests directly to your origin, so the configuration will only execute once.
In VCL, the fastly.ff.visits_this_service
variable is the best mechanism available to detect whether the POP processing a request is acting as an edge or a shield. Additionally, you can use the following variables to determine whether the currently assigned backend is a customer origin or a Fastly shield POP:
So, for example, if req.backend.is_origin
is true, then if Fastly makes a backend request, it will go to your origin server. This doesn't necessarily mean that the request has already passed through an edge POP, since the end user may have made their request directly to the POP designated as the shield location.
Be aware that changes made to a response at a shield POP will be viewed by an edge POP as if they are part of the response from the origin. Therefore any changes you want to make to a response just before serving it to the browser should be done only on the edge.
In general, operations performed on the request should generally be done at the edge, and operations performed on the response should happen at the shield. Here is a list of some of the most common operations performed in Fastly services and an indication of where these should normally be done in a shielded configuration:
Best done at the edge | Best done at the shield |
---|---|
Manipulating the request URL Normalizing the request Authentication Security filtering (eg WAF or bot detection) Redirects Geolocation A/B testing ESI | Compressing responses Setting backend-specific headers |
HINT: Rather than detecting the execution location, consider writing your code in a way that is idempotent, that is, it only has effect once, and if you run it again, nothing happens.
For example, static object store origins like S3 or GCS may require a path prefix to be added to the URL. Doing this unconditionally may result in the prefix being added twice, e.g. /bucket-name/bucket-name/path/to/file
. While you could use a variable such as fastly.ff.visits_this_service
to avoid this, a better solution is to detect the presence of the prefix:
if (req.url.path !~ "^/bucket-name/") { set req.url = "/bucket-name/" + req.url;}
Origin definition
For VCL services, it is possible to define backends using VCL code as well as creating a configuration object via the web interface, API or CLI. However, shielding is deployed by generating a large director in your configuration, and generating logic in vcl_recv
that will select that director if the POP is not the one identified as the shield. While you could write the vcl_recv
logic yourself, you cannot generate the director definition because servers are regularly added and removed from the Fastly network, and when this happens, your shield director will be regenerated. Therefore you cannot apply shielding to origins that you define in VCL.
Host header manipulation
Fastly uses the HTTP Host
header on inbound requests to select the correct service to handle the request. If the Host
header doesn't match to a known customer domain a 500 Internal Server Error
is served to the end user.
If you change the value of req.http.host
as part of your configuration and it executes at the edge POP, then be aware that it may be used for service selection at the shield POP. Either manipulate the Host
header only at the shield POP (see fastly.ff.visits_this_service
) or when a fetch is going to your origin (see req.backend.is_origin
), or use the override_host
property when creating the backend. The latter option is often the most conceptually straightforward and least prone to error.
Client IP
Requests made from an edge POP to a shield will report the edge POP as the client.ip
. To reliably access the true client IP, use the Fastly-provided Fastly-Client-IP
header. The client.identity
variable is also influenced by the apparent client IP, so if making use of client directors, client.identity
should be reset to Fastly-Client-IP
or to an identifier specific to your service.
Limitations and constraints
Please be aware of the following when using shielding on your service:
Cache hit ratio (CHR) inaccuracy
If a request results in a MISS at an edge location and is forwarded to a shield where it finds a HIT, the user is ultimately served from cache, but we will record both the miss and the hit for the purpose of calculating your cache hit ratio. While 'shield hits' will involve more latency for end users than 'edge hits', the hit will still mean there is no need for an origin request. Equally, a request that does reach your origin server will be counted as two misses, one at the edge, and one at the shield.
This will result in a cache hit ratio that may be lower than you expect. Since there are multiple ways of calculating CHR on shielded configurations, you may like to use our historical stats API to get raw numbers and perform your own calculations.
Backend selection
The process of assigning a backend to a request normally happens in the vcl_recv
stage of the VCL request lifecycle. For shielded backends, Fastly will insert logic into the #FASTLY recv
macro that detects where the backend is set to the shielded backend, and change it to the shield if the current POP is not the designated shield location for that backend.
As a result, if you are using custom VCL and you set the value of req.backend
after the #FASTLY recv
macro, you will override shielding. Instead, consider performing your backend selection before #FASTLY recv
. If you have to do backend selection after the Fastly recv macro has run, you will need to also implement the logic to assign the shield backend where appropriate.
If you use VCL but only via VCL snippets, these are rendered as part of the #FASTLY recv
macro and placed before shielding logic, so this is a safe place to perform backend allocation without affecting shielding.
Billing implications
Traffic from one Fastly POP to another will count towards your request count and billable bandwidth. If your service is configured to PASS all traffic, then your request count and delivery bandwidth will almost double, since most requests will be presented to two Fastly POPs, but in more realistic scenarios, shielding will often reduce costs overall. See our guide in documentation for more information.
Examples
Prevent caching in the browser (but not at the edge!):
if (fastly.ff.visits_this_service == 0) { set resp.http.Cache-Control = "no-store, private";}
Reset client.identity
to Fastly-Client-IP
when using client directors
set client.identity = req.http.Fastly-Client-IP;
Set a host header, but only if the backend is the real origin:
if (req.backend.is_origin) { set req.http.host = "example.com";}
Advanced shielding scenarios
Shielding can be used in many different configurations and variations. Some of the most common include:
Multiple origins
In many cases, when a service has multiple origins, they are in the same place and benefit from the same shield location. However, if you have multiple origin locations (for example because you have origins serving different regions), then each origin may benefit from having a distinct shield location.
This is supported without additional VCL. Choose the shield location that is most appropriate for each origin, and configure the shield
property to your chosen shield identifier.
Service pinning
If your service is pinned, then the domain the end user is connected to may not be explicitly attached to your service, because your service will answer any request that resolves to your Fastly-assigned dedicated IP space. This can cause a problem when requests are forwarded from an edge POP to a shield POP, because the shield does not know which service to invoke. In order to resolve this, the service must set the HTTP Host
header to a domain name that is explicitly associated with the service, before forwarding the request to the shield:
For consistency it's a good idea to also reinstate the original Host
header on the shield POP so that both the edge and shield use the same Host
value to look up the object in the cache.
Debugging
Shielding creates more potential outcomes for a request presented to a Fastly edge. It's possible that the request will be answered directly from the edge POP. If the edge POP doesn't have the object, the request might still result in a cache HIT, but from the shield POP. Observing these effects and understanding how they affect your metrics can be a necessary step in debugging services with shielding enabled.
The X-Served-By
, X-Cache-Hits
and X-Cache
response headers, which normally show only one entry without shielding enabled, will include an entry for each Fastly POP that has processed the request, but bear in mind that if a request is a HIT at the edge, the entry representing the shield POP will be from when the cached object was originally cached. First, start by understanding the possible values of X-Cache
:
X‑Cache | Meaning | CHR implications |
---|---|---|
MISS, MISS | The object was not in cache at either the edge or the shield. The requested object was fetched from the backend. This will count as two misses as part of the calculation of your headline CHR. | 2 misses |
HIT, MISS | The object was not in cache at the edge, so was forwarded to the shield, where it was found in cache. This outcome will contribute one 'miss' to your headline CHR although ultimately the request is satisfied from within the Fastly network. | 1 hit, 1 miss |
MISS, HIT | The object was found in cache at the edge. When the object was (previously) fetched from the shield, it was a MISS at the shield. The 'MISS' here is a record of a prior event, not something that happened in this request. | 1 hit |
HIT, HIT | The object was found in cache at the edge. When the object was (previously) fetched from the shield, it was a HIT at the shield. The first 'HIT' here is a record of a prior event, not something that happened in this request. | 1 hit |
HIT | The object was found in cache, and the POP that received the request in this case happens to be the designated shield, so the object was originally loaded directly from the backend. | 1 hit |
MISS | The object was not in cache, and the POP that received the request in this case happens to be the designated shield, so the object was fetched directly from the backend and served to the end user. | 1 miss |
So, where the X-Cache
header contains two entries and the second one is 'HIT', the first entry in each of the three debugging headers relates to when the object was originally fetched from the shield, not the current status of the object at the shield.
Additionally, the X-Cache-Hits
header records the value of the obj.hits
VCL variable, which is local to the individual cache node. To optimise and balance load, Fastly may cache objects on multiple machines in a POP, and particularly hot objects may end up cached on every node in the POP (see clustering to learn more). As a result, where the second token of X-Cache
is 'HIT', the first token of X-Cache-Hits
will refer to the number of hits recorded on the individual cache server at the shield POP at the time that the object was served from the shield to the edge. This can often be confusing.
Example response data
Imagine a request for an object that is not cached by Fastly, on a service with shielding enabled. The response would contain headers that look like this:
X-Cache: MISS, MISSX-Served-By: cache-iad2120-IAD, cache-sjc3120-SJCX-Cache-Hits: 0, 0
In this instance, the X-Cache: MISS, MISS
shows that the request has transited two Fastly POPs and was not in the cache in either of them. X-Served-By
lists the servers acting as the delivery node in each POP, in the order in which they processed the response. In this case, cache-iad2120-IAD
(Dulles, Virginia) was the shield POP (closest to the backend), and therefore saw the response first, and cache-sjc3120-SJC
(San Jose, California) was the edge POP (closest to the end user).
If the same request is made, moments later, by the same user on a still-open connection, it would be expected to be handled by exactly the same edge server:
X-Cache: MISS, HITX-Served-By: cache-iad2120-IAD, cache-sjc3120-SJCX-Cache-Hits: 0, 1
This time, the request was a hit at the edge cache-node (cache-sjc3120-SJC). Because it is a hit at the edge it would not be forwarded to a shield. The MISS listed for cache-iad2120-IAD
reflects the state of that node from the first request, and not its current state. The object is now cached in both POPs. Making a third request on the same connection would result in the same response except that X-Cache-Hits
would now be 0, 2
.
Requesting the object again on a fresh connection will likely result in the request being handled by a different edge cache server:
X-Cache: MISS, HITX-Served-By: cache-iad2120-IAD, cache-sjc3122-SJCX-Cache-Hits: 0, 1
This third request is very similar to the second, but in being handled by a different cache node (cache-sjc3122-SJC
) at the edge POP, X-Cache-Hits
reflects the hit count at the individual server level so still shows only 1 hit on this machine and 0 at the shield POP.
Choosing a shield location
You should choose a shield POP that is physically close to your origin servers. There are a few other parameters that can be taken into account too:
- Some Fastly POPs have interconnection points with cloud provider networks. Where a POP has a private network interconnect (PNI), requests from that POP to any host that is within that provider's network will typically flow over the interconnect and not via the public internet. If your origin is hosted with one of these providers, choose a shield location where we have an interconnect, for optimal performance and potential cost savings.
- Fastly POPs vary dramatically in size and current spare capacity. Choose a POP that offers the largest cache storage for a better cache hit ratio at the shield, and therefore reduced origin traffic.
The following POPs are suitable for shielding Fastly services:
HINT: Enter your origin hostname below to show the suitability of each POP to be the shield location for your origin
We will find the Fastly POP with the fastest link to your origin. If there are multiple fast options, we'll prefer those with PNIs.
Location | POP | Shield code | PNIs | Recommended for | |
---|---|---|---|---|---|
Amsterdam | AMS | amsterdam-nl | europe-west1 europe-west4 west-europe | ||
Ashburn (Metro) | IAD | iad-va-us | us-east-1 us-east1 us-east4 east-us | ||
Atlanta | ATL | atl-ga-us | |||
Atlanta - FTY | FTY | fty-ga-us | |||
Auckland | AKL | auckland-akl | |||
Bogota | BOG | bog-bogota-co | |||
Boston | BOS | bos-ma-us | |||
Brisbane | BNE | brisbane-au | |||
Cape Town | CPT | cpt-capetown-za | af-south-1 | ||
Chennai | MAA | maa-chennai-in | |||
Chicago - CHI | CHI | chi-il-us | |||
Chicago - MDW | MDW | mdw-il-us | us-east-2 us-central1 | ||
Chicago - PWK | PWK | pwk-il-us | |||
Copenhagen | CPH | cph-copenhagen-dk | |||
Dallas | DFW | dallas-tx-us | |||
Dallas - DAL | DAL | dal-tx-us | |||
Delhi | DEL | del-delhi-in | asia-south2 | ||
Denver | DEN | den-co-us | |||
Dublin | DUB | dub-dublin-ie | eu-west-1 | ||
Frankfurt | FRA | frankfurt-de | eu-central-1 europe-central2 europe-west3 europe-west6 | ||
Frankfurt - Interxion | HHN | hhn-frankfurt-de | europe-central2 europe-west3 europe-west6 | ||
Fujairah Al Mahta | FJR | fjr-fujairah-uae | |||
Gainesville | GNV | gnv-fl-us | |||
Helsinki | HEL | hel-helsinki-fi | |||
Hong Kong | HKG | hongkong-hk | ap-east-1 cn-north-1 cn-northwest-1 asia-east1 asia-east2 | ||
Houston | IAH | iah-tx-us | |||
Hyderabad | HYD | hyd-hyderabad-in | |||
Johannesburg | JNB | jnb-johannesburg-za | |||
Kolkata | CCU | ccu-kolkata-in | |||
Lisbon | LIS | lis-lisbon-pt | |||
London - LCY | LCY | london_city-uk | europe-west2 | ||
London - LHR | LHR | london-uk | europe-west2 eu-west-2 | ||
London - LON | LON | lon-london-uk | |||
Los Angeles (Metro) | LGB | lgb-ca-us | us-west2 us-west3 us-west4 | ||
Los Angeles - BUR | BUR | bur-ca-us | |||
Madrid | MAD | mad-madrid-es | |||
Manchester | MAN | man-manchester-uk | |||
Marseille | MRS | mrs-marseille-fr | |||
Melbourne | MEL | melbourne-au | |||
Miami | MIA | miami-fl-us | |||
Milan | MXP | mxp-milan-it | me-south-1 eu-south-1 | ||
Minneapolis | MSP | msp-mn-us | |||
Montreal | YUL | yul-montreal-ca | |||
Mumbai | BOM | bom-mumbai-in | ap-south-1 asia-south1 | ||
New York City - LGA | LGA | lga-ny-us | |||
Newark | EWR | ewr-nj-us | |||
Osaka | ITM | osaka-jp | ap-northeast-2 ap-northeast-3 | ||
Oslo | OSL | osl-oslo-no | |||
Palo Alto | PAO | pao-ca-us | us-west-1 west-us | ||
Paris | CDG | cdg-par-fr | eu-west-3 aws | ||
Perth | PER | perth-au | |||
Portland | PDX | pdx-or-us | |||
Rio de Janeiro | GIG | gig-riodejaneiro-br | sa-east-1 | ||
San Jose | SJC | sjc-ca-us | us-west3 us-west4 | ||
Sao Paulo | CGH | cgh-saopaulo-br | southamerica-east1 | ||
Sao Paulo | GRU | gru-br-sa | |||
Seattle | SEA | sea-wa-us | us-west-2 us-west1 | ||
Seoul | ICN | icn-seoul-kr | |||
Singapore | QPG | qpg-singapore-sg | ap-southeast-1 asia-south1 asia-south2 asia-southeast1 asia-southeast2 | ||
Sofia | SOF | sof-sofia-bg | |||
Stockholm | BMA | stockholm-bma | eu-north-1 europe-north1 | ||
Sydney | SYD | sydney-au | ap-southeast-2 australia-southeast1 australia-southeast2 australia-east | ||
Tokyo | TYO | tyo-tokyo-jp | ap-northeast-1 asia-northeast1 asia-northeast2 asia-northeast3 | ||
Tokyo - HND | HND | hnd-tokyo-jp | asia-northeast1 asia-northeast2 asia-northeast3 | ||
Tokyo - NRT | NRT | nrt-tokyo-jp | asia-northeast1 asia-northeast2 asia-northeast3 | ||
Toronto | YYZ | yyz-on-ca | ca-central-1 northamerica-northeast1 northamerica-northeast2 | ||
Vienna | VIE | vie-vienna-at |