Determining a customer’s country is widely used in many online stores. Geolocation (often called GeoIP) is used for implementing various scenarios, such as setting the default language, currency, delivery methods and redirecting a user to another URL created specifically for his country.
The redirection can be performed automatically or manually when customers click on a link that has been offered to them.
Varnish vs. PHP-modules
There are plenty of modules for Magento 2 that allow different scenarios to be carried out depending on the visitor’s IP address, or on the data obtained in a different way, for example, using the country code from Cloudflare.
But Varnish changes everything. Varnish is a caching proxy server that is placed before the web server with Magento 2. As soon as a user opens a page on the webstore, the entire page is stored in Varnish cache. Other visitors also get this saved static page. This is done to all the other pages of the site.
Saved static pages are loaded much faster than dynamic ones, and this gives a significant increase in speed. The result is so impressive, that even Magento 2 developers recommend putting a third-party Varnish solution instead of the default Full Page Cache.
However, if we use GeoIP modules, which first determine the visitor’s country through the PHP code and then perform a redirect, they become useless after installing Varnish. After all, it doesn’t even get to the execution of this code. If a person from Hungary has downloaded a specific URL, people from other countries will see exactly the page cached for Hungary.
There are two ways to get around this problem:
- Setting Varnish for an automatic redirect.
- Creating a module that works through AJAX after loading the base page.
Both of these methods have their advantages and disadvantages. We will consider the creation of an AJAX module in our next publication, and now we’ll take a look at how to configure Varnish for automatic redirection.
Installing a docker with a web server and Varnish
The server we will be using in our work runs on Ubuntu. Make sure you already have nginx, curl, git, docker, docker-compose installed.
Create a docker folder in a convenient place, add the docker-compose.yml file to it. Here is an example of my file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
version: '2' services: apache: container_name: apache build: context: ./ dockerfile: apache.dockerfile volumes: - "/var/www/example.com:/var/www/html" networks: app_net: ipv4_address: 172.20.0.2 mysql: container_name: mysql image: 'bitnami/mysql:latest' volumes: - "db-geoip:/var/lib/mysql" networks: app_net: ipv4_address: 172.20.0.4 environment: - MYSQL_ROOT_PASSWORD=root redis: container_name: redis image: "redis" networks: app_net: ipv4_address: 172.20.0.5 phpmyadmin: image: phpmyadmin/phpmyadmin container_name: phpmyadmin networks: app_net: ipv4_address: 172.20.0.3 depends_on: - mysql environment: - PMA_HOST=172.20.0.4 varnish: container_name: varnish image: emgag/varnish:4.1 depends_on: - apache links: - apache volumes: - ./varnish/varnish.vcl:/etc/varnish/default.vcl environment: - VARNISH_STORAGE = 1024M networks: app_net: ipv4_address: 172.20.0.6 volumes: db-geoip: networks: app_net: driver: bridge ipam: driver: default config: - subnet: 172.20.0.0/24 |
I won’t include the dockerfile on the apache container here since it’s irrelevant to the topic of this article. You can use your own file with the necessary settings.
Pay attention to the volume of the apache container. Its left part “/var/www/example.com:/var/www/html” reflects the location of my site folder, change it to your own. Its right part does not need to be changed.
Partner With Us
Let's discuss how to grow your business. Get a Free Quote.Varnish container + GeoIP module
Speaking of Varnish container — we will use the image emgag/varnish version 4.1. Its detailed description and distribution kit can be found on hub.docker.com.
It already has all the additional modules for Varnish, which are necessary for the operation of our solution. First of all, it’s the GeoIP module.
If you already have Varnish installed, you can install the GeoIP module according to the instructions in the provided link.
Adding a VCL file for Varnish
Pay attention to the volume in the Varnish container ./varnish/varnish.vcl:/etc/varnish/default.vcl. In our docker folder, we created a varnish folder, and inside it a varnish.vcl file. You don’t have to stick to such a structure and names, as long as the left side shows the path to your custom VCL file, in which you will register all the necessary settings.
Now we will add our VCL file. To do this let’s refer to the official Magento 2 documentation. According to it, you should go to the site administration panel and open the Stores➜Configuration➜Advanced➜System section, open the Full Page Cache tab and select Varnish Cache. Then in Varnish Configuration we need to input our data.
Type apache into the Backend host field. It is the apache container that our Varnish will refer to. The Access List field is the address from which Varnish will receive a signal that changes have been made and it is time to flush the cache. These signals will also come from Apache. Backend port will be 80 instead of 8080 by default (you can set your own number depending on the settings of your Apache container).
After we save the settings, the Export VCL for Varnish 4 and 5 buttons will become active. In our example it’s Varnish 4, therefore, we export this varnish.vcl file and upload it to our varnish folder inside the docker folder.
When installing the Varnish container, this file will be used to create the /etc/varnish/default.vcl file inside the container.
It is necessary to make some editing for compatibility with our container.
First, let’s cut this code:
1 2 3 4 5 6 7 8 9 10 11 12 |
backend default { .host = "apache"; .port = "80"; .first_byte_timeout = 600s; .probe = { .url = "/pub/health_check.php"; .timeout = 2s; .interval = 5s; .window = 10; .threshold = 5; } } |
Here is what should be left of it:
1 2 3 4 |
backend default { .host = "apache"; .port = "80"; } |
Second, replace this code:
1 2 3 4 5 6 7 8 9 10 |
if (!req.http.X-Magento-Tags-Pattern && !req.http.X-Pool) { return (synth(400, "X-Magento-Tags-Pattern or X-Pool header required")); } if (req.http.X-Magento-Tags-Pattern) { ban("obj.http.X-Magento-Tags ~ " + req.http.X-Magento-Tags-Pattern); } if (req.http.X-Pool) { ban("obj.http.X-Pool ~ " + req.http.X-Pool); } return (synth(200, "Purged")); |
with this:
1 2 3 4 5 6 7 |
if (!req.http.X-Magento-Tags-Pattern) { return (synth(400, "X-Magento-Tags-Pattern header required")); } ban("obj.http.X-Magento-Tags ~ " + req.http.X-Magento-Tags-Pattern); # If all Tags should be purged clear ban everything to catch assets as well if (req.http.X-Magento-Tags-Pattern == ".*") { ban("req.url ~ .*"); } return (synth(200, "Purged")); |
Here are the rules for clearing the cache. We remove X-Pool, because the extension for it is not supported by our Varnish and we do not use this header in our Magento 2. We also add a line commented in the code for adding new assets.
In order for Varnish cache it to be flushed by clicking on a button in the admin panel or a console command, you need to add the http_cache_hosts array in the env.php file:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<?php return array ( ... 'http_cache_hosts' => array ( 0 => array ( 'host' => 'apache', 'port' => '80', ), ), … ); |
Configuring NGINX for docker work
On Ubuntu, open the etc/nginx/sites-available folder, create a vhosts file inside it with the following contents:
1 2 3 4 5 6 7 8 9 |
server { listen 80; server_name example.com; location / { proxy_pass http://172.20.0.6; include snippets/proxy-apache.conf; } } |
Create a link to this vhosts file in the etc/nginx/sites-enabled folder by creating a simlink.
In this file, example.com is the address of your site.
Let’s take a look at the proxy_pass http://172.20.0.6 line. Pay attention to the IP addresses assigned to each container in the docker-compose.yml file. So, the IP address for the Varnish server will be 172.20.0.6, and for the Apache web server 172.20.0.2.
Thus, we send the user who entered example.com to the Varnish proxy server. After that Varnish contacts the Apache server at a different IP address.
If you want to temporarily remove Varnish from the chain, it will be enough to write 172.20.0.2 in this line and restart Nginx.
By the way, make sure that the IP address of your server has not been assigned to your domain in the /etc/hosts file. If it has, you can delete this line.
Next, we need to create the etc/nginx/snippets/proxy-apache.conf file and write the following code in it:
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
This code is needed so that we can get the real IP of the user who has visited the site.
After making all the changes, restart nginx with the service nginx restart command.
Magento Webdesign
Take your online store to the next level with BelVG Magento Webdesign
Visit the pageLaunching and testing docker with Varnish
Now we can enter the folder with docker and execute the docker-compose up -d command. After launch, see if all containers are running using the docker ps -a command.
Then enter the Varnish container (docker exec -it varnish bash), and enter the varnishlog command. After that go to your website and see if logs have appeared in the console.
Working with the GeoIP module in Varnish
Now we need to configure the extension for geolocation, which we have installed with Varnish. Varnish is configured in the VCL file, so we will continue editting it.
First, you need to add the GeoIP extension. Add it at the beginning of the file as the import geoip line. Here is what the beginning of the file will look like:
1 2 3 4 |
vcl 4.0; import geoip; import std; …. |
Now add the following code to sub vcl_recv:
1 2 3 4 5 6 7 8 |
sub vcl_recv { set req.http.X-Country-Code = geoip.country_code(req.http.X-Real-IP); set req.http.X-Country-Code = std.tolower(req.http.X-Country-Code); if (req.http.X-Country-Code ~ "(de|at)" ) { return(synth(750, "Moved Temporarily")); } ….. } |
Now let’s take a look at each line separately.
- set req.http.X-Country-Code = geoip.country_code(req.http.X-Real-IP) — sets the HTTP header X-Country-Code, assigning it a two-letter country code, which forms the country_code function from the geoip extension. The IP address of the visitor is passed to the function.
- set req.http.X-Country-Code = std.tolower(req.http.X-Country-Code) — the country code is reduced to lowercase for a uniform standard.
- if (req.http.X-Country-Code ~ “(de|at)” ) — checks if the country code matches the values of de and at (Germany and Austria). If yes, the synth function is performed with parameter 750 and redirection to another domain.
Now let’s create the synth function:
1 2 3 4 5 6 7 |
sub vcl_synth { if (resp.status == 750) { set resp.http.Location = "https://german.com/"; set resp.status = 302; return(deliver); } } |
In this function, we check what value came into it, and if it equals 750, then we perform a redirect to another domain.
You can create a variety of conditions and verification codes (such as 750, 751, 752, etc.) and redirect to different sites depending on the value of the code.
After the changes in the VCL file, you need to rebuild the varnish container. To do this, we execute the docker restart varnish command.
Conclusion
We have implemented an automatic redirect to another site on the side of Varnish. The advantage of this solution is its quick functioning.
It also has disadvantages: you will have to manually edit both redirect domains and country codes in the VCL file. It is also worth noting that this solution is technically difficult.
However, if you need an automatic redirect immediately after entering the address, this solution, with all of its flaws, is the only possible one.
For changing the language, currency on the same site, as well as going to the appropriate site manually, you will need to use another solution based on AJAX. We will cover this topic in our next article. Thank you and stay tuned!
Magento Custom Development
Take your online store to the next level with BelVG Magento Custom Development
Visit the page
Hi Renars,
thanks for the great idea! We will update an article as soon as we can.
Would be nice if you included the redirect part and commented why changing currency won’t work without AJAX.
Beside Magento other PHP frameworks like Symfony Laravel can also optimize with varnish.
Hi Vector!
You can check if Varnish is enabled in Magento 2 in the article
How to check if varnish is running magento?