Varnish
What is Varnish?
Varnish is an HTTP accelerator that caches responses in memory to serve repeat requests without hitting your app. In Laradock it sits behind Nginx: Nginx listens on 80/443 and forwards to Varnish, and Varnish forwards back to Nginx on port 81 (VARNISH_BACKEND_PORT). The shipped config was developed and tested for WordPress but likely works with other systems too; the approach is based on this Linode guide.
Start Varnish
Varnish's own startup checks the backend's availability, so start Nginx first:
- Laradock CLI
- Docker Compose
./laradock start nginx
docker compose up -d nginx
Then start Varnish itself:
- Laradock CLI
- Docker Compose
./laradock start proxy
docker compose up -d proxy
The service ships as two containers, proxy and proxy2 (both defined in varnish/compose.yml), so it can front two different domains/backends at once. Start the second one the same way if you need it:
- Laradock CLI
- Docker Compose
./laradock start proxy2
docker compose up -d proxy2
Stop Varnish
Varnish's cache lives entirely in memory (malloc storage), so stopping the container discards the cache, there's nothing to back up:
- Laradock CLI
- Docker Compose
./laradock stop proxy proxy2
docker compose stop proxy proxy2
To delete the containers entirely:
- Laradock CLI
- Docker Compose
./laradock remove proxy proxy2
docker compose rm -sf proxy proxy2
Configuration
All settings live in varnish/defaults.env and can be overridden by adding the same line to your own .env:
| Variable | Default | What it does |
|---|---|---|
VARNISH_CONFIG | /etc/varnish/default.vcl | Path to the active VCL config inside the container. |
VARNISH_PORT | 6081 | Port Varnish listens on. |
VARNISHD_PARAMS | -p default_ttl=3600 -p default_grace=3600 | Extra flags passed to varnishd. |
VARNISH_PROXY1_CACHE_SIZE | 128m | Cache size for the first proxy (proxy). |
VARNISH_PROXY1_BACKEND_HOST | workspace | Domain/host the first proxy serves. |
VARNISH_PROXY1_SERVER | SERVER1 | Server label for the first proxy. |
VARNISH_PROXY2_CACHE_SIZE | 128m | Cache size for the second proxy (proxy2). |
VARNISH_PROXY2_BACKEND_HOST | workspace | Domain/host the second proxy serves. |
VARNISH_PROXY2_SERVER | SERVER2 | Server label for the second proxy. |
VARNISH_BACKEND_PORT (default 81, the port Nginx listens on for traffic coming back from Varnish) lives in the project's root .env, not varnish/defaults.env, since Nginx's compose.yml also reads it.
These are all read at container start, not baked into the image, so after changing any of them in .env you need to recreate the container rather than just restart it:
- Laradock CLI
- Docker Compose
./laradock start proxy
docker compose up -d proxy
docker compose restart reuses the existing container as-is and won't pick up the new value; up -d recreates it with the current .env. Either way the cache is memory-only, so recreating the container is never a data-loss concern here.
Configure a domain
- Set your domain in
VARNISH_PROXY1_BACKEND_HOST. - Update your Varnish config and add a matching Nginx config, using
nginx/sites/laravel_varnish.conf.exampleas a starting point. - Rename
default_wordpress.vcltodefault.vclto use the WordPress-tuned config instead of the olderdefault.vcl.
Serve multiple domains
- Add a second configuration section to
.env:VARNISH_PROXY1_CACHE_SIZE=128mVARNISH_PROXY1_BACKEND_HOST=replace_with_your_domain.nameVARNISH_PROXY1_SERVER=SERVER1 - Add a matching service to
varnish/compose.yml, modeled onproxy2:custom_proxy_name:container_name: custom_proxy_namebuild: ./varnishexpose:- ${VARNISH_PORT}environment:- VARNISH_CONFIG=${VARNISH_CONFIG}- CACHE_SIZE=${VARNISH_PROXY2_CACHE_SIZE}- VARNISHD_PARAMS=${VARNISHD_PARAMS}- VARNISH_PORT=${VARNISH_PORT}- BACKEND_HOST=${VARNISH_PROXY2_BACKEND_HOST}- BACKEND_PORT=${VARNISH_BACKEND_PORT}- VARNISH_SERVER=${VARNISH_PROXY2_SERVER}ports:- "${VARNISH_PORT}:${VARNISH_PORT}"links:- workspacenetworks:- frontend
Purge and reload
Purge the cache for a URL (evicts it so the next request goes to the backend again):
curl -X PURGE https://yourwebsite.com/
Reload Varnish after changing VCL, without dropping the whole cache:
- Laradock CLI
- Docker Compose
./laradock exec proxy varnishreload
docker compose exec proxy varnishreload
Reload Nginx too if you also changed its site config:
- Laradock CLI
- Docker Compose
./laradock exec nginx nginx -t
docker compose exec nginx nginx -t
nginx -t only validates the config; once it reports no errors, apply it:
- Laradock CLI
- Docker Compose
./laradock exec nginx nginx -s reload
docker compose exec nginx nginx -s reload
Allowed Varnish CLI commands inside the container: varnishadm, varnishd, varnishhist, varnishlog, varnishncsa, varnishreload, varnishstat, varnishtest, varnishtop.
Check whether caching is working
Open a terminal inside the proxy container:
- Laradock CLI
- Docker Compose
./laradock enter proxy
docker compose exec proxy bash
Then, from inside the container:
- Live hit/miss stats:
varnishstat(add-1for a single one-shot snapshot instead of the live dashboard). Look atcache_hitvscache_miss, a healthy cache should showcache_hitclimbing on repeat requests. - Backend health:
varnishadm backend.list. The configured backend (server1, fromdefault.vcl's health probe) should showHealthy; if it saysSick, Varnish can't reachVARNISH_PROXY1_BACKEND_HOST/VARNISH_PROXY1_BACKEND_PORTand will fail closed to serving errors. - Per-request trace:
varnishlogstreams every request live, showing whether each one was ahitor amissand why. - Validate a VCL file before reloading:
varnishd -C -f /etc/varnish/default.vcl > /dev/nullcompiles the file and exits without starting a server, it fails loudly on a syntax error instead of leaving you to debug a crashed reload.
Common issues
- Varnish container fails to build. It's expected to be built after Nginx is already up, since it checks the domain's availability at build/start time; run
./laradock start nginxfirst. - Stale content keeps being served. Purge the cache (
curl -X PURGE ...) or reload Varnish (varnishreload) after deploying changes. - Wrong backend served. Confirm
VARNISH_PROXY1_BACKEND_HOST/VARNISH_PROXY2_BACKEND_HOSTmatch the domain in the corresponding Nginx site config, and that you're usingdefault_wordpress.vcl(renamed todefault.vcl) if following the WordPress setup. - Changed
.envbut nothing happened.VARNISH_PORT,VARNISHD_PARAMS, and the cache size/backend variables are only read when the container is created../laradock restart proxyreuses the old values; run./laradock start proxyagain to recreate it with the new.env. - Cache is always empty after a deploy. Expected: the cache is in-memory only (
mallocstorage), so it's wiped every time the container stops, restarts, or is recreated, not just when you purge it manually. varnishadm backend.listshowsSick. The health probe indefault.vcl/default_wordpress.vclcan't reach the backend onBACKEND_HOST/BACKEND_PORT. Confirm the backend service (usuallyworkspace, perVARNISH_PROXY1_BACKEND_HOST) is running and listening on the expected port.
Varnish sits in front of Nginx; for balancing across multiple Varnish instances see HAProxy. New to Laradock? Start with Getting Started.