How to configure TLS in Varnish
Varnish has TLS support, as of Varnish version 9. This means incoming connections to Varnish can now happen using HTTPS. Varnish can also communicate with backends using HTTPS.
This tutorial explains the different ways to configure native TLS support.
Option 1: Use the -A option
The varnnishd program offers a -A argument to enable TLS support by linking to a TLS configuration file.
varnishd example
This is what the varnishd command could look like with both regular HTTP and HTTPS enabled:
/usr/sbin/varnishd \
-a :80 \
-A /etc/varnish/tls.cfg
...
The -A argument reads the /etc/varnish/tls.cfg file where TLS-related configurations are defined.
TLS config file
This is what that tls.cfg file could look like:
frontend = {
host = ""
port = "443"
}
pem-file = "/etc/varnish/certs/mycert.pem"
The frontend directive in the config file opens port 443 for incoming HTTPS requests for all hosts and interfaces.
The pem-file directive references the TLS certificate that should be loaded. The TLS config file can have multiple pem-file entries and Varnish will use Server Name Indication (SNI) to match the right certificate.
You can define pem-file as a config block and split the certificate from the private key and the DH parameters:
pem-file = {
cert = "/etc/varnish/certs/mycert.pem"
private-key = "/etc/varnish/certs/myprivkey.pem"
dhparam = "/etc/varnish/certs/dhparam.pem"
}
The TLS configuration file also offers configuration parameters to configure TLS ciphers, protocols, and other TLS-related settings:
ciphersuites = "TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256"
tls-protos = TLSv1.2 TLSv1.3
ecdh-curve = "X25519:prime256v1:secp384r1"
Option 2: Register an HTTPS listener with -a
Another way to enable support for HTTPS requests in Varnish is by adding an HTTPS listening port using the -a option. The supported protocols for -a are http, https and proxy.
For plain HTTP listening interfaces, the protocol is often not mentioned and defaults to http.
varnishd example
Here’s how you configure an HTTPS listener:
/usr/sbin/varnishd \
-a :80 \
-a :443,https
...
If you want a clean and consistent listener definition, you can even add the http protocol to the listener on port 80:
/usr/sbin/varnishd \
-a :80,http \
-a :443,https
...
Register certificates with varnishadm
It’s not because you have an HTTPS listener, that TLS is fully configured. You now need to load TLS certificates. This can be done using specific Varnish CLI commands with varnishadm.
Here’s how you load a certificate:
varnishadm tls.cert.load /etc/varnish/cert.pem
When you run varnishadm tls.cert.list, this is the output:
default cert0 staged localhost
a1 cert0 staged localhost
a1 cert0 staged localhost
Here’s how you activate the staged certificates:
varnishadm tls.cert.commit
When you run varnishadm tls.cert.list again, this is the output:
default cert0 active localhost
a1 cert0 active localhost
a1 cert0 active localhost
Now you can access your Varnish server over HTTPS and the certificates will be used.
Changing certificates at runtime
The main benefit of enabling TLS support in Varnish via -a :443,https compared to using -A /etc/varnish/tls.cfg is that certificates can be dynamically added, reloaded, discarded and rolled back at runtime.
This means Varnish does not have to be restarted and the cached content remains intact. Let’s look at a couple of scenarios where certifactes are changed at runtime.
Discard certificates
The tls.cert.discard command discards active certificates and allows ongoing sessions to complete.
Here’s an example:
Let’s assume these are my active certificates when running varnishadm tls.cert.list:
default cert0 active localhost
a1 cert0 active localhost
a1 cert0 active localhost
I can run the following command to discard the certificate with identifier cert0:
varnishadm tls.cert.discard cert0
When you run varnishadm tls.cert.list again, this is the state of the certificate:
default cert0 discard localhost
a1 cert0 discard localhost
a1 cert0 discard localhost
To commit the discard and remove the certificate, simply run varnishadm tls.cert.commit.
Rollback certificates
The tls.cert.rollback command rolls back staged certificates. This is the opposite of tls.cert.commit.
Before the rollback, you first need to load a certificate. We run varnishadm tls.cert.load /etc/varnish/cert.pem to make this happen and the varnishadm tls.cert.list output is the following:
default cert0 staged localhost
a1 cert0 staged localhost
a1 cert0 staged localhost
We can now perform a rollback:
varnishadm tls.cert.rollback
The any staged certificate is now gone and won’t appear in your varnishadm tls.cert.list output.
The rollback command also works for discarded certificates: because it it the opposite of a commit, discarded certificates will become active again.
Reload active certificates
When certificates expire, they need to be reloaded. The tls.cert.reload CLI command atomically reloads all certificates. A successful reload is immediately committed. Each active certificate will be re-read from disk and loaded using the same parameters as the current configuration.
If an error is encountered during a reload, all changes will be rolled back and the previous state will be preserved.
Here’s an example:
varnishadm tls.cert.reload
Reloads can only happen if there are not staged or discarded certificates. You have to commit or roll back these certificates before reloading.
Persisting certificates
Loaded and committed certificates are not persisted. When varnishd gets restarted, your certificates are gone.
You can persist your TLS certificates by storing the tls.cert.load and tls.cert.commit CLI commands in a file and letting Varnish run them automatically on startup using the -I option.
Here’s a file named cli.cfg that contains the Varnish CLI commands that need to run on startup:
start
tls.cert.load /etc/varnish/cert.pem
tls.cert.commit
Please note that the start command is run first to start the Varnish child process.
Here’s an example varnishd command that loads this file via -I:
/usr/sbin/varnishd \
-a :80,http \
-a :443,https \
-I /etc/varnish/cli.cfg
...
Backend TLS
Not only can Varnish communicate with the client over TLS, but also with the backend.
Enabling backend TLS support happens in the backend definition. Here’s an example:
backend default {
.host = "server.example.com";
.port = "443";
.ssl = 1; # Turn on SSL support
}
By adding the .ssl = 1; property to the backend definition, Varnish will communicate use HTTPS to communicate with the backend.