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.
Prerequisites
- Your Compute Engine Instance running.
- For setting up Compute Engine, see the Setting up Compute Engine Instance.
- Initial Server Setup on Google Cloud.
- Set up Cloud DNS, see the Setting up Google Cloud DNS for your domain.
- 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.
15 Comments
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.
Thank you, very happy to hear this post can help you. I will try to make a post you have requested
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/
–resolvewww.zhyz.ru:443:127.0.0.1
-k Have a responseaccess.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”
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.
Please configure your wp-config.php as mentioned in the post. Thank you
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.
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 😉
You are very welcome, also thank you for checking out cloudbooklet
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
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 :/
You’ll also have to add a fix to wp-config.php for wp admin login to work:
if ( $_SERVER[‘HTTP_X_FORWARDED_PROTO’] == ‘https’ )
{
$_SERVER[‘HTTPS’] = ‘on’;
$_SERVER[‘SERVER_PORT’] = 443;
}
For preventing redirection loop I have add the snippet in wp-config.php file. You can check that section.
Great tutorial! Very detailed and clean explanation! Lots of thanks!
Getting 504 gateway time out on this tutorial.
I am using the same setup on some sites, it works fine. You missed something