Applications Azure

Ghost 6 on Ubuntu 24.04 on Azure User Guide

| Product: Ghost 6 on Ubuntu 24.04 LTS on Azure

Overview

Ghost is the leading open-source headless CMS and publishing platform. Powering newsletters, magazines, and membership sites, Ghost combines a clean writing experience with native support for paid subscriptions, email delivery, and a fast Casper storefront theme. The cloudimg image installs Ghost 6.36 from the official ghost-cli alongside Node.js 22 LTS, MySQL 8, and nginx — all wired together by hand for predictable single-VM behaviour.

What is included:

  • Ghost 6.36.x installed via the official ghost-cli at /var/www/ghost, owned by the ghost system user
  • Node.js 22 LTS from NodeSource (deb.nodesource.com node_22.x)
  • MySQL 8 from Ubuntu noble main with a per-VM ghost_user and rotated password
  • nginx from Ubuntu noble main reverse-proxying TCP 80 to Ghost on 127.0.0.1:2368
  • ghost_localhost.service (Type=simple, User=ghost) — node current/index.js from /var/www/ghost
  • ghost-6-firstboot.service (one-shot) rotating MySQL root + ghost_user passwords and recreating the ghost_prod database on first boot
  • Storefront at http://<vm-ip>/, Admin UI + setup wizard at http://<vm-ip>/ghost/
  • 24/7 cloudimg support

Prerequisites

Active Azure subscription, SSH key, VNet + subnet, and a Network Security Group that exposes TCP 22 to your management CIDR and TCP 80 to your readers (or to your CDN / Front Door / Application Gateway, with TLS terminated upstream). Standard_B2s (2 vCPU, 4 GB RAM) is comfortable for Ghost plus MySQL plus nginx as a single-tenant publication. For high-traffic membership sites, move to D4s/D8s and put MySQL on Azure Database for MySQL Flexible Server.

Step 1: Deploy from the cloudimg gallery

In the Azure Portal, create a new VM from cloudimgGallery/ghost-6-ubuntu-24-04, choose Standard_B2s, attach your SSH key, and place the VM in a subnet whose NSG allows inbound TCP 22 (SSH) and TCP 80 (HTTP). Wait for provisioning to finish and copy the public IP from the VM Overview blade.

Step 2: SSH to the VM

ssh azureuser@<vm-ip>

Step 3: Service status

sudo systemctl status ghost_localhost.service nginx.service mysql.service --no-pager | head -30

ghost_localhost, nginx, and mysql all active (running) on the build VM

Step 4: Confirm Ghost is listening

ss -tln | grep -E ':(80|2368|3306) '

Port 80 is nginx (public), 2368 is the Ghost Node process bound to 127.0.0.1, and 3306 is MySQL (also 127.0.0.1).

Step 5: Storefront round-trip

curl -sI http://127.0.0.1/ | head -5

A 200 OK from nginx confirms the reverse proxy is forwarding to Ghost successfully. Browse to http://<vm-ip>/ from your laptop to see the default Casper theme welcome page.

Ghost Casper theme storefront — "Thoughts, stories and ideas" default home page

Step 6: Claim the owner account

Browse to http://<vm-ip>/ghost/ in your browser. On a fresh VM, Ghost detects there is no owner yet and redirects you to the setup wizard at /ghost/#/setup. Fill in the site title, your name, your email address, and a strong password. Ghost owns this flow — the cloudimg firstboot does not pre-create an owner, so you are the only person with access to the admin.

Ghost admin setup wizard — "Welcome to Ghost" form for the owner account

Step 7: Admin dashboard

After completing the setup wizard, Ghost signs you in and lands you on the admin dashboard. The left-hand sidebar lists Posts, Pages, Tags, Members, and Settings — your editorial workspace.

Ghost admin dashboard with Posts, Pages, Tags, Members and Settings sidebar after first sign-in

Step 8: Database round-trip

sudo mysql -u root -p"$(sudo grep ^MYSQL_ROOT_PASSWORD= /stage/scripts/ghost-credentials.log | cut -d= -f2-)" -e "SHOW DATABASES;" 2>/dev/null | grep -E '(ghost_prod|mysql|information_schema)'

You should see ghost_prod in the list — that is the per-VM database that Ghost initialized via knex migrations on first boot.

Step 9: Read the per-VM credentials

sudo cat /stage/scripts/ghost-credentials.log

The file is mode 0600, root-owned. It contains MYSQL_ROOT_PASSWORD, GHOST_DB_PASSWORD, the database name and user, and the URLs you need for backups, scripted content imports, or migrating to managed MySQL later. Keep this file off-VM in your secrets manager.

Step 10: Components

Component Path
Ghost install /var/www/ghost/
Ghost CLI /usr/bin/ghost (npm global)
Node.js 22 LTS /usr/bin/node
systemd unit /etc/systemd/system/ghost_localhost.service
Production config /var/www/ghost/config.production.json
MySQL data /var/lib/mysql/
nginx site /etc/nginx/sites-enabled/ghost-cloudimg.conf
Firstboot script /usr/local/sbin/ghost-6-firstboot.sh
Firstboot sentinel /var/lib/cloudimg/ghost-6-firstboot.done
Credentials /stage/scripts/ghost-credentials.log (mode 0600 root:root)

Step 11: Authoring your first post

In the admin UI, click Posts in the sidebar, then New post. Ghost's editor is markdown-aware with rich blocks for images, embeds, bookmarks, and email-only call-to-actions. When you publish, Ghost regenerates the storefront and your post is live at http://<vm-ip>/<slug>/. Use Pages for evergreen content (About, Contact) and Tags to organise the storefront's category navigation.

Step 12: Production hardening

  • Front the VM with TLS: terminate HTTPS at Azure Application Gateway or Front Door, or run certbot --nginx on the VM after pointing your apex DNS at the public IP. Then update url in /var/www/ghost/config.production.json to https://your-domain and sudo systemctl restart ghost_localhost.
  • Move MySQL off the VM: provision Azure Database for MySQL Flexible Server, restore the ghost_prod schema, and update the database.connection block in config.production.json to point at the managed endpoint. Keep the VM-local MySQL stopped after the migration.
  • Email delivery: set the mail section in config.production.json to your SMTP provider (Mailgun, SendGrid, Amazon SES) so member sign-ups and post broadcasts deliver reliably.
  • Backups: schedule mysqldump ghost_prod and a tarball of /var/www/ghost/content to Azure Blob Storage or AWS S3. The content/ directory holds uploaded images, themes, and member exports.
  • Restrict the NSG: lock TCP 22 down to your management CIDR and front TCP 80/443 with your CDN's IP range only.
  • Patch monthly: sudo apt-get update && sudo apt-get -y upgrade && sudo reboot. Subscribe to https://ghost.org/changelog/ for Ghost releases — upgrade with sudo -u ghost ghost update from /var/www/ghost.

Licensing

Ghost is MIT licensed — free to use commercially. cloudimg provides commercial support separately. support@cloudimg.co.uk.