At some point almost every Proxmox VE homelab ends up running a few self-hosted web apps — a photo gallery, a bookmark manager, maybe a wiki. If you've ever thought about running your own blog or newsletter instead of paying for Substack or a hosted WordPress plan, Ghost is worth a look. It's a Node.js publishing platform built specifically for writing and sending newsletters, and it runs comfortably in a small Proxmox VE LXC container.

This guide walks through the whole process: creating the container, installing the exact software Ghost needs, and getting a working site at an address like http://192.168.1.50:2368. None of it requires Docker or a one-click appliance — just a plain Ubuntu container and the official ghost-cli tool.

What You Will Learn

  • What Ghost actually is and how it differs from WordPress
  • How to create an Ubuntu LXC container in Proxmox VE that's ready for Ghost
  • How to install Node.js 22, MySQL, and Nginx the way Ghost expects
  • How to run ghost install and answer its setup prompts correctly
  • The specific errors people run into on their first attempt, and how to fix them

What Is Ghost?

Ghost is open-source publishing software written in Node.js. You write posts in a block-based editor that feels a lot like Notion, and it handles email newsletters, memberships, and paid subscriptions out of the box — no plugins required. WordPress can technically do all of that too, but only after you've installed and configured several third-party plugins. Ghost ships with it built in, which is part of why publications like Buffer's blog and 404 Media run on it.

The tradeoff is stack complexity. WordPress runs on plain PHP and MySQL, which almost any cheap host supports. Ghost needs a specific Node.js version, MySQL 8, and Nginx, all wired together by an installer called ghost-cli. That's a bit more particular about its environment, but it's also exactly the kind of thing an LXC container is good at — a clean, disposable box with only what Ghost needs.

Why Would You Use It?

If you already write a newsletter through a paid service, self-hosting Ghost removes the monthly fee once you're past a few hundred subscribers — you just pay for the VM (or in this case, the container) and, if you want, a transactional email provider like Mailgun for outbound mail. If you just want a personal blog with a clean editor and don't want to fight with WordPress plugins, Ghost is honestly less hassle to maintain long-term.

Running it in an LXC container instead of a full VM matters here too. Ghost doesn't need much — a couple of CPU cores and a gig or two of RAM is plenty for a personal site. An LXC container shares the host kernel instead of virtualizing hardware, so it starts in under a second and uses a fraction of the RAM a VM would for the same job. For something this lightweight, a full VM is overkill.

Prerequisites

Before you start, make sure you have:

  • A Proxmox VE host on version 8.x or 9.x with some free storage (10 GB is plenty for the container)
  • An Ubuntu 24.04 LXC template — Ghost's official installer does not support Debian, which trips up a lot of people since Debian is the default template most Proxmox tutorials use
  • At least 2 GB of RAM to assign to the container (ghost-cli will warn you below 1 GB, and the install can hang on anything less)
  • Basic comfort with the Linux command line — you'll be typing commands, not clicking through a GUI installer
  • Optional: a domain name pointed at your public IP, if you want a real HTTPS certificate instead of accessing Ghost over plain HTTP on your local network

That last point matters for how you'll use this guide. If you're running Ghost purely inside your home network with no public domain, you'll skip the SSL step during setup and just browse to the container's IP address. That's the path most homelab users will take, and it's the one this guide focuses on.

Step-by-Step Tutorial

Step 1: Download the Ubuntu 24.04 Template

Log into the Proxmox VE web interface, click your node in the left sidebar, then local (or whichever storage holds your templates) and open the CT Templates tab. Click Templates, search for ubuntu-24.04, and download it. From the shell, the same thing looks like this:

pveam update
pveam available --section system | grep ubuntu-24.04
pveam download local ubuntu-24.04-standard_24.04-2_amd64.tar.zst

The exact filename changes as Canonical ships point releases, so check the output of the available command rather than copying the filename above verbatim.

Step 2: Create the Container

You can do this from the GUI with the Create CT button, or from the shell with pct create. I'll use the CLI here since it's easier to follow exactly what's happening:

pct create 201 local:vztmpl/ubuntu-24.04-standard_24.04-2_amd64.tar.zst \
  --hostname ghost \
  --cores 2 \
  --memory 2048 \
  --swap 512 \
  --rootfs local-lvm:10 \
  --net0 name=eth0,bridge=vmbr0,ip=dhcp \
  --unprivileged 1 \
  --features nesting=1 \
  --password

A few things worth explaining before you run it:

  • 201 is just the container ID — pick any number that isn't already in use on your node.
  • --rootfs local-lvm:10 assumes your storage pool is called local-lvm. If you're on a ZFS install it's probably local-zfs instead — check Datacenter → Storage if you're not sure.
  • --features nesting=1 is not optional here. Ghost runs as a systemd service, and unprivileged LXC containers need the nesting feature enabled for systemd to behave correctly. Skip this and you'll fight confusing service failures later.
  • --password with no value after it will prompt you to type one interactively, which is safer than putting a plaintext password in your shell history.

Step 3: Start the Container and Log In

pct start 201
pct enter 201

pct enter drops you straight into a root shell inside the container — no SSH keys needed for this first login. Once you're in, update the base system before installing anything else:

apt update && apt upgrade -y
apt install -y curl sudo

Minimal Ubuntu container templates sometimes don't ship with sudo pre-installed, and you'll need it in the next step.

Step 4: Create a Non-Root User

This step catches almost everyone the first time. Ghost-CLI flat out refuses to run as root:

adduser ghostuser
usermod -aG sudo ghostuser
su - ghostuser

adduser will ask for a password and some optional details you can skip by pressing Enter. From here on, run everything as ghostuser, using sudo where a command needs root privileges.

Step 5: Install Node.js 22

Ghost 6.x requires Node.js 22 LTS specifically — older LTS releases like Node 18 and 20 are no longer supported, and anything newer than 22 isn't either. Add the NodeSource repository and install it:

curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs
node -v

The version output should start with v22. If it doesn't, something grabbed an older Node package from the default Ubuntu repos instead of NodeSource — double check the curl command ran without errors before continuing.

Step 6: Install MySQL

sudo apt install -y mysql-server
sudo mysql_secure_installation

mysql_secure_installation walks you through setting a root password, removing anonymous accounts, and disabling remote root login. Answer yes to pretty much everything it asks — there's no good reason to leave a MySQL server wide open, even on a container that's only reachable inside your LAN.

Step 7: Install Nginx

sudo apt install -y nginx

Ghost-CLI configures Nginx for you automatically later — you just need the package present so it has something to configure.

Step 8: Install Ghost-CLI

sudo npm install ghost-cli@latest -g

This installs the ghost command globally, which handles everything from here: downloading Ghost itself, wiring up the database, generating the Nginx config, and setting up the systemd service.

Step 9: Install Ghost

sudo mkdir -p /var/www/ghost
sudo chown ghostuser:ghostuser /var/www/ghost
sudo chmod 775 /var/www/ghost
cd /var/www/ghost
ghost install

The installer asks a series of questions. Here's roughly what to expect and how to answer if you're running this on your local network without a public domain:

  • Enter your blog URL: use http:// plus the container's IP, e.g. http://192.168.1.50. Don't use HTTPS here unless you actually have a domain and a certificate ready.
  • Enter your MySQL hostname: localhost
  • Enter your MySQL username / password: use the root credentials you set in Step 6, or create a dedicated MySQL user first if you'd rather not use root.
  • Enter your Ghost database name: the default suggestion is fine.
  • Set up Nginx? Yes.
  • Set up SSL? Only say yes if you entered a real public domain in the first prompt. On a LAN-only setup, say no.
  • Set up systemd? Yes — this is what keeps Ghost running after reboots.
  • Start Ghost? Yes.

Step 10: Log In and Set Up Your Site

Once the install finishes, visit http://<container-ip>:2368 for the public site and http://<container-ip>:2368/ghost for the admin panel, where you'll create your owner account on first load. From there you're writing posts, not fighting infrastructure.

Commands Explained

CommandWhat It Does
pveam downloadDownloads an LXC template into Proxmox's local storage so pct create can use it.
pct createBuilds a new LXC container from a template with the resources and network settings you specify.
pct enterOpens a root shell inside a running container directly from the Proxmox host, without SSH.
adduser / usermod -aG sudoCreates a non-root user and grants it permission to run commands with sudo.
ghost installDownloads Ghost, configures the database, sets up Nginx and systemd, and starts the site.
ghost statusShows whether Ghost is currently running, stopped, or crashed.
ghost logPrints recent Ghost application logs, useful when the site won't load.

Common Errors

"Ghost-CLI cannot be installed as root/sudo user." You're logged in as root inside the container. Create a regular user with adduser, switch to it with su - username, and run ghost install from there instead.

"Node.js version is not supported." You've got an old Node package installed, probably from Ubuntu's default repos rather than NodeSource. Remove it with sudo apt remove nodejs, re-run the NodeSource setup script from Step 5, and reinstall.

"MySQL Error: Access denied for user." The username or password you gave the installer doesn't match what MySQL actually has. If you're not sure what you set, log into MySQL directly with sudo mysql and reset the root password, or create a fresh dedicated user for Ghost.

Install hangs at "Checking system Node.js version" or similar for several minutes. Usually means the container is short on RAM and swapping heavily. Shut it down, bump the memory allocation in the Proxmox GUI (or with pct set 201 --memory 2048), and try again.

Site loads over LAN but email/newsletter features don't work. This one's expected, not a bug. Ghost needs an external transactional email service (Mailgun is the officially documented option) to send newsletters and password reset emails — there's no built-in mail server, and there shouldn't be one.

Troubleshooting

If something's wrong and the error message alone isn't enough to go on, ghost log and ghost log --error are your first stop — they show what Ghost itself is complaining about, not just that it crashed. For issues below the application layer, check the systemd service directly:

sudo systemctl status ghost_<yourdomain>
sudo journalctl -u ghost_<yourdomain> -n 50

If Nginx is returning a 502 Bad Gateway instead of your site, that almost always means Ghost itself isn't running — check ghost status before you start poking at the Nginx config. And if you can't reach the container at all from another machine on your network, confirm the container actually got an IP with ip a from inside it, then check that your Proxmox bridge (vmbr0) is configured the way you expect in Datacenter → System → Network.

Best Practices

Take a Proxmox snapshot right after the install finishes and works. If something goes sideways during a Ghost or Node upgrade later — and Node major version bumps have broken Ghost installs before — you can roll back in seconds instead of rebuilding the whole container.

Back up the MySQL database and the /var/www/ghost/content folder on a schedule, not just the container as a whole. The content directory holds your uploaded images and themes, and it's not automatically included in a database dump.

Don't run Ghost as root even after the install finishes, and don't skip mysql_secure_installation just because the container is only reachable on your LAN. Homelab networks get exposed to the internet more often than people expect, usually through a misconfigured port forward or a reverse proxy rule someone forgot about.

If you eventually want a real domain and HTTPS, it's easier to set that up correctly during the initial ghost install than to bolt it on afterward. Reinstalling with ghost setup ssl works, but starting clean avoids some edge cases in how Nginx gets configured.

Frequently Asked Questions

Can I run Ghost in a Debian LXC container instead of Ubuntu?

Not with the official installer. Ghost-CLI checks the OS and refuses to proceed on Debian. You could theoretically hack around it, but it's not supported and you'll be on your own when something breaks.

How much RAM does Ghost actually need?

1 GB is the documented minimum, but 2 GB gives you enough headroom that the install itself won't struggle. A single-author blog with modest traffic runs fine on 2 GB long-term.

Do I need Docker for this?

No. This guide uses the official Node.js installation method, which doesn't touch Docker at all. Ghost does publish a Docker image if you'd rather go that route, but it's a different setup process than the one here.

Can I use SQLite instead of MySQL to keep things simpler?

Ghost's local development mode uses SQLite, but the production installer expects MySQL 8 and doesn't officially support SQLite for a real self-hosted install.

Will this work on a Raspberry Pi running Proxmox?

Proxmox VE doesn't run on ARM at all, so this applies to x86_64 Proxmox hosts only. If your Proxmox box is a repurposed PC or a mini PC, you're fine.

Conclusion

The trickiest part of getting Ghost running isn't Ghost itself — it's the handful of environment requirements that don't match what most Proxmox tutorials assume: an Ubuntu template instead of Debian, a non-root user instead of the default root login, and Node 22 specifically instead of whatever version happens to be in the default apt repos. Get those three things right and ghost install does the rest in a couple of minutes.

From here, the container is just a normal Ghost server. Write posts, connect a custom domain when you're ready, and take a snapshot before any major upgrade so you've always got a way back.