Skip to main content

CDN

Serving your site from the edge, and how to clear the cache from your own code.

A CDN puts copies of your site in datacentres near your visitors, so a page loads from the same continent rather than from the machine it is built on. The platform runs it for you: you buy an amount, and the pull zone, your domains and their certificates are all set up for you.

Buying it

In the configurator when you set a project up, or afterwards under Commercial terms on the project's configuration page, under Edge. It is bought by the terabyte a month, minimum one.

It is a commitment, not a meter. You pay for what you bought whether or not you use it, which is what lets us sell it without metering every byte. The CDN tab shows what you have actually served this month, so you can tell whether the number is the right one before the next invoice rather than after it.

Raising the amount takes effect at once, charged for the rest of the period. Lowering it, or setting it to zero to give it up, is recorded and takes over at your next invoice — you keep what you bought until the period it was bought for ends, and it is not credited. Once zero applies the pull zone is removed, and your domains stop being served from the edge the moment DNS catches up. See Billing.

Pointing a domain at it

The CDN is for your own domains. An environment's …vallic.cloud hostname is deliberately never put behind it — it stays a direct route to the machine, which is what gives you a way in that does not depend on the cache, and what lets the pull zone read from it without reading from itself.

So the order is:

  1. Add your domain under Routing and prove you control it.
  2. Point it at the address the CDN tab shows. Copy it from there rather than guessing at its shape — it is the one value in this that is not yours.
  3. Wait. A certificate is issued once the name resolves to the edge, which cannot happen before you publish that record.

The console does the rest: attaching the hostname to the pull zone, asking for the certificate, and telling you when it is ready. Until the certificate arrives the name will not serve over HTTPS — that is the CDN waiting for your DNS, not something to fix here.

An apex domain cannot hold a CNAME. If your DNS provider offers ALIAS or ANAME, point that at the same name; if it does not, use a subdomain such as www. Either way, remove the records it had before: an old A or AAAA left beside the new one sends some visitors past the CDN to your old address, and the certificate cannot be issued while the CDN's own check lands there.

Clearing the cache from your code

A cache is only useful if you can drop it when you publish. Your application can, without any credential:

VALLIC_CDN_PURGE_SOCKET=/run/vallic-cdn/purge.sock
VALLIC_CDN_PURGE_URL=http://localhost/purge
VALLIC_CDN_PURGE_TOKEN=…

They arrive in the environment like every other variable, and are there only when the CDN is on. Send the request through the socket; the URL supplies only the path.

Drupal

Install Vallic Purge. It plugs into the Purge module, reads both variables itself, and clears exactly the pages a change affects the moment it is saved. There is nothing to configure:

composer require drupal/vallic_purge
drush en vallic_purge purge_queuer_coretags purge_processor_lateruntime purge_processor_cron
drush p:purger-add --if-not-exists vallic

Export your configuration afterwards, so every environment gets the same purger on its next deploy.

Then set Browser and proxy cache maximum age under Configuration → Development → Performance. Until Drupal says a page may be cached, the CDN keeps no copy of it, so there is nothing to clear. Pages for signed-in visitors are sent as private and are never cached, whatever this is set to.

Keep the module enabled everywhere. On your laptop, in CI, or on an environment without the CDN, it sends nothing and adds nothing to your responses. The status report shows which of those it is.

Anything else

Send a POST to that address with the token as a bearer:

{"scope": "all"}
{"scope": "url", "values": ["https://www.example.com/news"]}
{"scope": "tag", "values": ["* node:42 *"]}
  • all empties the whole cache. The blunt instrument, and the one to reach for after a deploy that changed templates.
  • url drops individual addresses. Only hostnames this environment answers on are accepted; anything else is ignored rather than failing the batch, so one mistyped address does not stop the rest.
  • tag drops every response whose tags match. The precise one, and the one worth wiring into a CMS that already knows which pages a change affects.

You never name the pull zone. The request is answered on your own machine, and which environment is asking is decided by the token — which is why the token should be treated like any other secret in the environment, and why a CDN credential never appears in your container.

Tagging a response

A response is tagged by a CDN-Tag header. The CDN keeps that header as one string, not a list, and matches each purge value against the whole string, with * standing for anything. So a page sent with

CDN-Tag: : node:42 node_list :

is cleared by * node:42 *, but not by node:42, which only matches a header that is exactly node:42. Write the tags separated by spaces, with a character at each end as above so the first and last tags have a space on both sides too, and purge with * tag *.

Keep the header short. A busy page can carry hundreds of tags, and headers that run to many kilobytes can be refused on the way out, which fails the page instead of caching it. Shorten long tags to a hash of a few characters and purge by the same hash. The Drupal module writes each tag as eight.

After a deploy

A deploy does not clear the CDN. Pages your site clears by tag stay fresh as content changes, but a release that changes templates, stylesheets or scripts leaves the old pages at the edge until they expire. To start a release from an empty cache, clear it in the last deploy step.

For Drupal with Vallic Purge:

deploy:
  steps:
    - 'drush deploy'
    - 'drush cache:rebuild-external -y'

cache:rebuild-external goes through Purge's Drush processor, which has to be added once, like the purger: run drush p:processor-add drush_purge_invalidate and export your configuration. Without it the step fails, and with on_failure: rollback so does the release.

For anything else:

deploy:
  steps:
    - '[ -z "$VALLIC_CDN_PURGE_URL" ] || curl -fsS --unix-socket "$VALLIC_CDN_PURGE_SOCKET" -X POST "$VALLIC_CDN_PURGE_URL" -H "Authorization: Bearer $VALLIC_CDN_PURGE_TOKEN" -d "{\"scope\":\"all\"}"'

The test at the front skips the call where the CDN is off, so the same manifest deploys staging too.

Emptying the cache means every page misses at once, so your machine is at its busiest in the minutes after a release. A site that already clears by tag often needs this only when the look of the site changed. You can also do it by hand: Clear the CDN cache on the environment's CDN tab, for anybody who can deploy.

Who is really asking

Behind a CDN every request reaches your application from the CDN, not from your visitor — so the address your framework reports is one of a few hundred edge servers. Two headers carry the truth instead, on every request:

X-Vallic-Ip: 203.0.113.9
X-Vallic-Country: DE

Read X-Vallic-Ip wherever you would have read the client address: rate limiting, fraud checks, anything that logs who did what. X-Vallic-Country is the visitor's country as a two-letter code, for a price list or a language default. Only trust them on requests that came through the CDN — somebody reaching your platform hostname directly can send any header they like.

What is cached, and what never is

A page your application marks private, no-cache or no-store is never cached, whatever else is configured. That is how a signed-in page stays somebody's own: every framework already sends one of those on a response that belongs to a person.

A request from a signed-in visitor is answered by your site, never from the CDN, and reaches their browser as private, no-cache — so an editor never sees the copy of a page that was cached for everybody else. Signed-in means the request carries your application's session cookie, under its framework's default name:

Application Session cookies
Drupal SESS…, SSESS…
WordPress wordpress_logged_in_…, wp-postpass_…
Laravel laravel_session
PHP (Symfony and others) PHPSESSID
Node.js connect.sid (Express)
Go none — name yours under Session cookies

A session under another name goes under Session cookies on the CDN tab, below.

Beyond that, these settings on the environment's CDN tab are yours:

  • Dynamic cache lets the CDN decide what is cacheable from your own response headers rather than by file type. For a site that will not be purging by URL or cache tag. Leave it off if you have tuned your cache headers yourself.
  • Browser cache time for pages and for static files, with Dynamic cache off: how long visitors' browsers keep a page — 5, 15 or 60 minutes, or a day — and your stylesheets, scripts, images and fonts — 1, 7 or 30 days — before asking again. Told apart by the Content-Type your site sends. Left at As your site says, your own Cache-Control decides, and a long one means a browser goes on showing an old copy after you purge the CDN. Keep the page time short on a site people sign in to: a page somebody saw signed out stays in their browser, signed out, for that long after they sign in. Signed-in visitors are always told private, no-cache, and anything your site marks private, no-cache or no-store keeps that. These change only what browsers are told; the CDN still keeps a response as long as your site says, so your site is not asked more often. A time is set rather than capped — a response you mark for one minute is kept for the chosen time too.
  • Vary the cache by WebP or AVIF support, mobile against desktop, country, region, hostname or cookie. Each one keeps a separate copy of every page per value, and two of them multiply — so tick only what your site genuinely serves differently. Cookie takes the names of the cookies that matter — a language or currency choice — and only those make a copy; every other cookie is ignored. A session cookie cannot be one of them, since that would be a copy per visitor — signed-in visitors skip the cache instead.
  • Request headers to vary by, one name per line — Accept-Language, say — for a site that answers differently by a header. Cookie and User-Agent cannot be used: both would be close to a copy per visitor.
  • Blocked countries are refused at the edge and never reach your site.
  • Session cookies, one name per line — or the start of one, for a cookie with a varying suffix — for a session your application names differently from its framework's default. A visitor carrying one is answered by your site, never from the CDN, and told private, no-cache. Up to five; names only, so letters, digits, dots, dashes and underscores.
  • Never cache these paths — /admin/*, /cart — for anything that should always come from your application even though it does not say so itself. Browsers are told the same: these paths reach them as private, no-cache, whatever your site sent. Up to twenty.

They are read from the CDN and written straight back to it. Nothing is kept separately, so the page always shows what the edge is actually doing.

Some things are decided for every site and are not switches: the query string is always part of the cache key, so ?page=2 is never served the first page; a stale copy is served while your site is slow or down rather than an error; an error response is never stored, so the edge stops serving it the moment your site answers again; and redirects are passed to the browser rather than followed at the edge — so your canonical URLs stay enforced.

How it is bought

By the terabyte a month, committed rather than metered — you pay for what you bought whether or not you use it, and nothing here counts bytes. A CDN bought by the hundred gigabytes before it was sold by the terabyte keeps its amount and its price until you change it; a new amount is rounded up to whole terabytes.

On one of two networks. The Volume network is the one selected to begin with: it reaches 10 locations across Europe, Asia and North and South America, costs a fraction as much, and is enough for most sites. The Standard network reaches 119 locations worldwide, and is worth its price when your visitors are spread out; anybody far from a Volume location gets a slower first byte. You can move between them later; the pull zone stays and no hostname is lost. Moving to the Standard network happens at once; moving to the Volume network is a reduction, so like any other it takes over at your next invoice.

A project that was already behind the CDN before there was a choice is on the standard network and stays there until you change it.

The Volume network is one price everywhere. The Standard network is priced by the datacentre you chose, because that is what decides where the bytes come out: Europe and North America is the cheapest, then Asia and Oceania, then South America, then the Middle East and Africa. Change the datacentre in the configurator and the figure moves with it.

The figure itself is quoted where it is agreed, not here: the configurator and the Commercial terms dialog both show what will actually be invoiced.

Next

  • Domains — adding a domain and proving it
  • Variables — where the purge settings arrive