Adding Varnish cache in front of a DirectAdmin server is one of the highest-impact performance changes you can make for a traffic-heavy site, but the setup has a few DirectAdmin-specific quirks that trip people up -- especially around port binding, Nginx reverse-proxy configuration, and cache purging on dynamic content. This guide walks through a working DirectAdmin + Nginx + Varnish stack from scratch, plus the fixes for the most common issues once it's running.
Why Varnish in Front of DirectAdmin
DirectAdmin typically runs Apache or Nginx (or Nginx as a reverse proxy in front of Apache) to serve requests. Varnish sits in front of all of that, serving cached HTTP responses directly from memory for repeat requests, which means the backend web server, PHP-FPM, and database never get touched for a cache hit. For a WordPress or WooCommerce site under real traffic, this routinely cuts server load by 60-90% and drops response times from hundreds of milliseconds to single digits.
Step 1: Confirm the Current Stack and Port Layout
Before installing Varnish, check what's currently listening on port 80:
ss -tlnp | grep :80
In a typical DirectAdmin + Nginx setup, Nginx is bound to port 80 directly. Varnish needs to take over port 80, and Nginx (or Apache) needs to move to an internal port, commonly 8080. Plan this shift before touching any config, since a mistake here takes the site offline until corrected.
Step 2: Install Varnish
curl -fsSL https://packagecloud.io/varnishcache/varnish72/gpgkey | apt-key add -
apt-get install -y apt-transport-https
echo "deb https://packagecloud.io/varnishcache/varnish72/ubuntu/ $(lsb_release -cs) main" > /etc/apt/sources.list.d/varnishcache_varnish72.list
apt-get update && apt-get install -y varnish
(On CentOS/AlmaLinux systems commonly used with DirectAdmin, use the equivalent yum/dnf repository from the Varnish Cache project instead.)
💡 None of these worked? Skip the guesswork.
Get Expert Help →Step 3: Move Nginx to an Internal Port
In DirectAdmin, this is managed through the web server templates rather than editing vhost files directly, since DirectAdmin regenerates configs from templates. The safe approach:
1. Go to /usr/local/directadmin/data/templates/custom/ (create the custom directory if it doesn't exist).
2. Copy the relevant Nginx server template (e.g. nginx_server.conf) into the custom directory so your edits survive DirectAdmin config rebuilds.
3. Change the listen directive from listen 80; to listen 127.0.0.1:8080; in the custom template.
4. Rebuild web server configs: echo "action=rewrite&value=httpd" >> /usr/local/directadmin/data/task.queue then run cd /usr/local/directadmin && ./dataskq d2 to process the queue.
Step 4: Configure Varnish to Listen on Port 80
Edit the Varnish systemd unit (usually via systemctl edit varnish or directly in /etc/systemd/system/varnish.service) to set:
ExecStart=/usr/sbin/varnishd -a :80 -a localhost:8443,PROXY -T localhost:6082 -f /etc/varnish/default.vcl -S /etc/varnish/secret -s malloc,512m
Adjust the cache size (malloc,512m) based on available RAM -- a dedicated cache size of 512MB-2GB is typical for a mid-size site.
Step 5: Write the VCL to Point at the Backend
Edit /etc/varnish/default.vcl:
vcl 4.1;
backend default {
.host = "127.0.0.1";
.port = "8080";
}
sub vcl_recv {
if (req.http.Cookie ~ "(wordpress_logged_in|comment_author|woocommerce_)") {
return (pass);
}
unset req.http.Cookie;
}
sub vcl_backend_response {
if (bereq.url !~ "wp-admin|wp-login|checkout|cart|my-account") {
set beresp.ttl = 1h;
unset beresp.http.Set-Cookie;
}
}
This is a minimal but production-safe starting VCL: it bypasses caching entirely for logged-in users and WooCommerce sessions (critical -- caching a logged-in page for someone else is a serious bug), while caching everything else for an hour.
Step 6: Restart Services in the Correct Order
systemctl restart nginx
systemctl daemon-reload
systemctl restart varnish
systemctl status varnish
Verify Varnish is serving on port 80 and Nginx has moved off it:
curl -I http://example.com/ | grep -i "x-varnish\|via"
A response header showing X-Varnish or Via: 1.1 varnish confirms requests are now passing through the cache layer.
Common Issues After Setup
Cache Never Hits (Always MISS)
Check for cookies being set on every response -- WordPress sets a session cookie for anonymous visitors in some plugin configurations, which forces every request through pass mode in the VCL above. Inspect response headers with curl -I and strip unnecessary cookies from the VCL's vcl_recv as needed.
Stale Content After Publishing an Update
Varnish doesn't know your CMS updated content until the cache TTL expires or you explicitly purge. Install a cache-purging plugin (for WordPress, most cache plugins support a Varnish purge module) or manually purge via the admin port:
varnishadm ban req.url ~ .
This bans (invalidates) the entire cache -- use targeted bans in production instead of a full flush when only one page changed.
SSL/HTTPS Traffic Bypassing Varnish Entirely
Varnish doesn't terminate TLS natively in older configurations; you typically need Nginx (or a dedicated TLS terminator) in front of Varnish for HTTPS, then Varnish talking to the backend on port 8080. Confirm your architecture is: Nginx (443, TLS) → Varnish (80) → Nginx/Apache backend (8080), not skipping Varnish for HTTPS traffic.
Getting a Varnish + DirectAdmin caching layer stable under real traffic -- with correct purging, SSL termination, and safe handling of logged-in sessions -- is exactly the kind of performance tuning our server management team handles for hosting clients who need consistent page speed under load.
Monitoring Cache Hit Ratio in Production
Once Varnish is live, don't just assume it's working -- measure it. Use the built-in statistics tool:
varnishstat -1 | grep -E "cache_hit|cache_miss"
A healthy production site should settle at a 70-95% hit ratio once the cache has warmed up (typically within an hour of consistent traffic). A ratio stuck below 30% after warm-up almost always points back to a cookie or session issue forcing pass-mode on requests that should be cacheable. You can also watch live request handling in real time with:
varnishlog -g request
This shows each incoming request, whether it hit, missed, or passed, and why -- invaluable for tracking down exactly which URL pattern or cookie is preventing caching.
Handling Multiple Domains on One DirectAdmin + Varnish Server
Most DirectAdmin servers host more than one domain, and each site may need different caching rules -- a WooCommerce store needs aggressive session bypass, while a static marketing site can be cached almost entirely. Extend the VCL with a per-host conditional:
sub vcl_recv {
if (req.http.host == "store.example.com") {
if (req.http.Cookie ~ "woocommerce_") {
return (pass);
}
}
if (req.http.host == "blog.example.com") {
unset req.http.Cookie;
}
}
This lets you run one Varnish instance in front of an entire DirectAdmin server while tailoring cache behavior per site, rather than needing a separate Varnish instance for every domain.
Rolling Back Safely If Something Breaks
Because Varnish takes over port 80 entirely, any misconfiguration takes every site on the server offline, not just one. Before making this change on a live production server, always have a rollback plan ready: keep the original Nginx template backed up outside the custom directory, and know the exact commands to stop Varnish and revert Nginx to port 80 if something goes wrong:
systemctl stop varnish
# revert nginx custom template listen directive back to 80
echo "action=rewrite&value=httpd" >> /usr/local/directadmin/data/task.queue
cd /usr/local/directadmin && ./dataskq d2
systemctl restart nginx
Testing this rollback procedure once during a maintenance window, before you actually need it under pressure, is worth the extra few minutes.
Load Testing Before You Trust the Setup
Before relying on Varnish for a production launch or a traffic spike (a sale, a marketing campaign, a press mention), load test the cached and uncached paths separately using a tool like ab or wrk:
wrk -t4 -c100 -d30s https://example.com/
Compare requests-per-second with Varnish enabled versus a direct hit to the backend port (8080) to confirm the cache is actually carrying the load you expect. If the numbers barely differ, revisit your VCL -- something is still forcing most requests to bypass the cache.
Frequently Asked Questions
Why is Varnish showing MISS on every request in DirectAdmin?
This is almost always caused by cookies being sent on every response, which forces the request into pass mode instead of being cached. Check response headers for Set-Cookie and adjust the VCL's vcl_recv logic to strip unnecessary cookies for anonymous visitors while still bypassing cache correctly for logged-in sessions.
Do I need to move Nginx off port 80 to use Varnish with DirectAdmin?
Yes. Varnish needs to bind to port 80 to intercept all incoming HTTP traffic. Nginx (or Apache) must be reconfigured to listen on an internal port like 8080, with Varnish's VCL backend pointing to that internal port.
How do I purge Varnish cache after updating content in DirectAdmin?
Use varnishadm ban req.url ~ . for a full purge, or a targeted ban matching the specific URL that changed. Most CMS platforms also have Varnish-aware cache plugins that automatically send a purge request whenever content is published or updated.
Will Varnish cache my WooCommerce checkout or cart pages by mistake?
It shouldn't if your VCL is configured correctly -- checkout, cart, my-account, and any page relying on session-specific cookies should be explicitly excluded from caching in vcl_backend_response, and requests carrying WooCommerce session cookies should return (pass) in vcl_recv.
Does Varnish work with HTTPS out of the box on DirectAdmin?
Not directly -- Varnish itself doesn't handle TLS termination in a typical setup. You need Nginx (or another TLS-capable proxy) in front of Varnish to terminate HTTPS on port 443, then forward decrypted traffic to Varnish on port 80, which in turn talks to the backend web server.
