Using Podman To Deploy A Ghost Blog Server

Introduction

My favorite blogging platform is Ghost. Ghost is simple yet powerful and does not require as much in the way or resources as WordPress. Ghost also does not suffer from the same security woes that pop up with WordPress. To properly use Ghost, you will want to have a reverse proxy for TLS. I recommend using NGINX here and I'll include an NGINX config for you.

The tutorials out there really center on using Docker for deploying Ghost but I like podman because it is rootless. So this guide will show you how to deploy it using podman. This guide focuses on using Alma Linux so your distro will vary somewhat.

Preparation

The first steps are some preparation for the application stack. We have to create the user that Ghost is going to run under and create a pod.

# useradd -c "Ghost" -m -G wheel ghost
# passwd ghost

Once you have done this, log in as the ghost user. It is important to be logged in as the ghost user and no just sudo. The next step will create the pod for Ghost to run under and some mount points to make the data persistent across reboots. The database directory will store the MySQL database and the content directory will store the Ghost content that you create.

# podman pod create --publish 3306:3306 --publish 8080:2368 --name ghost-blog
# mkdir database content

If you want to use a reverse proxy, install nginx by running sudo dnf install nginx and add the following lines to your nginx.conf file. After doing this, be sure to enable and start nginx by typing sudo systemctl enable --now nginx.service.

server {
    listen 80;
    server_name goblackcat.com www.goblackcat.com;
    return 302 https://goblackcat.com$request_uri;
}

server {
    listen 443 ssl http2;
    server_name example.com;

    # SSL certificate and key files
    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # Enable SSL protocols and ciphers
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";

    # Location block for proxying requests
    location / {
        proxy_pass http://<ip-address-here>:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        tcp_nodelay on;
    }
}

Deploy The Ghost and MySQL Containers

Now that the pod has been created, we can begin to use podman to download and start the containers. Omit the :Z if you do not use SELinux. Also, if you use a reverse proxy for TLS, replace the url with https. Do the following:

# podman run -d --name mysql -e MYSQL_ROOT_PASSORD=<your-password-here> \
-e MYSQL_USER=ghost \
-e MYSQL_PASSWORD=<your-password> \
-e MYSQL_DATABASE=ghost \
-v ./database:/var/lib/mysql:Z --pod ghost-blog mysql:latest
# podman run -d --name ghost -e database__connection__host=mysql \
-e database__connection__user=ghost \
-e database__connection__password=<your-password-here> \
-e database__connection__database=ghost \
-e url=http://example.com \
-v ./content:/var/lib/ghost/content:Z --pod ghost-blog ghost:latest

After running the containers above, let's just check to make certain they are running. The following below should look similar to yours. Note that you should have three items – a pod and two containers.

# podman ps
# CONTAINER ID  IMAGE                                    COMMAND               CREATED       STATUS       PORTS                                           NAMES
6b2c64657166  localhost/podman-pause:4.6.1-1714365972                        12 hours ago  Up 12 hours  0.0.0.0:3306->3306/tcp, 0.0.0.0:8080->2368/tcp  e95bfdb8ee20-infra
9f32be2d465a  docker.io/library/mysql:8.0              mysqld                12 hours ago  Up 12 hours  0.0.0.0:3306->3306/tcp, 0.0.0.0:8080->2368/tcp  mysql
878a4b003198  docker.io/library/ghost:latest           node current/inde...  12 hours ago  Up 12 hours  0.0.0.0:3306->3306/tcp, 0.0.0.0:8080->2368/tcp  ghost

Ghost and MySQL are now running. Remember to replace http with https if you are using a reverse proxy. Go to http://example.com/ghost to setup the ghost admin user and configure your installation.

Setting Up Ghost To Start Automatically On Boot

You will most likely want Ghost to start up automatically and that is done through systemd. Fortunately, podman includes features to automatically generate the systemd files necessary to start the ghost blog pod and containers.

# mkdir -p ~/.config/systemd/user
# cd ~/.config/systemd/user
# podman generate systemd --new --files --name ghost-blog

The above command creates 3 systemd unit files. The one we are concerned with is the pod-ghost-blog.service unit file. We have to expressly enable the service. Once we do this it will start on boot.

# sudo loginctl enable-linger ghost
# systemctl --user daemon-reload
# systemctl --user enable pod-ghost-blog.service

Your Ghost install is now complete and you can enjoy using a nice basic blogging service. Have fun with it and start creating content!

Mastodon