Network Services Load Balancing

How to setup HTTP(S) Load Balancing in Google Cloud with CDN

Disclosure: This post may contain affiliate links, which means we may receive a commission if you click a link and purchase something that we recommended.

Pinterest LinkedIn Tumblr

This post provides you with detailed and advanced steps to setup HTTP(S) Layer 7 Load Balancer for your web application on Google Cloud Platform.

Here we will set up WordPress, Nginx, PHP, Cloud SQL, and Cloud Storage for your Load Balancer.

Carefully follow this tutorial without missing any steps for a successful setup.

HTTP(S) Load Balancing can be configured and updated through three different interfaces:

  • gcloud command-line tool
  • Google Cloud Platform Console
  • Rest API

Steps to setup Load Balancing on Google Cloud

  1. Enable APIs and create a Service account
  2. Nginx configuration for Load Balancer
  3. Create Health Check
  4. Create Instance Template
  5. Create a Managed Instance Group
  6. Reserve Global Region IPv4 and IPv6 addresses
  7. Create Load Balancer
  8. Install LetsEncrypt SSL Certificate
  9. Configure DNS and setup Cloud CDN

Prerequisites

If you have all the above mentioned required requisites done and in place, you can proceed to setup Load Balancing.

Enable APIs and create a Service account

Go to APIs and Services and click Enable APIs and Services and enable Cloud SQL API and Cloud SQL Admin API

Now go to IAM & Admin >> Service accounts and click Create service account

In step 1

Enter Service account Name

Click Create

In step 2

Select Role

Cloud SQL >> Cloud SQL Client
Project >> Editor

Click Continue

In step 3

Click Create Key

Choose Key type as JSON

Click Create

Nginx Configuration for Load Balancer

If you have followed the WordPress setup above

Go to Compute Engine >> Instances and SSH into your instance. You must have a Nginx configuration file in your /etc/nginx/sites-available directory named as yourdomainname.com

Now you need to modify your Nginx configuration file to accept connections from Load Balancer, so edit the file

sudo nano /etc/nginx/sites-available/yourdomainname.com

and replace the contents with the following configuration and hit Ctrl+X followed by Y to save it. Make sure you replaced the yourdomainname.com with your domain name.

fastcgi_cache_path /home/username/yourdomainname.com/cache levels=1:2 keys_zone=yourdomainname.com:100m inactive=60m;

server {
    listen [::]:80;
    listen 80;

    server_name yourdomainname.com www.yourdomainname.com;

    if ($http_x_forwarded_proto != "https") {
        return 301 https://www.yourdomainname.com$request_uri;
    }

    error_log /home/username/yourdomainname.com/logs/error.log;

    root /home/username/yourdomainname.com/public/;
    index index.htm index.html index.php;

    set $skip_cache 0;

    if ($request_method = POST) {
        set $skip_cache 1;
    }

    if ($query_string != "") {
        set $skip_cache 1;
    }    

    if ( $cookie_woocommerce_items_in_cart = "1" ){
        set $skip_cache 1;
    }

    if ($request_uri ~* "/wp-admin/|wp-.*.php|/feed/|index.php|sitemap(_index)?.xml") {
        set $skip_cache 1;
    }
    
    if ($request_uri ~* "/(cart|checkout|my-account)/*$") {
        set $skip_cache 1;
    }

    if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {
        set $skip_cache 1;
    }

    location = /favicon.ico {
        log_not_found off;
        access_log off;
    }
    location = /robots.txt {
        allow all;
        log_not_found off;
        access_log off;
    }

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/run/php/php7.2-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;

        fastcgi_cache_bypass $skip_cache;
        fastcgi_no_cache $skip_cache;

        fastcgi_cache yourdomainname.com;

        fastcgi_cache_lock on;
        fastcgi_cache_use_stale error timeout invalid_header updating http_500;
        fastcgi_cache_valid 200 302 60m;
        fastcgi_cache_valid 301 1h;
        fastcgi_cache_valid any 1m;
        fastcgi_pass_header Set-Cookie:Set-Cookie;
        fastcgi_pass_header Cookie;
        fastcgi_ignore_headers Cache-Control Expires Set-Cookie;
        fastcgi_cache_background_update on;

        add_header X-Cache $upstream_cache_status;

        add_header Content-Security-Policy "img-src * 'self' data: blob: https:; default-src 'self' https://www.googletagmanager.com https://*.google-analytics.com https://www.yourdomainname.com https://*.googleapis.com https://*.gstatic.com https://*.gravatar.com https://*.w.org data: 'unsafe-inline' 'unsafe-eval';" always;
        add_header X-Xss-Protection "1; mode=block" always;
        add_header X-Frame-Options "SAMEORIGIN" always;
        add_header X-Content-Type-Options "nosniff" always;
        add_header Access-Control-Allow-Origin "https://www.yourdomainname.com";
        add_header Referrer-Policy "origin-when-cross-origin" always;
        add_header Strict-Transport-Security "max-age=31536000; includeSubdomains; preload";
    }

    location ~*  \.(jpg|jpeg|png|gif|ico)$ {
        expires 365d;
        add_header Cache-Control "public";
    }

    location ~* \.(?:css|js)$ {
        expires 7d;
        add_header Cache-Control "public";
    }

    location ~* \.(?:eot|woff|woff2|ttf|svg|otf) {
        expires 30d;
        add_header Cache-Control "public";

        types     {font/opentype otf;}
        types     {application/vnd.ms-fontobject eot;}
        types     {font/truetype ttf;}
        types     {application/font-woff woff;}
        types     {font/x-woff woff2;}  
    }
}

Now edit the /etc/nginx/nginx.conf file and change the value of keepalive_timeout directive to 650s and save the file.

Connect to Cloud SQL

Next edit the WordPress config file by issuing the following command

sudo nano ~/yourdomainname.com/public/wp-config.php

As the instances are created dynamically you ned to connect to Cloud SQL using Cloud SQL proxy or with Private IP.

Using Cloud SQL proxy

Change hostname to 127.0.0.1

Using Private IP

Go to your Cloud SQL Instance and enable Private IP.

Change hostname to PRIVATE_IP_ADDRESS

While using Private IP, make sure you are using the same VPN network.

Below define('DB_COLLATE', ''); add the following

define('FORCE_SSL_ADMIN', true);
if (strpos($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') !== false)
    $_SERVER['HTTPS']='on';

Create Instance Template

Next, stop the VM Instance and go to Compute Engine >> Images and click Create Image.

In Name enter a unique name

In Source select Disk

In Source Disk select the disk of your VM Instance

Click Create

Load Balancing Create Image

Once the Image is created go to Compute Engine >> Instance templates and click Create instance template

In Name enter name of the template

In Machine type choose 1 vCPU 3.75 GB RAM

In the Boot Disk click Change and click the Custom images tab.

Choose the Image that you created earlier

In the Boot disk type select SSD persistent disk

Click Select

In Identity and API access choose Allow full access to all Cloud APIs

In Firewall check both Allow HTTP traffic and Allow HTTPS traffic

Cloud SQL Proxy connection

If you are using the Private IP address to connect to Cloud SQL, you can skip the startup script.

In the Management tab find the Startup script and enter the following

#! /bin/bash
sudo apt-get update
sudo apt-get install mysql-client
wget https://dl.google.com/cloudsql/cloud_sql_proxy.linux.amd64 -O cloud_sql_proxy
chmod +x cloud_sql_proxy
sudo mkdir /cloudsql; sudo chmod 777 /cloudsql
./cloud_sql_proxy -instances=INSTANCE_CONNECTION_NAME=tcp:3306

Replace the INSTANCE_CONNECTION_NAME with your Cloud SQL connection name

In the Networking tab make sure Premium is selected in Network Service Tier

Click Create

Load Balancing Create Instance Template

Create a Managed Instance Group

Goto Compute Engine >> Instance groups and click Create instance group

In Name enter name

In Location choose Single-zone

In Region choose your preferred region

Click Specify port name mapping

In Port name enter http and in Port numbers enter 80

In Group type choose Managed instance group

In Instance template select the instance template you just created

Leave everything to default and click Create

Load Balancing Create Instance Group

Reserve Global Region IPv4 and IPv6 Address

Go to VPC network >> External IP addresses and click Reserve Static IP Address

In Name enter a name for IPv4 address

In Network Service Tier choose Premium

In IP version choose IPv4

In Type choose Global

Click Reserve

Again click Reserve Static IP Address

In Name enter a name for IPv6 address

In Network Service Tier choose Premium

In IP version choose IPv6

In Type choose Global

Click Reserve

Create Load Balancer

Go to Network Services >> Load Balancing and Click Create Load Balancer

In the HTTP(S) Load Balancing click Start Configuration

Create Load Balancer

Backend configuration

Enter a name for your Load Balancer and click Backend configuration

In Backend services & backend buckets select Backend service >> Create backend service

Enter a name for your backend service

In Backend Type choose Instance group

In Backends select the Instance group you created

In Port numbers enter 80

In Balance mode choose Utilization

Click Done

Check Enable Cloud CDN

Load balancing create backend service

Create Health Check

In Health Check click create health check

In Name enter a health check name

In Protocol select TCP

In Port enter 80

In Proxy protocol select None

In Check Interval enter 10

In Timeout enter 5

In Healthy threshold enter 2

In Unhealthy threshold enter 3

Click Save and Continue

Load Balancing Health Check

Frontend Configuration

Enter a name for your IPv4 frontend configuration

In Protocol select HTTPS

In IP version select IPv4

In IP address select the IP4 address you reserved

Load balancing Frontend configuration

In Certificate select Create Certificate

Enter a name for your certificate

In Create mode choose to Create Google-managed certificate

In Domains enter *.yourdomainname.com

Load Balancing Google Managed SSL Certificate

This setting will issue a Google managed Let’sEncrypt Certificate.

Attention: Once you have created a certificate it will be in the PROVISION status. Once the certificate is ACTIVE, you’ll have SSL issues for a few minutes with the error message ERR_SSL_VERSION_OR_CIPHER_MISMATCH. It took 15 minutes for mine to have everything up and running.

Uploading your own Certificate

To upload your own certificate, In Create mode choose to Upload my certificate

Here we use the Let’s Encrypt SSL certificate as an example

If you haven’t setup SSL in your VM instance, please check Installing SSL in Google Cloud Platform

SSH your VM Instance and enter the following commands and copy all contents

sudo nano /etc/letsencrypt/live/yourdomainname.com/fullchain.pem

In Public key certificate copy and paste the contents of fullcahain.pem file

sudo nano /etc/letsencrypt/live/yourdomainname.com/cert.pem

In Certificate chain copy and paste the contents of cert.pem file

sudo nano /etc/letsencrypt/live/yourdomainname.com/privkey.pem

In Private key  copy and paste the contents of privkey.pem file

Click Create

Load Balancing Upload SSL Certificate

Now in Frontend configuration click Done

Click Add Frontend IP and Port

Enter a name for your IPv6 frontend configuration

In Protocol select HTTPS

In IP version select IPv6

In IP address select the IPv6 address you reserved

In Certificate select the certificate you just created

Click Done

That’s all now your Backend and Frontend are configured

Configure DNS and Setup Cloud CDN

Click Create

Now Goto Network services >> Cloud DNS and click your domain name

Edit the A record and replace the IPv4 address with your newly reserved IPv4 address.

Click Add record set

In Resource record type select AAAA record

Enter the IPv6 address that you reserved

Goto Goto Network services >> Cloud CDN and click Add origin

In Origin select the Load balancer you just created.

Click Add

Now go to Network services >> Load Balancing and wait for 10 – 15 minutes for the Load Balancing settings to propagate. Once done you will see a green checkmark which indicates everything is fine.

Next you can set up Cloud Armor to secure your application.

That’s all, now your Load Balancer is configured to scale your website horizontally with Nginx web server

18 Comments

  1. I have a nginx bitnami application. did not succeed with your tutorial, could you do one specifically for bitnami?

    • Cloudbooklet Reply

      Bitnami configuration does not support this Load Balancing setup, because for this setup to work the database and media files must be separated from the VM instance to Cloud Storage and Cloud SQL.

  2. Thank you for this great tutorial. I saw and test it but it doesn`t work with the WordOps Installation 🙁

    Best

  3. Dear
    Cloudbooklet I followed each and every steps my cloud sql database establish my website ready but when I follow you HTTPS load balancer tutorial at the end I face

    Error: Server Error
    The server encountered a temporary error and could not complete your request.
    Please try again in 30 seconds.

    I don’t know what mistake I did could you please tell me how can I fix this problem.

    • There are many reasons for this error.

      • 1. Load Balanncer changes propagation takes around 10-20 min so you can try checking after 20 min from the setup completed.
      • 2. Nginx configuration does not make a 200 response, so the health check is not passed.
      • 3. Some other technical configuration issue.

      This tutorial is using Nginx, but you can try using Apache which will be easier than configuring Nginx if you can’t solve this issue.

  4. Mohsin Ahmed Reply

    I’ve setup my website using your wordpress guide. Installed Nginx,PHP7.3! Cloud sql, storage is running. Configured ssl, fast cgi cache and the load balancer. 1. But when i try to access http://mysite.com http not redirecting to https. Can you please help me out here.
    2. I’m using own ssl (created in vmas) in load balancer frontend configuration. As the server license expire after 3 months, do i have to update the ssl cert in load balancer after 3 months.
    3. Server getting down and can’t access live site frequently, is it load balancer related issue?
    Thank you for your tutorial!

  5. Hello Sir,
    First of all I must say you have written a great article, covering every aspect and minor detail, there was about setting up a GCLB.
    I have used your guide to set up a LAMP server, that sits behind an nginx proxy server. Every thing is working fine under http load balancing but when I deployed https load balancer using the steps you provided, rest of the things are working great except for uploading video file (of 1gb). The same file is being uploaded perfectly fine on http load balancer.
    The video uploading get stuck at around 60%. Upon inquiring network tab in inspect option on google chrome, it says net::ERR_HTTP2_PING_FAILED.
    The only difference in your deployment and mine is that you are using ipv4, ipv6 addresses and CDN is enabled but I am only using ipv4 for now without CDN.
    Any help will be highly appreciated.
    Best Regards,
    -Shams

    • Hi shams, did you solve your issue? It happens that we have the same ERR_HTTP2_PING_FAILED in the same configuration as yours. It does not happen every time, but for one of our customer. Any help would be great. Thanks.

  6. Hi,
    First of all, thanks for providing such a great tutorial.
    I followed everything as it is but there seems to be some error.
    The server throws up 502 Bad Gateway.
    I did sudo nginx -t and the output was: [warn] no “fastcgi_cache_key” for “fastcgi_cache” in /etc/nginx/nginx.conf:70
    My URL is: https://gamzo.in
    Please have a look.

    Thanks again!

    • Last few logs are:
      2020/04/11 04:04:24 [error] 23111#23111: *1087 directory index of “/home/geekhub762/gamzo.in/public/” is forbidden, client: 192.0.101.226, server: gamzo.in, request: “HEAD / HTTP/1.1”, host: “gamzo.in”

      2020/04/11 04:54:39 [error] 23111#23111: *1397 FastCGI sent in stderr: “PHP message: WordPress database error Unknown column ‘wp_’ in ‘field list’ for query SELECT wp_” while reading response header from upstream, client: 27.60.196.254, server: gamzo.in, request: “POST /wp-admin/setup-config.php?step=2 HTTP/2.0”, upstream: “fastcgi://unix:/run/php/php7.3-fpm.sock:”, host: “gamzo.in”, referrer: “https://gamzo.in/wpadmin/setup-config.php?step=1”

      • Hi Aryan.

        Go to your NGINX configs @ /etc/nginx/nginx.conf

        Add this to your file

        ##
        # Cache Settings
        ##
        fastcgi_cache_key “$scheme$request_method$host$request_uri”;
        add_header Fastcgi-Cache $upstream_cache_status;
        fastcgi_cache_use_stale error timeout invalid_header http_500;
        fastcgi_ignore_headers Cache-Control Expires Set-Cookie;

  7. RAMAKANTH RAO POGAKU Reply

    I want you to setup the load balancing for my website. Please let me know your service charges

  8. Rohan Yoon Reply

    I have an existing WP site running on CentOS7 with whm/cpanel on GCE, got to know that it’s impossible that cpanel hosted website is not suitable for autoscaling.

    If I manage to set a new wp site following above steps, do you have any documents or articles talk about how to move(or migrate) an existing un-autoscalable WP site to autoscalable WP site? if not, are you able to provide some guidance for me please? Thank you

  9. Christian Fleidl Reply

    I followed the steps as shown in the tutorial, I configured the virtualhost in Nginx, but when I load the WordPress installation for the first time, I get the error ERR_CONNECTION_REFUSED

    What could be happening?

Write A Comment

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.