/ devops

Setting up Ghost with Apache and HTTPS

Recently, I was working on a long due initiative to move www.codersbistro.com from Wordpress to Ghost. Why, because I love the new web and honestly I hate Wordpress. Well, we can talk about that later, but the important point is that I had to do some good amount of groundwork.

This blog is not to explain the peculiarities of the migration, but more of the work spent on setting up Ghost and using Apache as a reverse proxy, a forward proxy, an SSL tunnel to be used with Ghost. Ghost comes with the essential setup documentation to be used with NGINX, but it lacks some of the features of forward proxying that I needed for the setup. This guide covers those aspects, but I believe the guide will be helpful for anyone using Apache. Let's look into it.

1. Setting up Ghost

Ghost Team has done some awesome work in providing the neatest way to install and manage Ghost platform. If you are interested in setting up Ghost, I would recommend you to check out the latest install configuration here.

2. Setting up the Apache server

The following section walks you through the process of installing the required packages in the operating system. Once, this is done, we will walk through the configuration guide.

2.1 Updating the operating system

Well, most of the *NIX based operating system comes shipped with Apache Web server, but we would definitely want to upgrade the system and to ensure all the latest packages, especially the security patches are in place. I was using Ubuntu, so here it goes.

apt-get -y update
apt-get -y upgrade

2.2 Setting up the Essential Build Tools

We also need the build management tools to install certain things from source. So, let's get the latest build essentials tools.

apt-get install -y build-essentials

2.3 Installing Apache

Installing Apache is a piece of cake. Unless you explicitly require some out of world feature to be added, installing apache from package manager is just a simple command.

apt-get install -y apache2

2.4 Setting up additional modules and dependencies

Depending on the *NIX operating system you are using, you might be required to install some additional modules and dependencies. For example, if you are using the latest update and the above commands were successful, you would not require and able to locate the libapache2-mod-proxy-html. This module implements the proxy/gateway for Apache HTTP server, supporting a number of protocols and load balancing features. Let's try.

apt-get install -y libapache2-mod-proxy-html libxml2-dev

3. Configuring Apache to reverse proxy connections

As a first step, we need the www.codersbistro.com to serve the Ghost application. So, we require setting up the reverse proxy.

3.1 Activating the modules

As a very first step, we need to ensure all the required modules are installed and if not get the ones. With the following command, we get to see all the installed modules.

a2enmod

The output for my setup looks like this:

Your choices are: access_compat actions alias allowmethods asis auth_basic auth_digest auth_form authn_anon authn_core authn_dbd authn_dbm authn_file authn_socache authnz_fcgi authnz_ldap authz_core authz_dbd authz_dbm authz_groupfile authz_host authz_owner authz_user autoindex buffer cache cache_disk cache_socache cgi cgid charset_lite data dav dav_fs dav_lock dbd deflate dialup dir dump_io echo env expires ext_filter file_cache filter headers heartbeat heartmonitor ident include info lbmethod_bybusyness lbmethod_byrequests lbmethod_bytraffic lbmethod_heartbeat ldap log_debug log_forensic lua macro mime mime_magic mpm_event mpm_prefork mpm_worker negotiation proxy proxy_ajp proxy_balancer proxy_connect proxy_express proxy_fcgi proxy_fdpass proxy_ftp proxy_html proxy_http proxy_scgi proxy_wstunnel ratelimit reflector remoteip reqtimeout request rewrite sed session session_cookie session_crypto session_dbd setenvif slotmem_plain slotmem_shm socache_dbm socache_memcache socache_shmcb speling ssl status substitute suexec unique_id userdir usertrack vhost_alias xml2enc

**Which module(s) do you want to enable (wildcards ok)?**

You can use the following command to install the required modules.

a2enmod proxy
a2enmod proxy_http
a2enmod proxy_ajp
a2enmod rewrite
a2enmod deflate
a2enmod headers
a2enmod proxy_balancer
a2enmod proxy_connect
a2enmod proxy_html

3.2 Setting up the proxy configuration

Apache lets us define a number of Virtual Host files for various proxying configurations. Apache ships with a default virtual host configuration file 000-default.conf in /etc/apache2/sites-enabled/. We can go ahead with disabling this and create a new configuration file.

Let's disable this configuration file

a2dissite 000-default

Let's create a new virtual host configuration file for our Ghost setup.

nano /etc/apache2/sites-available/ghost-config-file.conf

and add the following set of lines

<VirtualHost *:80>
  ServerAdmin webmaster@localhost
  DocumentRoot /var/www/
  ErrorLog ${APACHE_LOG_DIR}/error.log
  CustomLog ${APACHE_LOG_DIR}/access.log combined
  ProxyPreserveHost On
  # Servers to proxy the connection, or
  # List of application servers Usage
  ProxyPass / http://localhost:2368/
  ProxyPassReverse / http://localhost:2368/
  ServerName codersbistro.com
  ServerAlias www.codersbistro.com
</VirtualHost>

We are telling Apache here to listen on port 80 and proxy all the requests to the downstream application at localhost:2368. In this particular case, Ghost is running on port 2368.

Let's enable the virtual host and restart Apache.

a2ensite ghost
/etc/init.d/apache2 restart

This will start Apache at port 80. Remember to stop any other service running on port 80. In my setup, I had been using NGINX before, so I went ahead and stopped the service as follows.

service nginx stop

Navigate to http://yourdomain.com/ to verify if apache is serving content fine.

4. Enable HTTPS

Setting up HTTPS is mostly optional, but with new security standards, it is becoming increasingly important to enable HTTPS support for your site.

Let's get started by enabling the SSL module for Apache.

a2enmod ssl

SSL configuration would require us to provide a valid SSL certificate for the identity verification of the site domain name. I assume you have a valid certificate with you. You can check-out here to generate a self-signed certificates or here for generating the Open CA certificates. Please note that a self-signed certificate will not be trusted by the client browsers and will be treated unsafe.

Now we need to create a new secondary virtual host file

nano /etc/apache2/sites-available/ghost-ssl-config-file.conf

and add the following lines with the pointers to the generated SSL certificates.

<VirtualHost *:443>
        ServerAdmin webmaster@localhost
        DocumentRoot /var/www/
        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined
        SSLEngine On
        # Set the path to SSL certificate
        # Usage: SSLCertificateFile /path/to/cert.pem
        SSLCertificateFile /etc/apache2/ssl/ca.crt
        SSLCertificateKeyFile /etc/apache2/ssl/ca.key
        ProxyPreserveHost On
        ProxyPass /var/www/ http://localhost:2368/
        ProxyPassReverse /var/www/ http://localhost:2368/
        ServerName codersbistro.com
        ServerAlias www.codersbistro.com
</VirtualHost>

Enable the new virtual host file

a2ensite ghost-ssl

Now, restart the Apache service to bring the new host file into effect.

/etc/init.d/apache2 restart

5. Setting up the ghost in a sub-path

As part of my setup of Ghost, I wanted ghost to be installed in a sub-path of the domain, so that ghost is served on www.codersbistro.com/blog rather than www.codersbistro.com. If this is not what you want, please skip through this section.

To enable ghost to be served on a sub-path, open the ghost configuration file config.production.json located in you ghost installation folder.

nano /var/www/ghost/config.production.json

and edit the url key to point to the complete address of your blog including the sub-path. If you enabled SSL, please make sure to use the full URL including HTTPS. This will instruct Ghost to server all the requests over HTTPS. All the requests over HTTP will be redirected to HTTPS.

"url": "https://www.codersbistro.com/blog/"

6. Setup request forwarding for web root.

If you have not setup your ghost blog in a sub-path, you can skip this section. If you have, you might want to enable the request forwarding from the web root to the blog sub-path. For my setup, that meant I would need to forward the request coming to https://www.codersbistro.com/ to https://www.codersbistro.com/blog/.

To enable request forwarding in Apache, open the virtual host configuration file for HTTP and HTTPS

nano /etc/apache2/sites-available/ghost-ssl-config-file.conf
nano /etc/apache2/sites-available/ghost-config-file.conf

and add the following rewrite rules

  RewriteRule "^/$" "http://localhost:2368/blog/" [P]

With the above rewrite rule, we are instructing Apache to forward proxy the request coming to '/' to '/blog'. Note that we are not redirecting the request in this case and rather serving the blog content at the root.

Don't forget to restart the Apache to enable the updated configurations.

/etc/init.d/apache restart

7. Setting up default redirects to HTTPS

Now with the SSL enabled, any client requesting a secured server access via https:// will be able to connect securely, but the client connecting via http:// will still be connecting via an unsecure connection.

It makes sense to setup a default redirect from HTTP to HTTPS. To set one up, open the virtual host file for the Ghost setup

nano /etc/apache2/sites-available/ghost-config-file.conf

and add a redirect to the HTTPS apache conf file. You can move all other redirect/re-write rules if any to the SSL conf file as well.

<VirtualHost *:80>
  ServerAdmin webmaster@localhost
  DocumentRoot /var/www/
  ErrorLog ${APACHE_LOG_DIR}/error.log
  CustomLog ${APACHE_LOG_DIR}/access.log combined
  ProxyPreserveHost On
  # Servers to proxy the connection, or
  # List of application servers Usage
  RewriteEngine on
  Redirect permanent / https://www.codersbistro.com/
  #ProxyPass / http://localhost:2368/
  #ProxyPassReverse / http://localhost:2368/
  ServerName codersbistro.com
  ServerAlias www.codersbistro.com
</VirtualHost>

Don't forget to restart the Apache server again.

/etc/init.d/apache restart

8. Supressing HTTPS redirect loops.

HTTPS redirect loops is a scenario where 301/302 response is sent multiple times to the client with each request, hence setting up an indefinite loop. Now this may not be the case with your specific settings, but you may need it if you followed the above configurations strictly.

The Ghost configuration file config.production.json has a url property which defines the default property name to be used all across the blog including the sitemaps, robots, internal links and so. It should be set to use the HTTPS endpoint to ensure better SEO.

However, this will also force multiple redirects, since the above Apache configuration uses a proxy pass with the HTTP endpoint. To fix this, we need to instruct Ghost, that we have enabled HTTPS from the reverse proxy and Ghost need not worry.

To do so, we will update the Apache configuration to add a special header to the ssl configuration file.

RequestHeader set X-Forwarded-Proto "https"

BONUS: For setting up enhanced SSL controls and hardening the SSL security controls, there is this nice article you can refer.

Love Hasija

Love Hasija

Full Stack Research Engineer, Software Architect | Helped build next generation software systems | Distributed Systems Fanatic | Open Source Hacker.

Read More