Aelia Currency Switcher allows WooCommerce and Easy Digital Downloads online business owners to display their products in different currencies depending on the visitor’s geolocation. It works by probing each visitor’s IP address and setting the currency based on their country, city or other parameters the business owner has chosen to decide the currency.
I had a long discussion with Diego on the Advanced WooCommerce facebook group about the Aelia plugin and how to cache the specific currencies separately more powerfully. Diego already had done what he could to speed things up by creating addons for some caching plugins. aelia Currency Switcher for WooCommerce probes every single visitor for their geolocation, after that the currency cookies are used as a cache key. This is very clever, but can still result in a first slow page load for each visitor and first speed impressions matter! I told Diego that this system could be improved with the Varnish MaxMind GeoIP vmod.
I suggested to Diego it would be possible to only probe the first visitor from each continent, country or city once, through the Varnish caching layer. Such operation would allow us to serve cached version of the site content to all subsequent visitors from the same region, without requiring the aelia plugins to perform the detection.
You can extend Varnish functionality with vmods. In this guide we are going to use the maxminddb vmod to cache the different currency values with Varnish. You must have root access to your VPS or dedicated server running Varnish or be able to modify your Varnish configuration. I used Ubuntu 16.04 and Debian 8 for this guide.
You must already have Varnish configured with WooCommerce.
WooCommerce Currency Switcher Speed Tests
For this test I set up a Digital Ocean VPS with nginx, PHP7, MariaDB and Varnish 4 with WooCommerce and added 10 products with the Product Generator.
I installed the Aelia WooCommerce Currency Switcher plugin and set 3 different currencies: EUR, USD and GBP.
I used the Varnish configuration outlined below and ran the tests with and without cache.
WooCommerce Currency Speed without Varnish Cache
Page load time from Sweden without Varnish was 882 ms
WooCommerce Currency Speed with Varnish Cache
Page load time from Sweden with Varnish was 279 ms
If you want a 300% WooCommerce speed improvement for your different currencies, read on!
Cache WooCommerce Currency from GeoIP with Varnish 4 vmod
Installation overview
- Install MaxMind GeoIP libraries
- Install the Varnish MaxMind GeoIP vmod
- Download the MaxMind Lite GeoIP databases
- Configure Varnish vcl to use the GeoIP vmod
- Test Varnish is caching currency specific pages based on GeoIP
Configure Aelia WooCommerce Currency Switcher
Make sure you go to WooCommerce Currency Switcher > Geolocation tab > check Enable automatic selection of Currency depending on Visitors’ location
Set any custom currency information with Aelia’s guide, I used Pluginception to create the custom plugin.
Install the MaxMind Libraries
These packages are required for the Varnish vmod to compile. For Debian 9 Stretch and Ubuntu 16.04 Xenial and later use these.
sudo apt-get update
sudo apt-get install build-essential libtool libvarnishapi-dev pkg-config python-docutils libmaxminddb-dev libmaxminddb0 -y
For Debian Jessie or Ubuntu 14.04 use these commands to install the Varnish libraries and MaxMind libraries from the .deb packages in Debian Stretch.
There may be updated packages, you can get the updated links from here.
sudo apt-get update
sudo apt-get install build-essential libtool libvarnishapi-dev pkg-config python-docutils -y
cd /tmp
wget https://ftp.de.debian.org/debian/pool/main/libm/libmaxminddb/libmaxminddb-dev_1.2.0-1_amd64.deb
sudo dpkg -i libmaxminddb-dev*.deb
wget https://ftp.de.debian.org/debian/pool/main/libm/libmaxminddb/libmaxminddb0_1.2.0-1_amd64.deb
sudo dpkg -i libmaxminddb0*.deb
rm libmasminddb*
Install the GeoIP Varnish vmod
The madminddb vmod lets you use the MaxMind GeoIP databases with Varnish.
cd /tmp
git clone https://github.com/simonvik/libvmod_maxminddb
cd libvmod_maxminddb
./autogen.sh
./configure VMOD_DIR=/usr/lib/varnish/vmods/
sudo make
sudo make install
libtool --finish /usr/lib/varnish/vmods/
Now the maxminddb vmod has been installed so Varnish can use the vmod to communicate with the MaxMind databases but we still need the GeoIP databases!
Download the MaxMind GeoIP Databases
The free MaxMind databases called GeoLite2 can be downloaded from here
The professional MaxMind databases are more precise but have a monthly subscription fee.
To use the MaxMind GeoLite2 databases use these commands
cd /etc/varnish
sudo wget https://geolite.maxmind.com/download/geoip/database/GeoLite2-City.mmdb.gz
sudo wget https://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.mmdb.gz
sudo gunzip GeoLite2*
sudo rm -rf GeoLite2*.gz
Configure Varnish to Detect GeoIP
These are the snippets we are going to include in the existing Varnish vcl for WooCommerce
- sub vcl_init – load the geoip databases
- sub vcl_recv – set headers based on geoip
- sub vcl_hash – specify cache separation based on calculated currency
Open the Varnish vcl first
sudo nano /etc/varnish/default.vcl
sub vcl_init
First import the maxminddb and std modules.
In sub vcl_init
we load the MaxMind databases.
# new 4.0 format.
vcl 4.0;
import maxminddb;
import std;
# Default backend definition. Set this to point to your content server.
backend default {
.host = "127.0.0.1";
.port = "8080";
}
#Initialize the GeoIP database locations
sub vcl_init{
maxminddb.init_db("/etc/varnish/GeoLite2-Country.mmdb");
maxminddb.init_db("/etc/varnish/GeoLite2-City.mmdb");
}
sub vcl_recv
In the sub vcl_recv
section we are going to detect the IP location and set some headers.
Then we will use the headers to set the currency and tell Varnish to cache based on these headers.
We are also explicitly caching the aelia query string and aelia currency cookie.
sub vcl_recv {
#get continent
set req.http.X-continent = maxminddb.query_continent(client.ip);
#get country
set req.http.X-Country = maxminddb.query_country(client.ip);
set req.http.X-state = maxminddb.query_state(client.ip);
set req.http.X-city = maxminddb.query_city(client.ip);
set req.http.X-postalcode = maxminddb.query_postalcode(client.ip);
#set currency based on country header
if (req.http.X-Country == "NL") {
set req.http.X-Currency = "EUR";
} else if (req.http.X-Country == "US") {
set req.http.X-Currency = "USD";
}
#set currency more specifically for multiple countries that share same currency
else if (req.http.X-Country ~ "DK|FO") {
set req.http.X-Currency = "DKK";
}
# for debugging in varnishlog
std.log("Continent value is: " + req.http.X-continent);
std.log("Country value is: " + req.http.X-Country);
std.log("Currency is: " + req.http.X-Currency);
std.log("City: " + req.http.X-city);
std.log("State: " + req.http.X-state);
std.log("Postal: " + req.http.X-postalcode);
#cache aelia currency cookie
if (req.http.cookie ~ "aelia_cs_selected_currency") {
return(hash);
}
#cache aelia query strings explicitly
if (req.url ~ "\?aelia_(cs_currency|customer_country|customer_state)=")
return(hash);
}
sub vcl_hash
In the sub vcl_hash
section we are caching specific versions of both the aelia currency cookie and the custom header we set for the currency.
sub vcl_hash {
#store cache based on aelia currency cookie
if (req.http.cookie ~ "aelia_cs_selected_currency") {
hash_data(req.http.cookie);
}
#hash based on currency header Varnish sets
hash_data(req.http.X-Currency);
}
Ctrl+X, Y and Enter to Save.
Test the Varnish GeoIP Configuration
This command will verify the Varnish vcl syntax is valid
varnishd -C -f /etc/varnish/default.vcl
Now reload the Varnish service
sudo service varnish reload
Using the command line on two different DigitalOcean VPS’s from the same region, we can verify if Varnish is caching our custom currency shop and product pages by using cURL.
sudo apt-get install curl -y
Now cURL the shop URL or a product page. Using the -I
switch which returns the response headers.
curl -I https://wp-bullet.online/shop/
At first you will probably see the X-Cache: MISS
header since it is the first visit from that specific continent.
HTTP/1.1 200 OK
Date: Sat, 27 Aug 2016 07:52:43 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Set-Cookie: __cfduid=dd68b58232cba6c1f53425d33bd2677741472284363; expires=Sun, 27-Aug-17 07:52:43 GMT; path=/; domain=.wp-bullet.online; HttpOnly
Link: <https://wp-bullet.online/wp-json/>; rel="https://api.w.org/"
Vary: Accept-Encoding
X-Varnish: 491537 32774
Age: 33489
Via: 1.1 varnish-v4
X-Cache: MISS
Server: cloudflare-nginx
CF-RAY: 2d8df21881550c05-AMS
Repeat the same cURL command
curl -I https://wp-bullet.online/shop/
Now you will see an X-Cache: HIT
showing Varnish has cached the WooCommerce currency page based on the headers we set.
HTTP/1.1 200 OK
Date: Sat, 27 Aug 2016 07:52:53 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Set-Cookie: __cfduid=dd68b58232cba6c1f53425d33bd2677741472284363; expires=Sun, 27-Aug-17 07:52:43 GMT; path=/; domain=.wp-bullet.online; HttpOnly
Link: <https://wp-bullet.online/wp-json/>; rel="https://api.w.org/"
Vary: Accept-Encoding
X-Varnish: 491537 32774
Age: 33491
Via: 1.1 varnish-v4
X-Cache: HIT
Server: cloudflare-nginx
CF-RAY: 2d8df21881550c05-AMS
On another VPS pair in the same continent or country you can run the test again. This should show you an X-Cache HIT immediately.
After verifying one continent works you can move on to the next continent using a VPS from that continent to do cURL tests. I recommend using pingdom tools if you want to see a picture of the shop page and verify it displays the correct currency.
If you need help leave a comment or get in touch, I’m always happy to make WooCommerce faster :).
hi, i am using bitnami and it has custom paths
i completed the steps before installing GeoIP
when i try to install Install the GeoIP Varnish vmod
./configure VMOD_DIR=/opt/bitnami/varnish/lib/varnish/vmods/
i get the following error
configure: error: in `/tmp/libvmod_maxminddb’:
configure: error: The pkg-config script could not be found or is too old. Make sure it
is in your PATH or set the PKG_CONFIG environment variable to the full
path to pkg-config.
i have no clue how to set the PKG_CONFIG environment, tried google but didnt get the answer for bitnami with debian 8, please help me out, my load time with currency converter is huge.
thanks
Can you try install pkg-config to make sure it’s up to date?
Which host are you using Bitnami on?
its bitnami wordpress on google cloud compute
running
gofinchh@wordpress-1-vm:~$ install pkg-config
install: missing destination file operand after ‘pkg-config’
Try ‘install –help’ for more information.
The exact command would be something like
sudo apt install pkg-config
pkg-config is already the newest version.
i read in their forums about the pkg-config location
PKG_CONFIG_PATH=/opt/bitnami/common/lib/pkgconfig PKG_CONFIG=/usr/bin/pkg-config
You may have to adjust that then in your environment, I don’t use bitnami so I’d have to dig into its setup further to help you, you are welcome to reach out to me on Codeable where I freelance 🙂
i got that working to next next but now stuck at
sudo make
akefile:438: recipe for target ‘vmod_maxminddb.lo’ failed
make[2]: *** [vmod_maxminddb.lo] Error 1
make[2]: Leaving directory ‘/home/gofinchh/libvmod_maxminddb/src’
Makefile:498: recipe for target ‘all-recursive’ failed
make[1]: *** [all-recursive] Error 1
make[1]: Leaving directory ‘/home/gofinchh/libvmod_maxminddb’
Makefile:365: recipe for target ‘all’ failed
make: *** [all] Error 2
It looks like you aren’t in the /tmp folder when you clone the github repo. You can literally copy and paste that whole block, it should work
Mike please let me know the charges for configuring it on my bitnami install that is on debian 8, i will send money through paypal
varnish is already configured and running
Please get in touch with me via Codeable, I freelance exclusively through there
When i run “sudo make” after ./configure VMOD_DIR=/usr/lib/varnish/vmods/
i get this error
vmod_maxminddb.c:122:25: error: expected ‘)’ before ‘struct’
event_function(VRT_CTX, struct vmod_priv *priv, enum vcl_event_e e)