Fastly platform guide
Fastly Origin Shielding: Safe Configuration, Verification, and Rollout
Origin shielding concentrates cache-miss traffic through a selected Fastly POP. It can reduce duplicate origin fetches, but it changes the request path, cache interpretation, failure modes, and cost model.
On this page
Without shielding, each Fastly POP can independently fetch an object that is absent from its local cache. With shielding, a local edge miss goes to a designated shield POP first. If the shield has the object, it answers the edge POP without an origin request; only a shield miss reaches the origin. This creates a second shared cache layer and concentrates origin-bound traffic through one POP.
Overview
Outcome
Shield Acme Shop's public catalog backend near its origin, prove an edge miss can become a shield hit without an origin request, and retain an unshielded version for rollback.
That topology is useful for cacheable, globally requested content and for controlling origin connection pressure. It is not access control, does not stop direct-origin traffic, and is not a universal latency improvement. An edge hit remains the shortest path. A local miss that travels to a shield adds an internal hop, and a poorly located shield can make the miss path worse. Measure the outcome for your routes and user regions rather than treating the feature as a default.
Fastly origin shielding is a per-backend setting, not a global switch, and that is exactly why it is easy to misconfigure at scale: one origin gets a well-placed shield, the next is left on a default, and nobody notices until an incident review asks why origin load doubled after a traffic shift. In a managed multi-provider edge, this is the kind of operational detail Optimi tracks deliberately rather than leaving to a one-time setup task — each backend's shield assignment, cache-miss verification evidence, and origin-load trend are worth watching continuously, not just at rollout.
Shielding is an origin-load and cache-topology control
Keep origin firewalling, authentication, rate limits, health checks, and capacity planning in place. Shielding can reduce duplicate requests to an origin; it does not authorize clients or make an unavailable origin healthy. Because the shield assignment lives on the backend object rather than the route, it also drifts quietly across services if nobody is watching for it — which is why Optimi's MYO observability correlates shield assignment, cache-hit ratio, and origin load per backend across every provider in a stack, rather than leaving each service's dashboard to tell a separate story.
Prerequisites and scope
Before changing the service, have an active Fastly service with a known-good version, a documented backend inventory, permission to clone and activate versions, access to origin and Fastly logs, and a representative test domain. Identify each backend's physical or cloud region, DNS name, TLS certificate name, expected Host header, cache policy, health-check path, and capacity limit.
Choose an initial scope of one cacheable, read-heavy backend and a small set of paths. Exclude authenticated pages, writes, payment or inventory flows, and intentionally uncached PASS traffic from the first experiment. Those requests can still transit a shield when forwarded to a backend, but they do not receive the same shared-cache benefit and can increase internal traffic.
Record a baseline for at least one normal traffic cycle: origin request rate and egress, origin connection count and p95 latency, Fastly cache status distribution, edge and origin errors, client p95/p99 latency by region, and delivery bandwidth. Define a rollback threshold before editing configuration.
Acme Shop scenario
Acme Shop's catalog origin is in a single European cloud region. Start with its public GET /products/demo-mug.webp backend only. A visitor in another region can be served by the local edge cache, an edge miss can ask the shield near the origin, and only a shield miss reaches Acme Shop's origin. Sessions, checkout, and private APIs remain out of scope.
- Visitor region edge
Serves a local HIT or forwards an eligible miss.
- Shield near origin
Serves a shared shield HIT or makes one origin fetch.
- Acme Shop origin
Receives only shield misses and permitted pass traffic.
A local edge HIT avoids both shield and origin; an edge MISS can be answered by the shield before the origin is contacted.
1. Select an origin shield POP near each origin
Use the Fastly POP API or Fastly control panel to obtain valid shield identifiers. The human POP name and the shield identifier are not necessarily the same. For example, Fastly's shielding documentation distinguishes Amsterdam's POP name (AMS) from its amsterdam-nl shield identifier.
Select the origin shield POP primarily by proximity and network quality to the backend, not by the average location of visitors. A shield near the origin can reduce the expensive origin leg and make a shared cache more effective. Then test the complete path from important user regions. A globally distributed audience with a single origin often benefits from one shield near that origin; geographically separate origins should normally have independently chosen shields.
Two further inputs belong in the decision, beyond raw geography:
- Private network interconnect (PNI). Where a shield POP has a private interconnect to the cloud provider hosting the origin, traffic between them can stay off the public internet. Fastly documents PNI availability per POP; if Acme Shop's origin sits on a provider with a PNI at a nearby shield, prefer that shield over an equally close POP without one. AWS origins do not currently gain a PNI-specific benefit the way Azure and GCP origins can, so factor the actual provider in, not just the map distance.
- Shield POP capacity tier. Fastly rates POPs by cache capacity (small through large). A shield handling a high-traffic, globally reused catalog benefits from a higher-capacity POP; a narrowly scoped or low-traffic backend has more latitude. Check the current POP list before committing a high-volume backend to a small shield.
Use this decision table before selecting a location:
| Question | Evidence to collect | Decision impact |
|---|---|---|
| Where does this backend actually serve from? | Cloud region, anycast behavior, origin logs, network traces | Choose a shield close to the backend, not a corporate office. |
| Is the response cacheable and reused across regions? | Cache headers, cache key, request distribution, object popularity | High cross-region reuse favors a shield; private or unique responses do not. |
| Is the backend regional or route-selected? | Backend map, failover design, health checks | Assign and test a shield per backend, not one blanket setting. |
| Does a candidate shield have a PNI to the origin's provider? | Fastly's current PNI/POP reference, provider region map | Prefer the interconnected shield when candidates are otherwise close. |
| Can the candidate shield's capacity tier absorb this backend's peak? | POP capacity rating, expected shield-layer request volume | Move high-volume backends off small-capacity POPs. |
| What happens if the shield cannot be reached? | Failure test and origin capacity plan | The request can bypass the shield and reach the origin directly. |
| Are user regions latency sensitive on a miss? | RUM and synthetic p95/p99 by region | Reject a shield choice that harms critical miss-path latency. |
Fastly documentation recommends selecting a data center close to the backend and notes that each backend can have its own shield. Do not select a shield based solely on a map. Test DNS resolution, TLS handshake, first byte, and sustained origin throughput through the intended path. Note also that shielding can only be assigned to backends managed through the web interface, API, or CLI — a backend declared entirely inside custom VCL cannot carry a shield property, so if Acme Shop later moves a backend into VCL-defined territory, shielding has to be reconsidered for that backend specifically.
2. Clone the active version and assign the shield
Make this change in a new service version. In the Fastly control panel, select the service, choose Edit configuration, and clone the active version. Open Origins, choose the backend, and select the shield location in the Shielding menu. Save the backend change. Repeat for every backend in scope, using the selected location for that backend rather than copying one location blindly.
For API or CLI-managed configuration, set the backend object's shield property to the shield identifier. Update the existing backend in the explicitly recorded, editable candidate version. Do not use latest, active, or --autoclone in a production change command because those make the target version implicit.
fastly service backend update \
--service-id="$FASTLY_SERVICE_ID" \
--version="$FASTLY_CANDIDATE_VERSION" \
--name="app_origin" \
--shield="amsterdam-nl"
Set FASTLY_CANDIDATE_VERSION only after cloning and recording the new draft version. This update changes only the shield property; it preserves the backend address, TLS, timeout, health-check, host override, and connection settings already reviewed in the clone. Use fastly service backend create only when intentionally adding a new backend and specify the same explicit candidate version plus every required backend setting.
If you change the request Host header before it reaches the shield, add the modified hostname to the service's domain list. Fastly uses the incoming host to identify the service at the shield; an unknown altered host can produce a 500. Prefer the backend override_host setting for the final origin hop instead of changing Host early in custom logic.
Validate the cloned version and review the diff. Confirm that the selected backend still has the expected address, TLS certificate validation, SNI, health check, timeout budget, conditions, logging endpoints, and cache policy. Keep the active version untouched and immediately activatable as rollback.
3. Understand the Fastly origin shielding cache-miss path
Fastly origin shielding does not change how an edge hit is served; it only changes what happens after an edge miss. For an object with a correct shared cache key, the request paths are:
Measure edge, shield, and origin outcomes separately: a shield hit avoids an origin fetch even though the local edge recorded a miss.
- Edge HIT: the edge POP returns its cached object. Shielding and the origin are not involved.
- Edge MISS, shield HIT: the edge POP forwards to the shield. The shield returns its cached object, which can populate the edge POP. The origin receives no request.
- Edge MISS, shield MISS: the edge POP forwards to the shield, and the shield fetches from the origin. The response can be cached at both layers according to the cache policy.
- PASS or uncacheable backend request: the request still uses the shield path when it is forwarded to the backend, but it does not gain a reusable cache hit. Evaluate this traffic separately.
This is why shielding can reduce origin load without increasing every visitor's edge cache hit. It also explains why Fastly's global cache-hit ratio may appear lower than expected: an edge miss and shield hit count as both a miss and a hit, while an origin fetch through the shield can register two misses. Use raw request, hit, miss, shield, and origin metrics rather than one aggregate ratio as the sole success criterion.
Worked through Acme Shop's numbers: without shielding, every edge POP that independently expires its copy of demo-mug.webp within the same TTL window opens a fresh connection and issues its own origin fetch — a dozen simultaneous regional misses can mean a dozen origin fetches. With the shield assigned, only the first of those misses to reach the shield triggers an origin fetch; the remainder become shield hits and never reach Acme Shop's origin at all. This is the concrete effect to look for in the baseline-versus-rollout comparison, not just a smaller miss percentage.
Even PASS and other uncacheable requests are not entirely unaffected: they still traverse the shield hop, and because Fastly POPs keep warm connection pools open to one another, that inter-POP leg typically has lower connection-setup latency than a fresh connection from the edge straight to the origin would. Do not use this as a reason to route uncacheable traffic through a shield on purpose — it is a side effect, not a design goal, and it does not offset the extra hop for latency-sensitive uncached requests.
Ensure the cache key does not mix users, entitlements, locale variants, or security-sensitive headers. Do not use the shield to paper over an unsafe Vary policy. If you change cache directives, prefer explicit Surrogate-Control for Fastly-facing freshness and Cache-Control for browser-facing freshness when those requirements differ.
4. Cache-miss verification on a non-production domain
Activate the cloned configuration first on a development or staging service, or use a representative isolated domain and origin. Warm a set of known public objects with repeated requests, then issue requests from more than one external region. Keep test objects separate from customer-specific content and use a short, documented TTL so the test is easy to invalidate.
Use curl -I or your HTTP test runner to capture headers and preserve output with the timestamp, test region, URL, response status, Age, cache-related headers, request ID, and deployment version. X-Cache and X-Served-By are Fastly's standard cache-status headers — X-Cache reports a comma-separated HIT/MISS sequence such as MISS, HIT for an edge-miss/shield-hit path, and X-Served-By names the cache nodes that were queried. For deeper cache-miss verification, sending Fastly-Debug: 1 on a request (never expose this to real users) surfaces Fastly-Debug-TTL and Fastly-Debug-Path, which report per-node hit/miss state, remaining TTL, grace, and the sequence of cache nodes the request traversed. Treat exact header presentation as configuration-dependent and diagnostic, not as a stable application contract, but rely on these named headers rather than inferring cache state indirectly.
At the origin, log a safe correlation ID plus the path template, status, latency, request source, and selected upstream identity. Run this sequence:
- Request a cold, public object from region A and confirm one expected origin fetch.
- Request the same object from region B after region A has populated the shield; confirm the expected response and look for a shield cache service rather than another origin fetch.
- Repeat after the TTL expires and during a controlled purge to observe miss coalescing behavior and origin capacity.
- Test an uncacheable route and a private route to ensure neither becomes shared-cache content.
- Temporarily make the staging origin slow or unhealthy and confirm the configured timeout, user-visible error behavior, alert, and rollback decision.
- If any custom VCL or Compute logic mutates the response, request the same object once through the shield-populating path and once already warm at the edge, and diff the bodies. A response modified during the shield-execution pass is cached and re-served to every edge POP that later hits it; a mismatch here is a cache-poisoning signal, not a one-off rendering bug.
Local Compute testing can simulate shielding sites through the [local_server.shielding_sites] table in fastly.toml — mapping a shield identifier to "Local" or to a remote shield URL — but the local server has no readthrough cache, so it cannot prove Fastly's global routing, real cache topology, or inter-POP latency. Use it for logic tests; use a live isolated service for path and cache-miss verification.
5. Observe headers, logs, and origin load
Add a dashboard that compares the baseline and rollout period by route, backend, and user region:
- edge hits, edge misses, shield hits, shield misses, and origin request rate
- Fastly and origin
4xx/5xxresponses, backend timeouts, and health-check state - client and backend p50/p95/p99 latency, split by hit and miss where possible
- origin connections, CPU, queueing, egress, and upstream rate-limit events
- Fastly request and bandwidth usage, including inter-POP traffic implications
Correlate Fastly logs and origin logs with a request or trace ID. Capture cache outcome, POP or region where permitted, backend name, version, origin duration, and a safe failure reason. Do not log cookies, authorization headers, signed query strings, or private response bodies.
Verify the expected behavior with evidence, not only a dashboard average. A successful trial shows fewer duplicate origin requests for the same cacheable object, stable or improved origin saturation, no unexpected cache leakage, and acceptable user-region latency. A shield hit avoids an origin fetch but may still be slower than a local edge hit; compare each path separately.
Validation
Paired cache-path validation
Use approved diagnostic access only. Read X-Cache together with X-Served-By, Age, Fastly debug data where authorized, and the Acme Shop origin request count; no one header proves the path alone.
Age: 42
X-Cache: HIT
Origin requests for /products/demo-mug.webp: 0
Age: 42
X-Cache: MISS, HIT
X-Served-By: cache-shield, cache-edge
Origin requests for /products/demo-mug.webp: 0
- Positive: after warming from region A, a request from region B has the expected body and demonstrates an edge-miss/shield-hit path with no new origin request.
- Negative: a private route retains its private/pass behavior and does not acquire a shared-cache response.
- Failure: any user-visible error, body mismatch, unexpected origin fetch for the warmed object, or miss-path latency beyond the agreed threshold stops rollout and requires the prior unshielded version.
6. Roll out gradually and roll back quickly
Activate shielding for one backend or route group first. Observe it through a complete peak period, cache expiration cycle, and a routine origin deployment if possible. Expand only when the origin-load reduction and user latency results meet the agreed thresholds. If a configuration-management system supports environments, promote the reviewed version through them; do not make unexplained manual production edits between stages.
Rollback
Rollback is simple only if prepared:
- Keep the current active version number and prior known-good version in the change record.
- If errors, latency, cache safety, or origin behavior exceed a stop condition, activate the earlier version without the shield assignment.
- Verify active-version state, synthetic requests, origin traffic, and cache-related logs after propagation.
- Preserve the failed version, logs, request samples with sensitive values removed, and metrics for root-cause analysis.
Do not try to solve an origin incident by enabling shielding blindly. If the origin is overloaded, shielding may reduce duplicate cache misses, but it cannot satisfy uncacheable workload or restore an unhealthy dependency. First apply the service's overload, failover, and stale-content policy where those are safe.
Troubleshooting
| Symptom | Likely cause | Check | Safe correction |
|---|---|---|---|
500 appears only after shielding | A modified Host is not recognized at the shield | Compare request-host mutations and service domains | Restore the known-good version; use backend override_host or mutate only on the origin hop. |
| Two regions both fetch the origin | Object is not cacheable or cache key differs | Compare Cache-Control, key inputs, and origin correlation IDs | Fix the public response contract before expanding shielding. |
| Origin load does not fall | Traffic is mostly PASS, private, or uniquely keyed | Split edge/shield/origin metrics by route | Remove the route from the shield experiment or redesign its cache policy. |
| Miss latency regresses | Shield is poorly placed or origin is unhealthy | Compare regional p95/p99 and backend timing to baseline | Reactivate the unshielded version and reassess shield placement. |
| Different regions see different cached bodies for the same URL | Response was mutated during the shield-execution pass and cached network-wide | Check whether custom VCL/Compute logic branches on req.backend.is_origin / shield.runningOn() before mutating the response | Gate origin-bound mutations to the origin-facing pass only; apply client-facing changes at the edge-connected POP. |
| Shield assignment silently stops applying after a VCL change | A custom vcl_recv/vcl_miss backend-selection override bypassed the generated shielding logic | Review whether req.backend is set directly instead of through fastly.try_select_shield() or condition-based selection | Route custom backend selection through fastly.try_select_shield() (VCL) or per-backend shield.runningOn() checks (Compute) instead of a direct assignment. |
| Backends behind automatic load balancing shield inconsistently | Auto load balancing requires every backend in the director to share one shield location | Compare shield identifiers across all backends in the load-balancing director | Align all balanced backends on one shield, or move to sticky balancing plus custom VCL if per-backend shields are required. |
Redundancy, security, and configuration caveats
Shielding has important operational tradeoffs:
-
Shield reachability: if a configured shield POP is inaccessible for a request, Fastly can send that request directly from the edge POP to the origin. Origin controls and capacity must tolerate this bypass path. In custom VCL or Compute code, always fail open toward the origin rather than raising an error when shield selection fails — a missing or unhealthy shield should degrade to a direct origin fetch, not a
500. -
Origin security: shielding is not an allowlist or firewall. Keep direct-origin access restricted with private networking or Fastly-source controls plus edge-to-origin authentication. Test the direct-origin path independently.
-
Multiple origins and load balancing: configure and assess shielding per backend. Fastly's automatic load balancing requires every backend in the same load-balancing director to share one shield location; it does not support per-backend shields inside one balanced group. If Acme Shop needs different shields per backend within custom logic, use conditions-based backend selection or the
fastly.try_select_shield(shield, fallback)VCL function, which selects a shield director only if it is healthy and has not already been visited on this request, falling back to the supplied backend otherwise:sub vcl_miss { set req.backend = fastly.try_select_shield(ssl_shield_amsterdam_nl, req.backend); }Assigning
req.backenddirectly, without going through this function or the generated conditions, silently disables shielding for that path — this is a common cause of a backend that appears configured with a shield but never shows shield-layer hits. -
Host handling: Fastly identifies the service using the host on the internal request. Preserve a service-recognized host until the final origin hop or use
override_hoston the backend. -
Custom VCL and Compute execution context: VCL executes once at the edge and again at the shield when shielding is active; use
req.backend.is_shield(true only at the shield) andreq.backend.is_origin(true only on the final origin-bound hop) to branch logic correctly — both depend on a backend already being assigned, so check them invcl_miss/vcl_pass, notvcl_recv. Compute shielding is explicit in the SDK:shield.runningOn()reports whether the current execution is at the shield, andshield.encryptedBackend()provides the encrypted tunnel to it. In both platforms, gate any origin-bound mutation (rewritingHost, adding upstream-only headers) behind the origin-facing check, and gate client-facing response changes behind the edge-connected check — a mutation applied during the shield pass is what gets cached and replayed to every edge POP that later hits the object, which is a cache-poisoning risk, not just a logic bug. VCL-defined backends (declared entirely in custom VCL rather than through the API, CLI, or control panel) cannot carry ashieldproperty at all, and Fastly Fiddle does not support the shielding APIs, so prototype shield-aware logic against a real service. -
Client address: at the shield, the immediate client is another Fastly POP, so
client.ipand equivalent Compute properties reflect the edge POP, not the visitor. ReadFastly-Client-IPfor the true client IP, and in VCL resetclient.identityfrom it (set client.identity = req.http.Fastly-Client-IP;) if identity-based logic such as sticky load balancing depends on the real visitor. Use this only after defining the proxy trust boundary; do not treat an arbitrary forwarded header as authenticated identity. -
Cost and capacity: inter-POP traffic contributes requests and bandwidth — the edge-to-shield leg and the shield-to-origin leg are each metered. A backend with a high PASS or uncacheable share can add close to another full leg of Fastly-billed traffic without any cache benefit. Measure the added Fastly traffic against origin egress and capacity savings, and treat a high-PASS route as a signal to fix cacheability rather than to leave shielded indefinitely.
Operational checklist
Before production activation, confirm each backend has a justified shield identifier; domains and host override work across the internal hop; TLS and health checks are intact; cache keys isolate private content; the origin can tolerate shield bypass; headers and logs prove the expected cache-miss path; dashboards separate edge, shield, and origin outcomes; and an unshielded known-good version is ready to activate.
Fastly primary references
- Shielding configuration guide
- Shielding concepts, effects, and advanced scenarios
- Backend API reference
- Fastly service version API reference
fastly.tomllocal-server reference- Testing and debugging on the Compute platform
fastly.try_select_shield()VCL function reference
Related guides
Related reading
- Shielding concepts, effects, and advanced scenarios
- Shielding configuration guide
- Checking cache
- Developer guide: backends
Get the origin shield POP placement right the first time
Optimi's Performance, Security, and Visibility approach helps you choose and verify the right origin shield POP per backend, keep origin protections intact through the shield hop, and track cache-miss verification evidence in MYO across every provider you run — not just this one Fastly service.
Discuss origin shielding with Optimi