Image by: Jaime Reimer - Pexels

Install Ghost on AlmaLinux 8

selfhosted May 29, 2022

Well, that was a roller-coaster :)

Installing Ghost is based on the premise that you run an Ubuntu (or rather Debian Family) system. Anything other than that would require Debian like changes.

As far as I remember Debian also doesn't use SELinux.

When trying to install Ghost many of the online sources did the one thing that would make any self respecting sysadmin cringe. Yeah, they did.. they turned off SELinux.

That, for something hosted online just isn't something you should do.


Base

We start with a base installation of AlmaLinux, but in all seriousness, it is a RedHat family Operating system so feel free to use CentOS ( stream ), Red Hat, Fedora or anything else.

Install epel

sudo yum install epel-release

Install packages

sudo yum install nginx python3-certbot-nginx mod_ssl python3-firewall python3-libselinux python3-libsemanage policycoreutils-python-utils python3-PyMySQL mariadb mariadb-server

Install nodejs

Here we start with finding the right version of NodeJS. For Ghost - currently - it will need to be higher than version 16.13.

sudo dnf module list nodejs
sudo dnf module enable nodejs:16-epel
sudo yum install nodejs

Ghost documentation

Following the Ghost documentation we start by adding a user.

sudo adduser ghostuser -s /bin/bash -h /home/ghostuser -c 'For Ghost Blog' -m

# it is requested for installation, allow sudo rights
sudo -i # the below command otherwise will fail.
echo "ghostuser ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers.d/ghostuser
exit

Firewalling

In a later stage Letsencrypt will want to connect on port 80 to verify the host. Because of this we will require to open ports for http and https.

sudo -i
firewall-cmd --list-all
firewall-cmd --zone=public --add-service={http,https} --permanent
firewall-cmd --reload
exit

SELinux

Nice and squished in the middle of the document. As stated earlier, i'm no hero when it comes to SELinux. However we can assume the following:

  • A database connection is required
  • HTTP service should be allowed to connect to Ghost
  • Site files are needed to be served

Which kind of leads to the following settings:

# HTTP
setsebool -P httpd_can_network_connect on
setsebool -P httpd_can_network_connect_db on
# setsebool -P httpd_can_network_relay on

# Files
semanage fcontext -a -t httpd_sys_content_t "/var/www/<sitename>(/.*)?"
# httpd_sys_script_exec_t (mentioned here because it might be needed)

# For Ghost - http connection
semanage port -a -t http_port_t -p tcp 2368

# Lastly
restorecon -irv /var/www/

MySQL

Mysql is already installed, you will have to create a user and a database with the correct permissions. For this we use mysql_setpermission.

riccardo@xxx ~ $ sudo mysql_setpermission #<---
Password for user  to connect to MariaDB:
######################################################################
## Welcome to the permission setter 1.4 for MariaDB.
## made by Luuk de Boer
######################################################################
What would you like to do:
  1. Set password for an existing user.
  2. Create a database + user privilege for that database
     and host combination (user can only do SELECT)
  3. Create/append user privilege for an existing database
     and host combination (user can only do SELECT)
  4. Create/append broader user privileges for an existing
     database and host combination
     (user can do SELECT,INSERT,UPDATE,DELETE)
  5. Create/append quite extended user privileges for an
     existing database and host combination (user can do
     SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,INDEX,
     LOCK TABLES,CREATE TEMPORARY TABLES)
  6. Create/append full privileges for an existing database
     and host combination (user has FULL privilege)
  7. Remove all privileges for for an existing database and
     host combination.
     (user will have all permission fields set to N)
  0. exit this program

Make your choice [1,2,3,4,5,6,7,0]: 2 #<---


Which database would you like to add: db_demoghost #<---
The new database db_demoghost will be created

What username is to be created: ghostie #<---
Username = ghostie
Would you like to set a password for ghostie [y/n]: y #<---
What password do you want to specify for ghostie: #<---
Type the password again: #<---
We now need to know from what host(s) the user will connect.
Keep in mind that % means 'from any host' ...
The host please: localhost #<---
Would you like to add another host [yes/no]: no #<---
Okay we keep it with this ...
The following host(s) will be used: localhost.
######################################################################

That was it ... here is an overview of what you gave to me:
The database name       : db_demoghost
The username            : ghostie
The host(s)             : localhost
######################################################################

Are you pretty sure you would like to implement this [yes/no]: yes #<---
Okay ... let's go then ...

Everything is inserted and mysql privileges have been reloaded.

######################################################################
## Welcome to the permission setter 1.4 for MariaDB.
## made by Luuk de Boer
######################################################################
What would you like to do:
  1. Set password for an existing user.
  2. Create a database + user privilege for that database
     and host combination (user can only do SELECT)
  3. Create/append user privilege for an existing database
     and host combination (user can only do SELECT)
  4. Create/append broader user privileges for an existing
     database and host combination
     (user can do SELECT,INSERT,UPDATE,DELETE)
  5. Create/append quite extended user privileges for an
     existing database and host combination (user can do
     SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,INDEX,
     LOCK TABLES,CREATE TEMPORARY TABLES)
  6. Create/append full privileges for an existing database
     and host combination (user has FULL privilege)
  7. Remove all privileges for for an existing database and
     host combination.
     (user will have all permission fields set to N)
  0. exit this program
  
  Make your choice [1,2,3,4,5,6,7,0]: 6 #<---


Which database from existing databases would you like to select:
You can choose from:
  - db_demoghost
  - information_schema
  - mysql
  - performance_schema
Which database will it be (case sensitive). Type * for any:
db_demoghost #<---
The database db_demoghost will be used.

What username is to be created: ghostie #<---
Username = ghostie
Would you like to set a password for ghostie [y/n]: y #<---
What password do you want to specify for ghostie: #<---
Type the password again: #<---
We now need to know from what host(s) the user will connect.
Keep in mind that % means 'from any host' ...
The host please: localhost
Would you like to add another host [yes/no]: no #<---
Okay we keep it with this ...
The following host(s) will be used: localhost.
######################################################################

That was it ... here is an overview of what you gave to me:
The database name       : db_demoghost
The username            : ghostie
The host(s)             : localhost
######################################################################

Are you pretty sure you would like to implement this [yes/no]: yes #<---
Okay ... let's go then ...

Everything is inserted and mysql privileges have been reloaded.

######################################################################
## Welcome to the permission setter 1.4 for MariaDB.
## made by Luuk de Boer
######################################################################
What would you like to do:
  1. Set password for an existing user.
  2. Create a database + user privilege for that database
     and host combination (user can only do SELECT)
  3. Create/append user privilege for an existing database
     and host combination (user can only do SELECT)
  4. Create/append broader user privileges for an existing
     database and host combination
     (user can do SELECT,INSERT,UPDATE,DELETE)
  5. Create/append quite extended user privileges for an
     existing database and host combination (user can do
     SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,INDEX,
     LOCK TABLES,CREATE TEMPORARY TABLES)
  6. Create/append full privileges for an existing database
     and host combination (user has FULL privilege)
  7. Remove all privileges for for an existing database and
     host combination.
     (user will have all permission fields set to N)
  0. exit this program

Make your choice [1,2,3,4,5,6,7,0]: 0 #<---

Dont forget to remember the settings.

Ghost-Cli

Time to install Ghost-Cli.

sudo npm install ghost-cli@latest -g

Install Ghost itself

Before we do there are a few things we would have to do to make the environment "seem" like its a Debian family system.

sudo mkdir /etc/nginx/sites-available
cd /etc/nginx
sudo ln -s conf.d sites-enabled
sudo mkdir snippets

From there we run (official documentation):

sudo mkdir -p /var/www/<sitename>/ghost
sudo chown -R ghostuser:ghostuser /var/www/<sitename>
sudo chmod 775 /var/www/<sitename>/ghost
sudo su - ghostuser
cd /var/www/<sitename>/ghost
/usr/local/bin/ghost install # and answer all questions

It Failed ?

Yeah, the installation ended up being successful, no problems there. The site just refused to load. After a lot of troubleshooting it turned out that Ghost didnt really run Letsencrypt and therefor port 443 never actually came up. (Https not accepted).

It was resolved by simply running cerbot again and restarting nginx.

/usr/bin/certbot --nginx --non-interactive --agree-tos --email <valid@email.addr> -d <sitename>
service nginx restart

And thats it,

Good luck.

Updating

This is an additional edit :)

To update ghost, as the mortal user do the following:

/usr/local/bin/ghost check-update
/usr/local/bin/ghost backup
/usr/local/bin/ghost update

Tags

Riccardo B.

Riccardo is an all round Linux Systems Engineer with over 20 years of experience and a knack for Automation. Favoring acronyms like NAO, IaC, SRE and more. Also hardly ever writes in third person :)