Updating self hosted Ghost blog using Ansible and Ghost CLI

How to update Ghost install with Ansible and Ghost CLI.

Updating self hosted Ghost blog using Ansible and Ghost CLI
header image

I have previously written about deploying Ghost using Terraform, Ansible, and Ghost CLI. In that last post I updated my existing repo to do a fresh install of the Ghost using the tools mentioned. Now I will be enhancing the same project with an update option.

Ansible role changes

I added two main features to the custom Ansible role, tags and update tasks. The tags I used to control which steps are run, and the new tasks I added to make sure the ghost instance can be properly updated in a relatively resource constrained environment.

DigitalOcean | Cloud Infrastructure for Developers
An ocean of simple, scalable cloud solutions.
---

- name: Add the user 'ghostuser' with a specific uid and a primary group of 'sudo'
  ansible.builtin.user:
    name: ghostuser
    group: sudo
  tags:
    - always

- name: Copy a new sudoers file into place, after passing validation with visudo
  ansible.builtin.template:
    src: 100-ghost-user
    dest: /etc/sudoers.d/100-ghost-user
    mode: '440'
  tags:
    - always

- name: Create a directory if it does not exist
  ansible.builtin.file:
    path: /var/www/hackandslash
    owner: ghostuser
    group: root
    state: directory
    mode: '755'
  tags:
    - always

- name: Install Ghost
  become: true
  become_user: ghostuser
  ansible.builtin.shell: |
    /usr/local/lib/npm/bin/ghost \
      install 5.89.1 \
      --no-prompt \
      --dir /var/www/hackandslash \
      --url https://hackandslash.blog \
      --port 2368 \
      --sslemail "{{ lookup('env', 'ALERT_EMAIL') }}" \
      --db mysql \
      --dbhost 10.137.0.3 \
      --dbuser "{{ lookup('env', 'GHOST_DB_USER') }}" \
      --dbpass "{{ lookup('env', 'GHOST_DB_PASSWORD') }}" \
      --dbname ghost \
      --mail SMTP \
      --mailservice Mailgun \
      --mailuser "{{ lookup('env', 'GHOST_MAIL_USER') }}" \
      --mailpass "{{ lookup('env', 'GHOST_MAIL_PASSWORD') }}" \
      --mailhost smtp.mailgun.org \
      --mailport 465 \
      --process systemd
  args:
    executable: /bin/bash
  tags:
    - freshinstall

- name: Stop Ghost
  become: true
  become_user: ghostuser
  ansible.builtin.shell: |
    /usr/local/lib/npm/bin/ghost \
      stop \
      hackandslash-blog \
      --dir /var/www/hackandslash \
      --verbose
  args:
    executable: /bin/bash
  tags:
    - update

- name: Update Ghost
  become: true
  become_user: ghostuser
  ansible.builtin.shell: |
    /usr/local/lib/npm/bin/ghost \
      update \
      --v5 \
      --no-prompt \
      --auto-rollback \
      --dir /var/www/hackandslash \
      --verbose
  args:
    executable: /bin/bash
  tags:
    - update

- name: Start Ghost
  become: true
  become_user: ghostuser
  ansible.builtin.shell: |
    /usr/local/lib/npm/bin/ghost \
      start \
      --enable \
      --dir /var/www/hackandslash \
      --verbose \
      hackandslash-blog
  args:
    executable: /bin/bash
  tags:
    - update

tasks/main.yaml

The main changes can be seen in the main.yaml task file above. The first three tasks have Ansible reserved tag, always. As the tag implies, these tasks will always run regardless of the other tags I specify in the command. The Install Ghost task has a custom freshinstall tag, and this will only run when I specify this tag in the command. And finally the new tasks, Stop Ghost, Update Ghost, and Start Ghost have the update tag, and these tasks will only run when this tag specified in the command.

So with these updates made to the role, I used the following command to update my Ghost instance.

ansible-playbook ./playbook/playbook.production.yml -i ./playbook/inventory.ini --limit "webservers" --tags "update" -u root

The above command ran all the tasks tagged with always and update.

I created explicit tasks for stop, update, and start because of the resource constraints a server might have. The update will fail if there is not enough RAM on the server. If you bypass the memory check, the update will still fail due to insufficient resources to actually download and setup the new Ghost install.

So with that I now have a brand new install of Ghost, with all my data migrated, and an automated way to maintain the install the recommended way.

Repo

GitHub - mbbaig/ghost-deployment: A Terraform and Ansible project to deploy the Ghost platform
A Terraform and Ansible project to deploy the Ghost platform - mbbaig/ghost-deployment

Hope it was useful.

Happy Hacking 😄