Host Multiple Web Applications on Single Google Compute Engine Instance Using Apache Reverse Proxy

Prasad Kothavale
6 min readApr 1, 2018

--

As of today, Google App Engine does not provide shared CPU instances hence it is overkill for small less resource consuming websites. One option to save money can be using shared CPU Google Compute Engine which costs less than App Engine.

Scenario: There are two websites abc.com and xyz.com, both the websites are to be hosted on one f1-micro (1 vCPU, 0.6 GB memory) compute engine instance which costs around $5/month.

Following diagram explains the solution to be achieved

This article is focused to setup Apache Reverse Proxy and does not cover setting up your web application as various tech stacks have their own setup procedures.

Setup Compute Engine

Create a compute engine

https://console.cloud.google.com/launcher/details/google-cloud-platform/compute-engine. In this article shell commands are based on Debian based compute engine.

Always keep track on billing section, set daily spend limits. Accidentally setting high configurations can shoot your bill.

Install packages required to run web application:

Install all the packages required to run the web application (e.g — Node.JS or Flask depending on tech stack of the web application). Run your web applications (abc and xyz) on any port other than 80 and 443. In this example abc will be on port 3000 and xyz will be on port 3001

Install Apache HTTP server:

sudo apt install apache2

Start Apache HTTP server:

sudo service apache2 start

This will start Apache HTTP server on port 80 and will server files from /var/www/html location.

Add firewall rules to open ports 3000 and 3001

Ports are opened for debugging purpose only. Once setup is done correctly you can close ports 3000 and 3001 for external traffic

Login in your Google cloud web console https://console.cloud.google.com

hamburger menu > VPC Networks > Firewall rules

Add below rule to open the port

Network: default
Priority: 1000
Direction: Ingress
Action on match: Allow
Source filters:
IP ranges: 0.0.0.0/0
Protocols and ports: tcp:3000

Repeat same steps for port 3001

Test your setup

Find external IP address of your compute engine in hamburger menu > Compute Engine > VM Instances. Check external IP of your VM instance (e.g. — 35.180.###.###). Make sure below three URLs are accessible from your browser:

http://35.180.###.###This should load Apache HTTP default page.
http://35.180.###.###:3000 — This should load abc web application.
http://35.180.###.###:3001 — This should load xyz web application

If above three URLs are working then it is good to proceed with next step to map domains.

Map Domains in Google Cloud DNS

Considering abc.com and xyz.com are domain names purchased from some domain name provider, these domains are now required to point to VM instance created above.

Create DNS zone as per instructions given in:

https://cloud.google.com/dns/quickstart.

Create two DNS zones, one for abc.com and other for xyz.com. On completion DNS zone would look similar to below:

hamburger menu > Network Services > Cloud DNS
hamburger menu > Network Services > Cloud DNS > abc-zone

Login to your domain name provider (from whom you have purchased domain names abc.com and xyz.com) and map the name servers (Type: NS, e.g. — ns-cloud-e1.googledomains.com … all the four). Mapping requires propagation time (48 hours as mentioned by domain provider but usually happens in 2 hours) to get domain name repointed to VM instance.

Verify whether domain name is pointed to VM instance

Open http://abc.com or http://xyz.com in web browser it should load Apache HTTP server’s default page. You can also try hitting port 3000 and 3001 if still kept open, both the applications will load by any of the URL (http://abc.com:3001 will load xyz, no need to worry about this now it will be configured in next steps)

If above domain name pointing is working then it is good to proceed with next step to configure reverse proxy.

Configure Apache HTTP Server for Reverse Proxy

This is the main step which will route requests to appropriate web application by host names. In this step you will create virtual hosts (vhost) and map them using reverse proxy.

Configure virtual hosts in /etc/apache2/sites-enabled/000-default.conf as below:

<VirtualHost *:80>
ServerAdmin your.name@something.com
DocumentRoot /var/www/html
ServerName 35.180.###.###
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
LogLevel error

<Location “/”>
Order deny,allow
Deny from all
Allow from all
</Location>
</VirtualHost>
<VirtualHost *:80>
ServerAdmin your.name@something.com
ServerName xyz.com
ServerAlias www.xyz.com
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
LogLevel error
ProxyPreserveHost on
ProxyPass “/” “http://127.0.0.1:3001/"
ProxyPassReverse “/” “http://127.0.0.1:3001/"
</VirtualHost>
<VirtualHost *:80>
ServerAdmin your.name@something.com
ServerName abc.com
ServerAlias www.abc.com
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
LogLevel error

ProxyPreserveHost on
ProxyPass “/” “http://127.0.0.1:3000/"
ProxyPassReverse “/” “http://127.0.0.1:3000/"
</VirtualHost>

Run below commands to enable mod_proxy_http

sudo a2enmod ssl
sudo a2enmod proxy
sudo a2enmod proxy_balancer
sudo a2enmod proxy_http
sudo service apache2 restart

Verify reverse proxy is set correctly

Open http://abc.com and http://xyz.com in your browser and check both the websites are loading as expected, it should not load Apache HTTP server’s default page now.

If above verification is works, congratulations! You have successfully hosted two web applications on one VM instance. If you want to set up HTTPS (SSL) please proceed with next step.

Setup HTTPS (SSL) Connections

Enable Apache SSL module

sudo a2enmod ssl
sudo a2ensite default-ssl
sudo service apache2 restart

Use CertBot to use SSL certificates from lets-encrypt

https://certbot.eff.org/lets-encrypt/debianjessie-apache

Install certbot

sudo apt-get install python-certbot-apache -t jessie-backports

Autoconfigure certbot

sudo certbot --authenticator webroot --installer apache

During configuration enter domain names: abc.com, www.abc.com, xyz.com, www.xyz.com. Provide webroot — location to public/static folder of your web application so that autoconfigure verifies your domain and server are linked.

Auto configure creates 000-default-le-ssl.conf file, configure all four vhost in same file.

For https access is required or optional select secure — make all request redirect to https.

Test auto renewal

(cron job will auto renew if following command is successful)

sudo certbot renew --dry-run

Auto renewal might fail as currently certbot do not support multiple virtual host. Please perform below manual step if auto renewal dry run fails.

Manual Steps

Edit generated /etc/apache2/sites-enabled/000-default-le-ssl.conf

<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName 35.180.###.###
ServerAdmin your.name@something.com
DocumentRoot /var/www/html
LogLevel errorErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
SSLCertificateFile /etc/letsencrypt/live/xyz.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/xyz.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf

<Location "/">
Order deny,allow
Deny from all
Allow from all
</Location>
</VirtualHost>
<VirtualHost *:443>
ServerName xyz.com
ServerAdmin your.name@something.com
LogLevel error
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
SSLCertificateFile /etc/letsencrypt/live/xyz.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/xyz.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
ServerAlias www.xyz.com

ProxyPreserveHost on
ProxyPass "/" "http://127.0.0.1:3001/"
ProxyPassReverse "/" "http://127.0.0.1:3001/"
</VirtualHost>
<VirtualHost *:443>
ServerName abc.com
ServerAdmin your.name@something.com
LogLevel error
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
SSLCertificateFile /etc/letsencrypt/live/xyz.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/xyz.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
ServerAlias www.abc.com

ProxyPreserveHost on
ProxyPass "/" "http://127.0.0.1:3000/"
ProxyPassReverse "/" "http://127.0.0.1:3000/"
</VirtualHost>
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
</IfModule>

Restart Apache http server

sudo service apache2 restart

Force redirect all HTTP traffic to HTTPS

If you want to force redirect http traffic to https like someone hitting http://abc.com will be forcefully redirected to https://abc.com, follow below steps:

Edit /etc/apache2/sites-enabled/000-default.conf

<VirtualHost *:80>
ServerAdmin your.name@something.com
DocumentRoot /var/www/html
ServerName 35.180.###.###

ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
LogLevel error

<Location "/">
Order deny,allow
Deny from all
Allow from all
</Location>
</VirtualHost>
<VirtualHost *:80>
ServerAdmin your.name@something.com
ServerName xyz.com
ServerAlias www.xyz.com

ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
LogLevel error

Redirect permanent "/" "https://xyz.com/"
</VirtualHost>
<VirtualHost *:80>
ServerAdmin your.name@something.com
ServerName abc.com
ServerAlias www.abc.com

ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
LogLevel error

Redirect permanent "/" "https://abc.com/"
</VirtualHost>

Test Auto Renewal

sudo certbot renew --dry-run

This time auto renewal should work. Verify hitting http://abc.com in browser it should redirect to https://abc.com

Congratulations! You have successfully configured HTTPS (SSL) and HTTP to HTTPS force redirect.

--

--