Compute Engine Google Cloud

Install WordPress with Nginx Reverse Proxy to Apache on Ubuntu 18.04 – Google Cloud

Install WordPress with Nginx Reverse Proxy to Apache with Ubuntu 18.04 on Google Cloud Platform with PHP 7.3, Nginx, Apache, Let’s Encrypt SSL, Cloud SQL (MySQL 5.7).

We already have covered how to install and set up WordPress with Nginx and with Apache. In this guide you are going to learn how to set up WordPress with the two most popular web servers Nginx and Apache.

Checkout how to install WordPress with Nginx + Apache with Docker and Docker Compose.

By this approach you will get the the benefits of Apache and Nginx for fast loading websites.

Choose Best Hosting for your Business

PlatformReviewsPricing
Siteground★★★★★$3.95
Kinsta – Google Cloud★★★★★$30

Prerequisites

  1. Your Compute Engine Instance running.
  2. For setting up Compute Engine, see the Setting up Compute Engine Instance.
  3. Initial Server Setup on Google Cloud.
  4. Set up Cloud DNS, see the Setting up Google Cloud DNS for your domain.
  5. Google Cloud SQL Setup, see Setup Cloud SQL and connect with Compute Engine.

Install Apache

Once you have your VM instance up and running and the server setup is completed, you can proceed to install Apache.

sudo apt install apache2

Now you need to configure Apache to listen on different port because Nginx will be placed in front of Apache which listens for HTTP and HTTPS traffic.

Configure Apache on Different Port

Now you can configure Apache to listen on port 8081. To configure this you need to change the port value in ports.conf

sudo nano /etc/apache2/ports.conf

Change port to 8081. So, you will have the port look like this

Listen 8081

Hit Ctrl + X followed by Y and Enter to save and exit the file.

Install Nginx

Now you are good to install Nginx.

sudo apt install nginx

Once the installation is complete you can check the status of both web servers using these commands.

sudo service apache2 status
sudo service nginx status

You should see both servers are active and running.

Setup your website

Your website will be located in the html directory and have the following structure.

Replace yourdomainname.com with your original domain name.

/var/www/html
 -- yourdomainname.com
 ---- public

The public directory is your website’s root directory. Go ahead and create those directories.

sudo mkdir -p /var/www/html/yourdomainname.com/public

Set up Apache Virtual Host

Once Apache listens on port 8081, you can proceed to setup your Apache virtual host.

Remove the default virtual host first.

sudo a2dissite 000-default

Create new configuration.

sudo nano /etc/apache2/sites-available/yourdomainname.conf

Paste the below Virtual Host configuration in your file.

<VirtualHost *:8081>
    ServerName yourdomainname.com

    DocumentRoot /var/www/html/yourdomainname.com/public

    <Directory />
        Options FollowSymLinks
        AllowOverride None
    </Directory>

    <Directory /var/www/html/yourdomainname.com/public>
        Options Indexes FollowSymLinks MultiViews
        AllowOverride All
        Order allow,deny
        allow from all
        Require all granted
    </Directory>
</VirtualHost>

Hit Ctrl + X followed by Y and Enter to save and exit the file.

Enable the new configuration.

sudo a2ensite yourdomainname.conf

Replace your yourdomainname with the name of the file you created above.

Enable Apache rewrite mode.

sudo a2enmod rewrite

Restart Apache.

sudo systemctl restart apache2

Configure Nginx

If you have firewall enabled, make sure the HTTP and HTTPS ports are allowed.

sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'

Next, open the Nginx configuration file, which can be found at /etc/nginx/nginx.conf

sudo nano /etc/nginx/nginx.conf

The worker_processes directive is the amount of CPU cores your instance. In my case, this is 1.

Uncomment the multi_accept directive and set it to on.

Lower the keepalive_timeout directive to 15.

For security reasons, you should uncomment the server_tokens directive and ensure it is set to off.

Add the new client_max_body_size directive below the server_tokens and set the value to 64m.

Uncomment the gzip_proxied directive and set it to any, uncomment the gzip_comp_level directive and set it to the value of 2 and finally uncomment the gzip_types directive.

Now you need to add a catch-all block to the Nginx configuration.

Find the line with include /etc/nginx/sites-enabled/*;

Below this line add the following

server { 
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
return 444;
}

In order for Nginx to correctly serve PHP you also need to ensure the fastcgi_param SCRIPT_FILENAME directive is set, otherwise, you will receive a blank white screen when accessing any PHP scripts. So open fastcgi_params file by issuing this command

sudo nano /etc/nginx/fastcgi_params

Add the following at the end of the file

fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

That’s all, this is the basic Nginx configuration, hit CTRL+X followed by Y to save the changes.

Now you can remove the default server blocks from Nginx.

sudo rm /etc/nginx/sites-available/default
sudo rm /etc/nginx/sites-enabled/default

Hit CTRL+X followed by Y to save the changes and then test the Nginx configuration and restart Nginx.

Set up Nginx as Reverse Proxy

Once you have Nginx configured, you can setup reverse proxy by creating new server blocks.

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

Paste the below configurations in the file.

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

    server_name www.yourdomainname.com;

    root /var/www/html/yourdomainname.com/public;
    index index.php;

    location / {
        try_files $uri @apache;
    }

    location ~ ^/\.user\.ini {
        deny all;
    }

    location ~*  \.(svg|svgz)$ {
        types {}
        default_type image/svg+xml;
    }

    location = /favicon.ico {
        log_not_found off;
        access_log off;
    }

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

    location @apache {
        proxy_set_header X-Real-IP  $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Host $host;
        proxy_pass http://127.0.0.1:8081;
    }

    location ~[^?]*/$ {
        proxy_set_header X-Real-IP  $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Host $host;
        proxy_pass http://127.0.0.1:8081;
    }

    location ~ \.php$ {
        proxy_set_header X-Real-IP  $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Host $host;
        proxy_pass http://127.0.0.1:8081;
    }

    location ~/\. {
        deny all;
        access_log off;
        log_not_found off;
    }
}

Hit Ctrl + X followed by Y and Enter to save and exit the file.

Enable the configuration.

sudo ln -s /etc/nginx/sites-available/yourdomainname.conf /etc/nginx/sites-enabled/yourdomainname.conf

Check the configuration and restart Nginx.

sudo nginx -t
sudo service nginx restart

Now Nginx is placed before Apache as a reverse proxy.

Install and configure PHP

sudo apt install php7.2 libapache2-mod-php php7.2-common php7.2-mysql php7.2-xml php7.2-xmlrpc php7.2-curl php7.2-gd php7.2-imagick php7.2-cli php7.2-dev php7.2-imap php7.2-mbstring php7.2-opcache php7.2-soap php7.2-zip php7.2-redis php7.2-intl unzip -y

Modify PHP configurations by editing the php.ini file.

sudo nano /etc/php/7.2/apache2/php.ini

Hit F6 for search inside the editor and update the following values

upload_max_filesize = 32M 
post_max_size = 48M
memory_limit = 256M
max_execution_time = 600
max_input_vars = 3000
max_input_time = 1000

Hit CTRL+X and Y to save the configuration and check if the configuration is correct and restart Apache.

sudo service apache2 restart

Download WordPress

Now that your server software is configured, you can download and set up WordPress.

It is always recommended to get the latest version of WordPress from their website.

cd /var/www/html/yourdomainname.com/public
curl -LO https://wordpress.org/latest.tar.gz

This command will download the latest version and it needs to be extracted.

tar xzvf latest.tar.gz

Now, you can copy the entire contents of the directory into our document root.

sudo cp -a /var/www/html/yourdomainname.com/public/wordpress/. /var/www/html/yourdomainname.com/public

Next cleanup your root directory by deleting the wordpress folder and the downloaded tar file.

sudo rm -r /var/www/html/yourdomainname.com/public/wordpress
sudo rm -f /var/www/html/yourdomainname.com/public/latest.tar.gz

Set correct permissions for the your website directory

sudo chown -R www-data:www-data /var/www/html/yourdomainname.com/public
sudo chmod -R 755 /var/www/html/yourdomainname.com/public

Install Free Let’s Encrypt SSL Certificate

HTTPS
HTTPS is a protocol for secure communication between a server (instance) and a client (web browser). Due to the introduction of Let’s Encrypt, which provides free SSL certificates, HTTPS are adopted by everyone and also provides trust to your audiences.

HTTP/2
HTTP/2 is the latest version of the HTTP protocol and can provide a significant improvement to the load time of your sites. There really is no reason not to enable HTTP/2, the only requirement is that the site must use HTTPS.

sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install python-certbot-nginx

Now we have installed Certbot by Let’s Encrypt for Ubuntu 18.04, run this command to receive your certificates.

sudo certbot --nginx certonly

Enter your email and agree to the terms and conditions, then you will receive the list of domains you need to generate SSL certificate.

To select all domains simply hit Enter

The Certbot client will automatically generate the new certificate for your domain. Now we need to update the Nginx config.

Redirect HTTP Traffic to HTTPS with www in Nginx

Open your site’s Nginx configuration file add replace everything with the following. Replacing the file path with the one you received when obtaining the SSL certificate. The ssl_certificate directive should point to your fullchain.pem file, and the ssl_certificate_key directive should point to your privkey.pem file.

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

    server_name yourdomainname.com www.yourdomainname.com;

    return 301 https://www.yourdomainname.com$request_uri;
}

server {
    listen [::]:443 ssl http2;
    listen 443 ssl http2;

    server_name yourdomainname.com;

    ssl_certificate /etc/letsencrypt/live/yourdomainname.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomainname.com/privkey.pem;

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

    return 301 https://www.yourdomainname.com$request_uri;
}

server {
    listen [::]:443 ssl http2;
    listen 443 ssl http2;

    server_name www.yourdomainname.com;

    ssl_certificate /etc/letsencrypt/live/yourdomainname.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomainname.com/privkey.pem;

    root /var/www/html/yourdomainname.com/public;
    index index.php;

    location / {
        try_files $uri @apache;
    }

    location ~ ^/\.user\.ini {
        deny all;
    }

    location ~*  \.(svg|svgz)$ {
        types {}
        default_type image/svg+xml;
    }

    location = /favicon.ico {
        log_not_found off;
        access_log off;
    }

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

    location @apache {
        proxy_set_header X-Real-IP  $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Host $host;
        proxy_pass http://127.0.0.1:8081;
    }

    location ~[^?]*/$ {
        proxy_set_header X-Real-IP  $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Host $host;
        proxy_pass http://127.0.0.1:8081;
    }

    location ~ \.php$ {
        proxy_set_header X-Real-IP  $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Host $host;
        proxy_pass http://127.0.0.1:8081;
    }

    location ~/\. {
        deny all;
        access_log off;
        log_not_found off;
    }
}

The http2 value is all that is needed to enable the HTTP/2 protocol.

Now you have enabled SSL Hardening, created a Content Security Policy, X-XSS-Protection, Clickjacking, MIME Sniffing, Referrer Policy, Access Control Allow Origin.

These are some Nginx security tweaks by closing all areas of attacks.

Hit CTRL+X followed by Y to save the changes.

Check your configuration and restart Nginx for the changes to take effect.

sudo nginx -t
sudo service nginx restart

Renewing SSL Certificate

Certificates provided by Let’s Encrypt are valid for 90 days only, so you need to renew them often. Now you set up a cronjob to check for the certificate which is due to expire in next 30 days and renew it automatically.

sudo crontab -e

Add this line at the end of the file

0 0,12 * * * certbot renew >/dev/null 2>&1

Hit CTRL+X followed by Y to save the changes.

This cronjob will attempt to check for renewing the certificate twice daily.

Configure WordPress for Reverse Proxy

Now you need to configure WordPress for Reverse proxy to use HTTPS by adding the lines in the wp-config.php

If you leave these out, you will end up in the endless redirect loop.

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

Add these line to the top of the file below <?php

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

Now, you’re ready to force all your traffic to use HTTPS.

Setup WordPress Filesystem

Once the Installation is complete we need to set the method that WordPress should use to write to the filesystem. Since we’ve given the web server permission to write where it needs to, we can explicitly set the filesystem method to “direct”. Failure to set this with our current settings would result in WordPress prompting for FTP credentials when we perform some actions like WordPress update, plugin updates, file upload, etc. This setting can be added below the database connection settings in the configuration file.

Find the line define('DB_PASSWORD', 'password'); and paste the following line below it.

define('FS_METHOD', 'direct');

Hit Ctrl+X and Y to save your configuration file.

Install WordPress

Now you can do the famous 5 minute WordPress installation.

You will be prompted to enter your database, user, password, and hostname.

Enter the database name we created in Cloud SQL and the user assigned with the database with the password. Finally, enter the IP address of Cloud SQL as the hostname.

Checkout how to install WordPress with Nginx + Apache with Docker and Docker Compose.

Learn the most Advanced Techniques of WordPress with this easy to learn course now.

Conclusion

Now you have installed WordPress with Nginx as a reverse proxy to Apache and installed SSL certificate and connected to Cloud SQL.

Now you have a high performance WordPress installation with the benefits of Apache and Nginx.

Cloudbooklet builds a large collection of Linux based guides and tutorials on Cloud platforms like Google Cloud, AWS, Azure, DigitalOcean and more

10 Comments

  1. Khandakar Rifat Reply

    Thanks a lot for this Detailed Tutorial, It helped me to set up my Hybrid Server.

    I have a request, please help us publishing an in-depth tutorial for Install WordPress with Nginx Reverse Proxy to Apache + Redis + MariaDB on Ubuntu 18.04

    A details guide to Setup & Configuration. Please help us.

    Thanks again for the awesome guide.

  2. After I set up https, the website is no longer accessible, and I use cloudflare’s certificate. Open cdn website 522, close cdn website will not open.
    Use curl https://www.zhyz.ru/ –resolve www.zhyz.ru:443:127.0.0.1 -k Have a response
    access.log results
    127.0.0.1 – – [27/Mar/2020:08:11:11 +0800] “GET / HTTP/1.1” 444 0 “-” “curl/7.68.0”
    127.0.0.1 – – [27/Mar/2020:08:11:15 +0800] “GET / HTTP/1.1” 400 248 “-” “curl/7.68.0”
    127.0.0.1 – – [27/Mar/2020:17:09:59 +0800] “GET / HTTP/2.0” 302 0 “-” “curl/7.68.0”

  3. After setting up the server according to yuour instruction I am getting the folowing error:

    The page isn’t redirecting properly

    Please guide me to resolve the issue.

  4. Hi,

    thanks for your great tutorial, i moved a site from an old server to this solutions.
    my only problem is with permalink, it doesn’t work anymore, and i don’t understand why.

  5. Jorge Ramirez Reply

    Thank you so much for this tutorial.

    I was trying for a whole day many other tutorials found on the internet to try to set up this environment (WordPress on Apache with a reverse proxy Nginx with SSL) and this was the only one that has worked 100%.

    I had a problem with the wordpress images that wouldn’t load but now it is completely functional.

    I ow you a beer or something 😉

  6. Dave Parkinson Reply

    Terrific tutorial!

    One question through – what modifications to the above configuration would be required if nginx resides on a single server dedicated to directing http and https requests to numerous upstream wordpress servers (ie – servers running apache2, php, wordpress).
    Thanks.
    Dave

  7. Adam Marsono Putra Reply

    Thank you for great explanation, however I’m trying xampp for the apache and database. Gonna try that out, I hope it works. One question though, it doesn’t need port 8081 to be public right? Because that’s my problem so far :/

Write A Comment

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

If you find this helpful? Support me!
Buy me a coffee Donation Please buy me a coffee