Ghost-CLI vs Docker for ease of use

Hey :wave:,

let me describe the mental model I got about this topic. I am running multiple Ghost instances on the same server since many years. All of them are running with the official Ghost-cli application and using all dependencies as described by the Ghost team.

And yes, I’ve run into all kinds of issues over the years. Failed upgrades, mismatching versions of nodejs & MySQL, file permissions and everything else.

Now I’m looking to run a few instances on a new cluster and would like to learn the ins and outs of what is different between the official ghost-cli way of things and the Docker new-kid-on-the-block way.

What I want to accomplish is:

  • Automate as much as possible
  • Minimize issues due to upgrading Ghost version
  • Automatic rollback that actually works when an upgrade fails
  • Automatic backup of Ghost content and database with no corruption
  • Encrypted disk and database for both Ghost and MySQL

How will ghost-cli help me accomplish this?
How will Docker help me accomplish this?

Looking forward for your insights :star_struck:.

I started out running multiple blogs with the Ghost CLI.

When I built a new server, I switched to using containers.

Specifically, I run each blog as a systemd service using podman and I use Ansible to automate configuring and deploying the server.

I use one MySQL instance that multiple blogs connect to.

When I used the CLI, I liked that it was interactive and checked for problems.

But with containers, some of those problems like with node version mismatch just aren’t possible.

At this point I prefer using the container solution, but my bias is that managing services like this is also my day job, so I’m already comfortable with Ansible/systemd/podman.

From monitoring the forums, running Ghost in a container seems to be very popular and is an install method I’d like to see the Ghost team officially support.

1 Like

docker with docker-compose is my go to.

It’s easy and could be perfect for your use case.
Each install is isolated and if you update one, you do not touch the other.

Running this for a few years now with auto updates. Can recommend it.

1 Like

Your replies makes me even more curious to dive into the Land of the Containers.

Learnt that Rocky Linux comes with full Podman support out of the box. And that Quadlets comes with Podman as a Docker Swarm replacement. I love the aspect of locking down privileges and not having to run containers as root is a nice touch.

My host of choice offers block storage that they replicate across three different hosts, which can be encrypted to prevent data access while at rest. Should be possible to combine this with Hashicorp Vault (or similar application) to keep secrets a bit more secure. The idea is then to place content from Ghost and MySQL on the block storage, since all other files on the server are already pre-secured.

And apply a healthy dose of STIG/CIS adaption as well before anything of the above to harden the server a tad.

To wrap it up:

  1. Rocky Linux 9 with CIS 2 and additional hardening including firewall
  2. Block storage with full disk encryption for content directories
  3. Hashicorp Vault for secret management
  4. Podman to run Ghost and MySQL
  5. Nginx with modsecurity and CRS
  6. Bunny CDN added to the Ghost installation
  7. Instance backup for quick recovery
  8. Backup of content directories and database encrypted and stored on external provider

Would that be a good approach to sort of running a couple of Ghost sites without overhead in the long term?

Use Hashicorp if you like. I use 1Password for secrets and render them into the config files using Ansible templates.

Regarding all the security features and the CDN, you could add those later.

Defense in depth doesn’t hurt, but there’s hardly any exploits for Ghost that have been found over the years and no vulnerable plugin ecosystem like WordPress.

The things I would worry most about would be brute-force logins and general DoS attacks.

1 Like

What do you need vault for?

I run vault at work and it’s not fun. Especially for a blog?
You are over engineering as heck.

1 Like

Cheers for replying and sanity-checking my write up. The only reason why I’d use something like Hashicorp Vault is to not have the credentials written in clear text. My research shows that might very well not be the case though.

If it’s the same for Vault or other similar solutions, there is no point in using them over simply typing the credentials directly into the files. It’s going to be clear text anyway.

It’s not only for a single blog. It’s for running multiple Ghost installations per instance and to run other applications on other instances all communicating with each other over private network(s). And since I’m based in the EU and will have customer’s PII stored on the servers, I must comply with the laws and regulations governing that. Which is why encryption at rest, in transit & in use is a core part because it simplifies the compliance part a whole lot.

Which is why I asked about pros/cons of using ghost-cli vs docker vs podman vs other solutions :slight_smile: ,

The problem is, at some point in time the password needs to be visible.
Only if you have some kind of integration in ghost with vault or other tools. But that is early the case and not the case for ghost.

Define your thread model and check what you want to protect against.
If it’s compliance reasons, check if you need those.
It sounded like a one man show (assuming, since I miss context) and for that you do not have too much of compliance.

1 Like

Thanks for providing the detailed information.

1 Like

Yes, the passwords are eventually in clear text on the server. In my case, involving 1Password allows me to manage my Ansible code that automates the blog in a Git repo, and push that repo to a public place but without the passwords exposed.

Because the Ansible playbook will have bits like this to define variables:

db_password: lookup('onepassword', 'ghost_mysql_db_password')

Someone else could use the same potentially open source playbook and as long as they also stored their credentials in 1Password with the same name, it work for them. (Or they could adapt it to hardcode passwords in a private fork if they choose).