<title>Installing Ghost · Sysadmining. All day. Every day.</title>
<metaname="description"content="I haven&rsquo;t published an article on here for over a year and a half&hellip; While this was mostly due to a lack of motivation, another reason was that I did"/>
<p>I haven’t published an article on here for over a year and a half… While this was mostly due to a lack of motivation, another reason was that I didn’t enjoy the blogging system I was using.</p>
<p>As lightweight as <ahref="https://blog.getpelican.com/">Pelican</a> is, I found it cumbersome to use on a regular basis. Every time I wanted to publish or update an article, I had to :
- edit local markdown files ;
- regenerate the website files ;
- start a webserver locally to proofread the article ;
- commit and push the files to my git repo ;
- pull the files on the webserver.</p>
<p>I hadn’t had a look at the CMS landscape for a while, and I started searching for one with a web editor that supports markdown. I also wanted to avoid anything that runs on PHP if possible.</p>
<p>I quickly discovered <ahref="https://ghost.org/">Ghost</a>, and decided to give it a shot. I was convinced by it within a few hours and I decided to migrate this blog.</p>
<p>So, to celebrate my move to Ghost, I figured I’d write an article on how I’ve installed it on my server.</p>
<p>All commands in this article have to be run as the <code>root</code> user on a Debian server.</p>
<h1id="installing-nodejs">Installing nodejs</h1>
<p>Unlike most CMS (Wordpress, for example), Ghost is not files that you have to upload to a webserver, but a daemon that runs on <ahref="https://nodejs.org/en/">nodejs</a>.</p>
<p>Here’s the official recommended way of installing the current LTS version of nodejs on Debian :</p>
<p>If, like me, you don’t want to run a bash script downloaded from the internet on your server, here are the commands you have to run to install it manually.</p>
<p>Since the nodejs repo uses https, we’ll first need to install the required package to use those :</p>
<p>Ghost needs an empty folder for the automated installation script to work. For that purpose, let’s create a subfolder in the <code>ghost</code> user home folder :</p>
<p>Ghost requires a MySQL/MariaDB database to store its data (technically, you could use a SQLite database, but please don’t).</p>
<p>I personnally have all my databases stored on a single LXC container running MariaDB. However, if you need to, you can install MariaDB locally this way :</p>
<p>You can change the <code>%</code> to <code>localhost</code> in the <code>create user</code> command if you’ve installed MariaDB locally. Please also remember to change <code>'password'</code> by an actual password.</p>
<p>Once that’s done, we’re ready to install Ghost !</p>
<h1id="installing-ghost">Installing Ghost</h1>
<h2id="ghost-cli">Ghost CLI</h2>
<p>To install Ghost, we first have to install the Ghost CLI :</p>
<pre><codeclass="language-bash">npm i -g ghost-cli
</code></pre>
<p>The Ghost CLI is a tool that lets you install, upgrade and manage your Ghost installation easily. Its usage is thoroughly documented on the official website <ahref="https://docs.ghost.org/v1/docs/ghost-cli">here</a>.</p>
<p>The command will ask you for the following information :
- the URL of your website ;
- the hostname or IP of the server that’s hosting your MariaDB installation ;
- the username to use to connect to the database (<code>ghost</code>) ;
- the password you’ve configured for the database user ;
- the database name (<code>ghost</code>).</p>
<p>Once the script has finished running, you’ve successfully installed Ghost ! However, the daemon won’t start since we haven’t configured systemd yet.</p>
<p>Since it contains a password, let’s fix the permissions on our installation’s configuration file to make sure it’s not world-readable :</p>
<p>As you can see from the <code>ghost install</code> command, it can install and configure pretty much all of its dependencies on its own. However, since I’m a <ahref="https://xkcd.com/705/"><em>sysadmin</em></a>, that’s not how I roll.</p>
<p>With its default configuration, Ghost runs as a webserver on localhost, on a non-standard HTTP port (TCP 2368). For your website to be publicly browseable, you’ll need to configure a webserver as a reverse-proxy in front of your Ghost installation. We’ll use nginx for that purpose.</p>
<p>If you already have nginx running on a different server from your Ghost installation, you can use it for that purpose. For it to work, you’ll need to edit the server host IP in Ghost’s <code>config.production.json</code> configuration file with your Ghost server public IP and to restart Ghost. If you do so, make sure to limit direct access to your Ghost installation to the IP of your reverse-proxy by using iptables.</p>
<p>If you need to, you can install nginx locally this way :</p>
<pre><codeclass="language-bash">apt install nginx
</code></pre>
<p>I won’t go into details on how to configure and secure a nginx installation here as it is beyond the scope of this article.</p>
<p>Here is my nginx configuration for this website :</p>
<p>As you can see, I’ve declared two location blocks :
- <code>/</code> is publicly visible by anyone ;
- <code>/ghost</code> (Ghost’s administation interface) is only accessible from 192.0.2.100 (my public IP address).</p>
<p>I’d rather have left Ghost’s administation interface accessible from anywhere. However, since there is currently no way to replace <code>/ghost</code> by another subfolder and two-factor authentification is not available, I’ve decided against it.</p>
<h1id="monit">Monit</h1>
<p>As I mentionned in previous articles, I have monit running on all of my servers to make sure that my services are running and to restart them should they crash.</p>
<p>I’ve created a configuration file for Ghost :</p>
<pre><codeclass="language-text">check process ghost
matching "ghost run"
start program = "/bin/systemctl start ghost"
stop program = "/bin/systemctl stop ghost"
if changed pid then alert
if changed ppid then alert
</code></pre>
<p>Let’s reload monit :</p>
<pre><codeclass="language-bash">monit reload
</code></pre>
<p>Ghost should now appear in your <code>monit summary</code>.</p>
<h1id="logging">Logging</h1>
<p>Ghost writes its logs through <code>syslog</code>. If you don’t want those messages to end up in <code>/var/log/syslog</code>, you’ll have to configure your <code>syslog</code> daemon. For me, that’s <code>syslog-ng</code>.</p>
<h2id="syslog-ng">Syslog-ng</h2>
<p>Let’s create a dedicated folder for the Ghost daemon’s log files :</p>
<p>Once that’s done, Ghost should start logging in <code>/var/log/ghost/ghost.log</code>. Accessing a page on your site will create a new log entry, so that’ll be enough to make sure it’s working properly.</p>
<h2id="logrotate">Logrotate</h2>
<p>As always with logs, let’s configure logrotate to make sure we don’t end up with huge files.</p>
<p>Let’s create a new logrotate configuration file :</p>
<p>There’s no need to reload anything here. This new configuration file will be read by logrotate automatically next time its cron runs.</p>
<h1id="conclusion">Conclusion</h1>
<p>This blog uses a previous version of Ghost’s default theme, <ahref="https://github.com/TryGhost/Casper">Casper</a>.</p>
<p>I’ve modified it a bit, and I really enjoy how it looks now ! You can get the theme with my modifications from my <ahref="https://github.com/captainark/Casper">GitHub</a> ! Credits to <ahref="http://www.brycematheson.io/fixing-ghosts-default-casper-theme/">this article</a> for some of the changes, and thanks <ahref="https://mastodon.fun/@aguay">@Aguay</a> for the help !</p>
<p>You’ve also probably noticed that I now use a private installation of <ahref="https://nodebb.org/">NodeBB</a> for the comments section. I’ll probably write an article on how I’ve installed and implemented it in my Ghost installation in the near future. In the meantime, please feel free to make use of it !</p>
<sectionclass="poweredby">Proudly generated by <aclass="icon-hugo"href="http://gohugo.io">HUGO</a>, with <aclass="icon-theme"href="https://github.com/vjeantet/hugo-theme-casper">Casper</a> theme</section>