Updating Ghost issue and fix

Updating Ghost issue and fix
ChatGPT image instructions: make an infographic about this issue we discussed in this chat that you solved

updating Ghost. will I break my site if I change ownership to ghost? I think we did things a little different when we originally set this up. I thought I upgraded npm ghost cli latest with the sudo command, but I still don't see the latest cli version Ghost-CLI version: 1.28.3 Ghost version: 6.10.3 (at /var/www/ghost/myconversationswithai) adam@mcwai:/var/www/ghost/myconversationswithai$ ghost update Love open source? We’re hiring JavaScript Engineers to work on Ghost full-time. https://careers.ghost.org You are running an outdated version of Ghost-CLI. It is recommended that you upgrade before continuing. Run npm install -g ghost-cli@latest to upgrade. + sudo systemctl is-active ghost_myconversationswith-ai ✔ Checking system Node.js version - found v22.21.0 ✔ Ensuring user is not logged in as ghost user ✔ Checking if logged in user is directory owner ✔ Checking current folder permissions ✔ Checking folder permissions ✖ Checking file permissions ✖ Checking content folder ownership ✔ Checking memory availability ✔ Checking free space One or more errors occurred. 1) Checking file permissions Message: Your installation folder contains some directories or files with incorrect permissions: - ./content/themes/casper-mcwai/assets/screenshot-mobile.jpg - ./content/themes/casper-mcwai/assets/screenshot-desktop.jpg - ./content/themes/casper-mcwai/assets/images/preloader.gif - ./content/themes/casper-mcwai/assets/images/default-skin.png - ./content/themes/casper-mcwai/assets/images/default-skin.svg - ./content/themes/casper-mcwai/assets/js/lib/photoswipe.min.js - ./content/themes/casper-mcwai/assets/js/lib/photoswipe-ui-default.min.js Run sudo find ./ ! -path "./versions/*" -type f -exec chmod 664 {} \; and try again. 2) Checking content folder ownership Message: Your installation folder contains a directory or file with incorrect permissions: - ./content/themes/casper-mcwai/partials/footer.hbs Run sudo chown -R ghost:ghost ./content and try again. Debug Information: OS: Ubuntu, v24.04.3 LTS Node Version: v22.21.0 Ghost Version: 6.10.3 Ghost-CLI Version: 1.28.3 Environment: production Command: 'ghost update' Try running ghost doctor to check your system for known issues. You can always refer to https://ghost.org/docs/ghost-cli/ for troubleshooting. adam@mcwai:/var/www/ghost/myconversationswithai$

ChatGPT 5.2 said:

Thought for 2m 21s

Changing the entire install to ghost:ghost is the thing that can bite you — because then you (adam) won’t be the directory owner, and Ghost-CLI will start failing checks when you run ghost update as your normal user.

Changing only ./content to ghost:ghost is normal and expected for a production Ghost install (Ghost needs to write uploads, generated files, etc.). That won’t break your site — it usually fixes exactly what you’re seeing.

Also: you’re only one patch behind on CLI. Latest is Ghost-CLI 1.28.4. 
And Ghost currently recommends Node v22 LTS, so your Node v22.21.0 is in the right lane. 

Do this (safe + minimal)

Run these as adam (with sudo where shown). You’re already in the right folder.

1) Make a quick backup (stored under /home/adam/)

sudo mkdir -p /home/adam/backups/ghost/myconversationswithai/$(date +%F-%H%M%S) && \
BKP="/home/adam/backups/ghost/myconversationswithai/$(date +%F-%H%M%S)" && \
sudo mkdir -p "$BKP" && \
sudo cp -a ./config.production.json "$BKP/" && \
sudo tar -czf "$BKP/content.tgz" -C . content && \
echo "✅ Backup saved in: $BKP"

2) Fix exactly what Ghost-CLI is complaining about

From /var/www/ghost/myconversationswithai:

# Fix file perms (Ghost-CLI’s own recommended command)
sudo find ./ ! -path "./versions/*" -type f -exec chmod 664 {} \;

# Ensure content is owned by the ghost service user
sudo chown -R ghost:ghost ./content

3) Upgrade Ghost-CLI (and verify you’re using the right ghost binary)

command -v ghost
ghost --version
npm -v
node -v

Now upgrade CLI:

  • If command -v ghost shows something like /usr/bin/ghost, do:

sudo npm install -g ghost-cli@latest
hash -r
ghost --version

  • If it shows something under your home directory (nvm-style), do:

npm install -g ghost-cli@latest
hash -r
ghost --version

(You should see 1.28.4 after this. )

4) Re-run update

ghost doctor
ghost update

If you want to edit theme files without sudo (optional, but nice)

Right now chown -R ghost:ghost content means Ghost owns your theme files. That’s fine. If you want adam to edit them easily, the clean way is to add adam to the ghost group and make content group-writable — tell me what id outputs and I’ll give you the exact 2–3 commands:

id
ls -ld ./content ./content/themes/casper-mcwai

But the core answer to your question: don’t change the whole install to ghost; do change ./content to ghost — that’s the correct ownership model for Ghost-CLI + production.

You said:

Should I use sudo or not on the next step? adam@mcwai:/var/www/ghost/myconversationswithai$ sudo mkdir -p /home/adam/backups/ghost/myconversationswithai/$(date +%F-%H%M%S) && \ BKP="/home/adam/backups/ghost/myconversationswithai/$(date +%F-%H%M%S)" && \ sudo mkdir -p "$BKP" && \ sudo cp -a ./config.production.json "$BKP/" && \ sudo tar -czf "$BKP/content.tgz" -C . content && \ echo "✅ Backup saved in: $BKP" ✅ Backup saved in: /home/adam/backups/ghost/myconversationswithai/2026-02-11-213256 adam@mcwai:/var/www/ghost/myconversationswithai$ # Fix file perms (Ghost-CLI’s own recommended command) sudo find ./ ! -path "./versions/*" -type f -exec chmod 664 {} \; # Ensure content is owned by the ghost service user sudo chown -R ghost:ghost ./content adam@mcwai:/var/www/ghost/myconversationswithai$ command -v ghost ghost --version npm -v node -v /usr/bin/ghost Love open source? We’re hiring JavaScript Engineers to work on Ghost full-time. https://careers.ghost.org Ghost-CLI version: 1.28.3 Ghost version: 6.10.3 (at /var/www/ghost/myconversationswithai) 11.10.0 v22.21.0 adam@mcwai:/var/www/ghost/myconversationswithai$

ChatGPT said:

Use sudo for the next step — because your ghost binary is /usr/bin/ghost, which comes from a global install, and updating global npm packages needs sudo on this setup.

Run:

sudo npm install -g ghost-cli@latest
hash -r
ghost --version

If ghost --version still shows 1.28.3 after that, run these two checks (no sudo needed) and paste the output:

ls -l /usr/bin/ghost
npm list -g --depth=0 | grep ghost-cli

You said:

adam@mcwai:/var/www/ghost/myconversationswithai$ sudo npm install -g ghost-cli@latest hash -r ghost --version npm warn deprecated inflight@1.0.6: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. npm warn deprecated glob@7.2.3: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me changed 682 packages in 35s 218 packages are looking for funding run npm fund for details Love open source? We’re hiring JavaScript Engineers to work on Ghost full-time. https://careers.ghost.org Ghost-CLI version: 1.28.3 Ghost version: 6.10.3 (at /var/www/ghost/myconversationswithai) adam@mcwai:/var/www/ghost/myconversationswithai$ ls -l /usr/bin/ghost npm list -g --depth=0 | grep ghost-cli lrwxrwxrwx 1 root root 39 Jan 3 15:41 /usr/bin/ghost -> ../lib/node_modules/ghost-cli/bin/ghost ├── ghost-cli@1.28.4 adam@mcwai:/var/www/ghost/myconversationswithai$

ChatGPT said:

Thought for 1m 44s

Don’t use sudo for the next Ghost steps. Run ghost commands as adam inside the install directory. Ghost-CLI will call sudo internally when it needs systemctl, nginx, etc.

Before you continue, your outputs show something important:

  • /usr/bin/ghost points to the global package ✅
  • npm list -g shows ghost-cli@1.28.4 ✅
  • But ghost --version (when run inside the install folder) is still displaying 1.28.3.

That “still 1.28.3” is usually just the instance context output from within the install folder. Let’s confirm the global CLI version outside the install:

cd ~
ghost --version

If that shows 1.28.4, you’re good. Then proceed (no sudo):

cd /var/www/ghost/myconversationswithai
ghost doctor
ghost update

If cd ~ && ghost --version still shows 1.28.3

Then the ghost you’re executing is somehow still loading old code. Do a clean reinstall (sudo required here):

sudo npm remove -g ghost-cli
sudo npm install -g ghost-cli@latest
hash -r
cd ~
ghost --version

After that, go back and run:

cd /var/www/ghost/myconversationswithai
ghost update

You said:

adam@mcwai:~$ sudo npm remove -g ghost-cli sudo npm install -g ghost-cli@latest hash -r cd ~ ghost --version removed 682 packages in 981ms npm warn deprecated inflight@1.0.6: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. npm warn deprecated glob@7.2.3: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me added 682 packages in 7s 218 packages are looking for funding run npm fund for details Love open source? We’re hiring JavaScript Engineers to work on Ghost full-time. https://careers.ghost.org Ghost-CLI version: 1.28.3 adam@mcwai:~$ cd /var/www/ghost/myconversationswithai ghost update Love open source? We’re hiring JavaScript Engineers to work on Ghost full-time. https://careers.ghost.org You are running an outdated version of Ghost-CLI. It is recommended that you upgrade before continuing. Run npm install -g ghost-cli@latest to upgrade. + sudo systemctl is-active ghost_myconversationswith-ai ✔ Checking system Node.js version - found v22.21.0 ✔ Ensuring user is not logged in as ghost user ✔ Checking if logged in user is directory owner ✔ Checking current folder permissions ✔ Checking folder permissions ✔ Checking file permissions ✔ Checking content folder ownership ✔ Checking memory availability ✔ Checking free space ✔ Checking for available migrations ✔ Checking for latest Ghost version # 6.18.1 * 🐛 Fixed welcome emails using noreply address instead of default newsletter reply-to address (#26358) - Chris Raible — View the changelog for full details: https://github.com/tryghost/ghost/compare/v6.18.0...v6.18.1 ✔ Fetched release notes ✔ Downloading and updating Ghost to v6.18.1 + sudo systemctl stop ghost_myconversationswith-ai ✔ Stopping Ghost ✔ Linking latest Ghost and recording versions ✔ Linking built-in themes + sudo systemctl start ghost_myconversationswith-ai ✔ Restarting Ghost ℹ Removing old Ghost versions [skipped] adam@mcwai:/var/www/ghost/myconversationswithai$

ChatGPT said:

Good news: your Ghost update completed and Ghost is now 6.18.1. That means the permissions/ownership fixes worked and you didn’t break anything.

Now the weird part: Ghost-CLI is actually upgraded, but ghost --version is still printing 1.28.3. Your earlier npm list -g proved it was 1.28.4, and ghost update proceeded fine. So what’s happening is almost certainly a stale “ghost” shim/binary somewhere else in your PATH (or an old cached wrapper), not the global npm package itself.

Let’s fix/verify cleanly. Run these exact commands and paste output:

which -a ghost
type -a ghost
ls -l /usr/bin/ghost /usr/local/bin/ghost 2>/dev/null
npm list -g --depth=0 | grep ghost-cli
/usr/bin/ghost --version

What I expect / what to do next (no waiting)

  • If which -a ghost shows more than one path (e.g., /usr/local/bin/ghost and /usr/bin/ghost), we’ll remove the stray one.
  • If it only shows /usr/bin/ghost but it still reports 1.28.3 while npm says 1.28.4, then it’s likely running the correct package but printing the version incorrectly in this environment — not harmful, but we can still force it to match by re-linking.

Meanwhile, confirm Ghost itself is updated

Run (no sudo):

cd /var/www/ghost/myconversationswithai
ghost version

You should see Ghost version 6.18.1.

Don’t change ownership of the install folder

Leave /var/www/ghost/myconversationswithai owned by adam, and content/ owned by ghost:ghost (that’s the right model).

You said:

adam@mcwai:/var/www/ghost/myconversationswithai$ which -a ghost type -a ghost ls -l /usr/bin/ghost /usr/local/bin/ghost 2>/dev/null npm list -g --depth=0 | grep ghost-cli /usr/bin/ghost --version /usr/bin/ghost /bin/ghost ghost is /usr/bin/ghost ghost is /bin/ghost lrwxrwxrwx 1 root root 39 Jan 3 15:41 /usr/bin/ghost -> ../lib/node_modules/ghost-cli/bin/ghost ├── ghost-cli@1.28.4 Love open source? We’re hiring JavaScript Engineers to work on Ghost full-time. https://careers.ghost.org Ghost-CLI version: 1.28.3 Ghost version: 6.18.1 (at /var/www/ghost/myconversationswithai) adam@mcwai:/var/www/ghost/myconversationswithai$

ChatGPT said:

Thought for 1m 17s

You’re done with the risky part — Ghost is updated to 6.18.1 and running. ✅

Now, for the Ghost-CLI version mismatch:

  • npm list -g says ghost-cli@1.28.4
  • but /usr/bin/ghost --version still prints 1.28.3

That almost always means your /usr/bin/ghost symlink is pointing at a different global npm “root” than the one npm is installing into.

Next step: use sudo

Because we’re going to touch /usr/bin (system path).

Run this exactly:

npm root -g
npm prefix -g

Then run the relink (this is the fix 90% of the time):

sudo ln -sf "$(npm root -g)/ghost-cli/bin/ghost" /usr/bin/ghost
hash -r
/usr/bin/ghost --version

If it STILL shows 1.28.3

Then your /usr/lib/node_modules/ghost-cli is genuinely still the old version, and npm is installing 1.28.4 somewhere else (usually /usr/local/...). We’ll quarantine the old one (no deleting) and reinstall into /usr:

sudo mkdir -p /home/adam/__quarantine__/ghost-cli
sudo mv /usr/lib/node_modules/ghost-cli "/home/adam/__quarantine__/ghost-cli/ghost-cli-$(date +%F-%H%M%S)" 2>/dev/null || true

sudo npm install -g ghost-cli@latest --prefix=/usr
sudo ln -sf /usr/lib/node_modules/ghost-cli/bin/ghost /usr/bin/ghost
hash -r
/usr/bin/ghost --version

And just to be clear on sudo usage going forward

  • Ghost commands (ghost updateghost doctorghost restart) → NO sudo (run as adam)
  • Global npm installs + /usr/bin fixes → YES sudo

Run the relink first and tell me what /usr/bin/ghost --version prints after.

You said:

adam@mcwai:/var/www/ghost/myconversationswithai$ npm root -g npm prefix -g /usr/local/lib/nodejs/node-v22.21.0-linux-x64/lib/node_modules /usr/local/lib/nodejs/node-v22.21.0-linux-x64 adam@mcwai:/var/www/ghost/myconversationswithai$ sudo ln -sf "$(npm root -g)/ghost-cli/bin/ghost" /usr/bin/ghost hash -r /usr/bin/ghost --version Love open source? We’re hiring JavaScript Engineers to work on Ghost full-time. https://careers.ghost.org Ghost-CLI version: 1.28.4 Ghost version: 6.18.1 (at /var/www/ghost/myconversationswithai) adam@mcwai:/var/www/ghost/myconversationswithai$

ChatGPT said:

Perfect. ✅ That fixed it the right way.

What’s now true

  • Ghost-CLI: 1.28.4
  • Ghost: 6.18.1
  • /usr/bin/ghost now points to the Ghost-CLI that lives under your Node install at /usr/local/lib/nodejs/...

What to do next (no sudo)

Just sanity-check the service and your site:

ghost doctor
ghost ls
sudo systemctl status ghost_myconversationswith-ai --no-pager

And in a browser, load the homepage + /ghost/ admin and make sure the theme looks normal.

One small note

You have two ghost commands in PATH: /usr/bin/ghost and /bin/ghost. Now that /usr/bin/ghost is correct and comes first, you can ignore /bin/ghost. If you want, we can later clean that up safely (but it’s not necessary since things are working).

You said:

adam@mcwai:/var/www/ghost/myconversationswithai$ ghost doctor ghost ls sudo systemctl status ghost_myconversationswith-ai --no-pager Love open source? We’re hiring JavaScript Engineers to work on Ghost full-time. https://careers.ghost.org ✔ Checking system Node.js version - found v22.21.0 ✔ Checking logged in user ✔ Ensuring user is not logged in as ghost user ✔ Checking if logged in user is directory owner ✔ Checking current folder permissions ✔ Checking system compatibility ✔ Checking for a MySQL installation + sudo systemctl is-active ghost_myconversationswith-ai Instance is currently running ℹ Validating config [skipped] ✔ Checking folder permissions ✔ Checking file permissions ✔ Checking content folder ownership ✔ Checking memory availability ✔ Checking binary dependencies ✔ Checking free space ✔ Checking systemd unit file ✔ Checking systemd node version - found v22.21.0 Love open source? We’re hiring JavaScript Engineers to work on Ghost full-time. https://careers.ghost.org + sudo systemctl is-active ghost_myconversationswith-ai ┌────────────────────────┬──────────────────────────────────────┬─────────┬──────────────────────┬────────────────────────────────┬──────┬─────────────────┐ │ Name │ Location │ Version │ Status │ URL │ Port │ Process Manager │ ├────────────────────────┼──────────────────────────────────────┼─────────┼──────────────────────┼────────────────────────────────┼──────┼─────────────────┤ │ myconversationswith-ai │ /var/www/ghost/myconversationswithai │ 6.18.1 │ running (production) │ https://myconversationswith.ai │ 2368 │ systemd │ └────────────────────────┴──────────────────────────────────────┴─────────┴──────────────────────┴────────────────────────────────┴──────┴─────────────────┘ ● ghost_myconversationswith-ai.service - Ghost systemd service for blog: myconversationswith-ai Loaded: loaded (/usr/lib/systemd/system/ghost_myconversationswith-ai.service; enabled; preset: enabled) Active: active (running) since Wed 2026-02-11 21:43:11 EST; 5min ago Docs: https://ghost.org/docs/ Main PID: 588133 (ghost run) Tasks: 22 (limit: 4537) Memory: 335.2M (peak: 380.6M) CPU: 10.881s CGroup: /system.slice/ghost_myconversationswith-ai.service ├─588133 "ghost run" └─588161 /usr/local/lib/nodejs/node-v22.21.0-linux-x64/bin/node c… Feb 11 21:47:03 mcwai node[588161]: [2026-02-11 21:47:03] INFO "GET /conte…53ms Feb 11 21:47:03 mcwai node[588161]: [2026-02-11 21:47:03] INFO "GET /conte… 4ms Feb 11 21:47:03 mcwai node[588161]: [2026-02-11 21:47:03] INFO "GET /membe… 1ms Feb 11 21:47:03 mcwai node[588161]: [2026-02-11 21:47:03] INFO "GET /membe… 1ms Feb 11 21:47:03 mcwai node[588161]: [2026-02-11 21:47:03] INFO "GET /membe… 5ms Feb 11 21:47:03 mcwai node[588161]: [2026-02-11 21:47:03] INFO "GET /ghost… 6ms Feb 11 21:47:03 mcwai node[588161]: [2026-02-11 21:47:03] INFO "GET /ghost… 5ms Feb 11 21:47:03 mcwai node[588161]: [2026-02-11 21:47:03] INFO "GET /ghost…10ms Feb 11 21:48:31 mcwai node[588161]: [2026-02-11 21:48:31] INFO [Recommenda…data Feb 11 21:48:31 mcwai node[588161]: [2026-02-11 21:48:31] INFO "GET /membe… 4ms Hint: Some lines were ellipsized, use -l to show in full. adam@mcwai:/var/www/ghost/myconversationswithai$

ChatGPT said:

That’s a clean bill of health. ✅

  • ghost doctor passed everything that matters.
  • ghost ls shows 6.18.1 running (production) on 2368 at your real URL.
  • systemd service is active (running) and using your Node v22 binary.

You’re stable.

1) Remove the /bin/ghost ambiguity (safe)
Right now you’ve got both /usr/bin/ghost and /bin/ghost. It’s not hurting you because /usr/bin is first, but it’s a future foot-gun.

Run:

ls -l /bin/ghost

If it’s just another symlink, we’ll repoint it to the same target as /usr/bin/ghost (or remove it if it’s unnecessary).

2) Snapshot current ownership/permissions (so you can revert fast later)

cd /var/www/ghost/myconversationswithai
stat -c '%U:%G %a %n' . content content/themes/casper-mcwai | sed 's/^/PERM: /'

If your browser looks good, you’re done

Homepage loads, /ghost/ loads, theme assets show correctly — you’re finished.

If anything looks off (missing CSS/images), tell me exactly what you see and I’ll zero in on the theme/static asset path or nginx cache.

You said:

make an infographic about this issue we discussed in this chat that you solved

ChatGPT said:

Thought for 16s
Analyzed
Always show details
from PIL import Image, ImageDraw, ImageFont
import textwrap, os, math, datetime

# Canvas size (tall infographic)
W, H = 1400, 2200
img = Image.new("RGB", (W, H), "white")
draw = ImageDraw.Draw(img)

# Fonts
def load_font(name, size):
paths = [
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
"/usr/share/fonts/truetype/dejavu/DejaVuSansCondensed.ttf",
"/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf",
]
for p in paths:
if os.path.exists(p) and (("Mono" in name and "Mono" in p) or ("Sans" in name and "Sans.ttf" in p) or True):
try:
return ImageFont.truetype(p, size)
except:
pass
return ImageFont.load_default()

font_title = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 56)
font_sub = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 30)
font_body = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 26)
font_small = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 22)
font_mono = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf", 22)

# Helpers
def rounded_rect(xy, r=18, fill="#f5f7fb", outline="#d9e1ee", width=3):
draw.rounded_rectangle(xy, radius=r, fill=fill, outline=outline, width=width)

def draw_wrapped(text, x, y, font, max_width, fill="black", line_spacing=6):
lines = []
for paragraph in text.split("\n"):
if not paragraph.strip():
lines.append("")
continue
words = paragraph.split(" ")
line = ""
for w in words:
test = (line + " " + w).strip()
if draw.textlength(test, font=font) <= max_width:
line = test
else:
lines.append(line)
line = w
if line:
lines.append(line)
yy = y
for ln in lines:
draw.text((x, yy), ln, font=font, fill=fill)
yy += font.size + line_spacing
return yy

# Header bar
header_h = 190
rounded_rect((40, 40, W-40, 40+header_h), r=26, fill="#0f172a", outline="#0f172a", width=0)
draw.text((80, 75), "Ghost Update Fix — The Exact Playbook", font=font_title, fill="white")
draw.text((82, 138), "Permissions + Ownership + Ghost-CLI mismatch (Ubuntu 24.04, Node v22)", font=font_sub, fill="#dbeafe")

# Meta line
meta = "Outcome: Ghost 6.18.1 ✅ Ghost-CLI 1.28.4 ✅ Service healthy ✅"
draw.text((80, 180), meta, font=font_small, fill="#bfdbfe")

y = 260

# Section 1: Symptoms
rounded_rect((40, y, W-40, y+290), r=22, fill="#f8fafc", outline="#cbd5e1", width=3)
draw.text((70, y+25), "1) What broke (symptoms)", font=font_sub, fill="#0f172a")
sym = (
"• `ghost update` refused to run due to file permissions + content ownership errors\n"
"• CLI warned: “You are running an outdated version of Ghost-CLI”\n"
"• `npm list -g` showed the new CLI, but `ghost --version` still showed the old one"
)
draw_wrapped(sym, 80, y+80, font_body, max_width=W-160, fill="#111827")
y += 330

# Section 2: Golden rule + backup
rounded_rect((40, y, W-40, y+360), r=22, fill="#fff7ed", outline="#fdba74", width=3)
draw.text((70, y+25), "2) Golden rule (safe ownership model)", font=font_sub, fill="#7c2d12")
rule = (
"• Keep the install folder owned by your admin user (ex: `adam`)\n"
"• Make only `content/` owned by `ghost:ghost` (Ghost must write uploads & generated files)\n"
"• Don’t blindly chown the whole install to ghost — it can break Ghost-CLI checks"
)
draw_wrapped(rule, 80, y+80, font_body, max_width=W-160, fill="#7c2d12")

draw.text((70, y+245), "Quick backup first (stored under /home/adam/):", font=font_small, fill="#7c2d12")
code = r"""sudo mkdir -p /home/adam/backups/ghost/myconversationswithai/$(date +%F-%H%M%S) && \
BKP="/home/adam/backups/ghost/myconversationswithai/$(date +%F-%H%M%S)" && \
sudo cp -a ./config.production.json "$BKP/" && \
sudo tar -czf "$BKP/content.tgz" -C . content"""
# code box
rounded_rect((70, y+275, W-70, y+345), r=16, fill="#111827", outline="#111827", width=0)
draw_wrapped(code, 90, y+287, font_mono, max_width=W-180, fill="white", line_spacing=4)
y += 400

# Section 3: Fix permissions/ownership
rounded_rect((40, y, W-40, y+330), r=22, fill="#ecfeff", outline="#67e8f9", width=3)
draw.text((70, y+25), "3) Fix what Ghost-CLI complained about", font=font_sub, fill="#164e63")
txt = (
"Run inside the Ghost install folder:\n"
"• Fix file permissions (exclude versions/)\n"
"• Set content ownership to ghost:ghost"
)
draw_wrapped(txt, 80, y+80, font_body, max_width=W-160, fill="#164e63")
code2 = r"""sudo find ./ ! -path "./versions/*" -type f -exec chmod 664 {} \;
sudo chown -R ghost:ghost ./content"""
rounded_rect((70, y+195, W-70, y+305), r=16, fill="#111827", outline="#111827", width=0)
draw_wrapped(code2, 90, y+210, font_mono, max_width=W-180, fill="white", line_spacing=4)
y += 370

# Section 4: Diagnose CLI mismatch
rounded_rect((40, y, W-40, y+360), r=22, fill="#f0fdf4", outline="#86efac", width=3)
draw.text((70, y+25), "4) CLI mismatch diagnosis (PATH + npm root)", font=font_sub, fill="#14532d")
txt2 = (
"Key idea: you can have the right package installed but the wrong `ghost` binary being executed.\n"
"Check where `ghost` is coming from and where npm installs globals."
)
draw_wrapped(txt2, 80, y+80, font_body, max_width=W-160, fill="#14532d")
code3 = r"""which -a ghost
type -a ghost
npm list -g --depth=0 | grep ghost-cli
npm root -g
npm prefix -g"""
rounded_rect((70, y+205, W-70, y+335), r=16, fill="#111827", outline="#111827", width=0)
draw_wrapped(code3, 90, y+220, font_mono, max_width=W-180, fill="white", line_spacing=4)
y += 400

# Section 5: The fix (relink /usr/bin/ghost)
rounded_rect((40, y, W-40, y+360), r=22, fill="#eef2ff", outline="#a5b4fc", width=3)
draw.text((70, y+25), "5) The fix that made versions match", font=font_sub, fill="#1e1b4b")
txt3 = (
"Because `ghost` was in /usr/bin, the correct move was to point it at the\n"
"global Ghost-CLI under your active Node install (npm root -g)."
)
draw_wrapped(txt3, 80, y+80, font_body, max_width=W-160, fill="#1e1b4b")
code4 = r"""sudo ln -sf "$(npm root -g)/ghost-cli/bin/ghost" /usr/bin/ghost
hash -r
/usr/bin/ghost --version"""
rounded_rect((70, y+205, W-70, y+335), r=16, fill="#111827", outline="#111827", width=0)
draw_wrapped(code4, 90, y+220, font_mono, max_width=W-180, fill="white", line_spacing=4)
y += 400

# Section 6: Verify + sudo rules
rounded_rect((40, y, W-40, y+410), r=22, fill="#fdf2f8", outline="#f9a8d4", width=3)
draw.text((70, y+25), "6) Verify + the sudo rule that prevents pain", font=font_sub, fill="#831843")
verify = (
"Verification:\n"
"• `ghost doctor` should pass\n"
"• `ghost ls` should show running (production)\n"
"• `systemctl status` should show active (running)\n\n"
"Sudo rule of thumb:\n"
"• Use sudo for: global npm installs, chown/chmod, and /usr/bin symlinks\n"
"• Do NOT use sudo for: `ghost update/doctor/restart` (run as your admin user)"
)
draw_wrapped(verify, 80, y+80, font_body, max_width=W-160, fill="#831843")

code5 = r"""ghost doctor
ghost ls
sudo systemctl status ghost_myconversationswith-ai --no-pager"""
rounded_rect((70, y+300, W-70, y+390), r=16, fill="#111827", outline="#111827", width=0)
draw_wrapped(code5, 90, y+315, font_mono, max_width=W-180, fill="white", line_spacing=4)

# Footer
footer_y = H - 85
draw.text((40, footer_y), "Tip: If `ghost --version` lies, trust `npm root -g` + the symlink target — not the printed banner.", font=font_small, fill="#334155")
draw.text((40, footer_y+30), "Generated for: myconversationswith.ai • Feb 11, 2026", font=font_small, fill="#64748b")

# Save
png_path = "/mnt/data/ghost-update-fix-infographic.png"
img.save(png_path, "PNG")

# Also save as PDF
pdf_path = "/mnt/data/ghost-update-fix-infographic.pdf"
img_rgb = img.convert("RGB")
img_rgb.save(pdf_path, "PDF", resolution=300.0)

png_path, pdf_path

Here you go — infographic ready for your blog: