Setting up Ghost on Proxmox LXC

Setting up Ghost on Proxmox LXC
Photo by Daniel Lincoln / Unsplash

Hello and welcome to my blog! This is the first post, and since this website is using Ghost let's see how it was set up.

Why Ghost?

For my personal website I was wondering whether to spin up a WordPress instance or try an alternative CMS.

First I looked into Jekyll and Hugo. Those two frameworks are static site generators. This means that they generate a static website from a collection of markup files (Markdown, HTML). A static website requires almost no resources to be hosted (it can run even an old router!). For my personal blog I wanted something more user-friendly though.

So the remaining options were WordPress and Ghost. I went for the Ghost route for the following reasons:

  • Ghost is new: I've already used WordPress before, and I wanted to try something new.
  • Markdown support: Ghost supports writing in Markdown out of the box.
  • Security: Even if WordPress can be considered safe, it's still the most used CMS of the world. Also, Ghost is built with some security features available out of the box, like brute force protection.
  • No plugins: WordPress is known for its vast ecosystem of plugins. But for my personal website, no plugins are needed with Ghost. No plugins mean reducing the attack surface.
  • Ghost UI looks sleek: this point is pretty self-explanatory. Even with the default theme, Ghost looks nice!

Deploying Ghost

My server is a mini pc running Proxmox with some LXCs. To install Ghost I followed the official guide, with some customization to integrate it with my existing services.

LXC creation and setup

First I created an Ubuntu 22.04 LXC. Then I installed Node.js and I created a new user for Ghost. I skipped installing Nginx as I use caddy as a reverse proxy.

Database setup

I'm using MariaDB deployed on a different LXC. I've created the user and the database with:

CREATE USER ghostuser@'ghost-lxc-ip' IDENTIFIED BY 'password';
CREATE DATABASE ghost_prod;
GRANT ALL PRIVILEGES ON ghost_prod.* TO ghostuser@'ghost-lxc-ip';
FLUSH PRIVILEGES;

Please note that only MySQL is officially supported. With MariaDB some features may not work correctly.

Ghost installation

I installed ghost-cli:

sudo npm install ghost-cli@latest -g

Ghost-cli is installed using NPM

I then installed Ghost inside /var/web/ghost with ghost install, skipping the automatic Nginx configuration as I'm using Caddy as a reverse proxy.

Caddy configuration

Now the last part: setting up Caddy. I've added this block to my Caddyfile:

matteoschiff.com {
        reverse_proxy <ghost-ip>:2368

        header /* {
                Strict-Transport-Security "max-age=31536000; includeSubdomains; preload"
                -Server
        }
}

Caddyfile configuration block

Caddy implements automatic SSL using Let's Encrypt.

Conclusion

The installation was pretty straightforward, as it took me only 30 minutes to go from zero to a working website. Although Ghost supports paid post and newsletters, I've decided to disable that functionality as I don't want to use it now.