Install Log: Ghost with Phusion Passenger on CentOS 7

I have considered switching to Ghost for my blogging needs, because WordPress was way too fancy, and it really drew itself away from writing something. But I did not have any motive, until the past weekend when I tried to move from MariaDB to Percona Server, which I screwed up, and made the entire WordPress installation in a broken state. This is a log on how my site is configured. Firewall etc. will not be discussed, as I have configured them long ago.

These guides, besides the official documentation from Percona, Phusion, and Disqus are referenced:

The basic objective is to install a Ghost Blog to replace my WordPress site, using Percona Server as database backend, Phusion Passenger as application server, OpenSMTPD as mail backend (so that it can be shared with other services and utilities), Disqus as commenting service, Prism.js for code highlighting. In the meantime, to reuse configurations that can still be reused from my previous WordPress installation.

0x0. Grab the Packages

OpenSMTPD is from EPEL, Percona Server and Phusion Passenger have their own upstream repositories, and I have chosen to use the Node.js shipped from NodeSource. Add these repositories to the system:

sudo yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm \
http://www.percona.com/downloads/percona-release/redhat/0.1-4/percona-release-0.1-4.noarch.rpm \
https://rpm.nodesource.com/pub_6.x/el/7/x86_64/nodesource-release-el7-1.noarch.rpm

sudo curl --fail -sSLo /etc/yum.repos.d/passenger.repo https://oss-binaries.phusionpassenger.com/yum/definitions/el-passenger.repo

sudo yum clean all

sudo yum makecache

Then install the required packages:

sudo yum install nginx nodejs passenger Percona-Server-server-57

Now, you have all the packages needed.

0x1. Set up database

Start Percona Server with sudo systemctl enable mysqld && sudo systemctl start mysqld.

Since version 5.7, Percona Server no longer initializes with an empty root password, but generates a random root password upon initialization, and is saved in its log file. To retrieve the root password:

sudo grep root /var/log/mysqld.log

Write the password down.

mysql_secure_installation

And follow the on-screen instructions.

Then log into Percona with the root password you have just set, and add database and user for your Ghost installation:

CREATE database <ghostdb>;
GRANT ALL PRIVILEGES ON <ghostdb>.* TO '<ghostuser>'@'localhost' IDENTIFIED by '<somepassword>';
FLUSH PRIVILEGES;

Until this step, your database is ready.

0x2. Deploy Ghost

Grab Ghost from its official release and save to a convenient location on your server.

Switch to superuser, and deploy Ghost to a location you feel comfortable, I chose /srv/www/sites/ghost/.

mkdir -p /srv/www/sites/ghost/{tmp,public,ghost,log}/
cd /srv/www/sites/ghost/
unzip -d ghost <path-to-ghost>/Ghost-0.11.8.zip
pushd public
ln -s ../ghost/{content/themes/casper/assets,core/shared} .
popd

Then write these lines to app.js in your text editor of chosen:

require('/srv/www/sites/ghost/ghost/index.js');  
process.chdir('/srv/www/sites/ghost/ghost'); 

Then configure your Ghost installation by modifying the template:

pushd ghost/
cp config.example.js config.js
<youreditor> config.js

Here's my configuration file (only showing the production part):

production: {
        url: 'https://<yourdomain>', // Assuming you have HTTPs
        mail: {
            from: '<adminemail>', // Assuming you decide to route all your mail to OpenSMTPD
            transport: 'SMTP',
            options: {
                service: 'Sendmail',
            }
        },
        database: {
            client: 'mysql',
            connection: {
                host: 'localhost',
                user: '<ghostuser>',
                password: '<password>',
                database: '<ghostdb>',
                charset: 'utf8'
            }
        },

        server: {
            host: '127.0.0.1',
            port: '2368'
        },
        privacy: {
            useGoogleFonts: false,
            useStructuredData: false
        }
},

Now install the node modules needed by Ghost:

npm install --production

To install Disqus commenting system, first obtain the comment box code from their website, and add them to where you like in content/themes/casper/post.hbs, I personally chose to add them right after {{/author}}.

To install Prism.js for code highlighting, first head to their download page, and it will generate a JavaScript file and a CSS file. Copy the content of the CSS file and drop it in content/themes/casper/assets/css/prism.css and the contents of the JavaScript file in content/themes/casper/assets/js/prism.js. Then add these lines to content/themes/caspter/deafult.hbs, right under the {{!-- Styles'n'Scripts --}} line.

<link rel="stylesheet" type="text/css" href="{{asset "css/prism.css"}}" />
<script type="text/javascript" src="{{asset "js/prism.js"}}"></script>

After this, set the correct UNIX permissions for the installation:

popd
chown -R nginx.nginx *

Until now, the installation of Ghost is complete.

0x3. Configure Nginx

Nginx will be the web server we use today. Add these lines to /etc/nginx/nginx.conf, right under the access_log <something>; line.

passenger_root /usr/share/ruby/vendor_ruby/phusion_passenger/locations.ini;
passenger_ruby /usr/bin/ruby;
passenger_instance_registry_dir /var/run/passenger-instreg;

Then add these to /etc/nginx/conf.d/ghost.conf, assuming you want to have TLS enabled.

server {
    listen 80;
    listen [::]:80;
    server_name  <yourdomain>;
    rewrite ^ https://$http_host$request_uri? permanent;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    include /etc/nginx/ssl_params; # I put all TLS-related parameters together in a single file
    ssl_certificate <path-to-chained-cert>;
    ssl_certificate_key <path-to-key>;
    ssl_trusted_certificate <path-to-chained-cert>; # Required for OCSP stapling
    server_name <yourdomain>;
    root /srv/www/sites/ghost/public/;
    passenger_enabled on;
    passenger_app_env production;
    access_log syslog;
    error_log syslog;
}

These four lines are required in the server block if you want to do something fancy.

server_name <yourdomain>;
root /srv/www/sites/ghost/public/;
passenger_enabled on;
passenger_app_env production;

Until now, Nginx configuration should be all set. Start Nginx with sudo systemctl enable nginx && sudo systemctl restart nginx.

0x4. Configure OpenSMTPD

OpenSMTPD will be used to handle outbound Email in my configuration.

First, edit your /etc/opensmtpd/smtpd.conf accordingly, mainly these lines:

## This line should go where all the table lines are
table secrets db:/etc/opensmtpd/secrets.db
## This line should go where all the ACL lines are
accept for any relay via
tls+auth://[email protected]<domain>:<port> auth <secrets> # The server must support STARTTLS on the give port

Then, add your SMTP credentials in /etc/opensmtpd/secrets file.

echo 'mysmtp <user>@<domain>:<password>' >> /etc/opensmtpd/secrets
chmod 640 /etc/opensmtpd/secrets
chown root.smtpd /etc/opensmtpd/secrets
makemap /etc/opensmtpd/secrets

Until now, OpenSMTPD will be ready after sudo systemctl enable opensmtpd && sudo systemctl start opensmtpd.

Finally, visit <yourdomain>/ghost to complete the setup of Ghost, and enjoy. The first visit will be slow as Phusion Passenger loads the app lazily, but subsequent visits will speed up significantly.

Sijie Bu

Read more posts by this author.

Subscribe to Rydeen

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!