Ghost Print

  • 0

Install and maintain Ghost on Ubuntu

Ghost is installed non-interactively with Node.js 22, MariaDB, the Ghost CLI, a dedicated system user, a custom systemd service, Nginx, and TLS.

How this guide was prepared: This is the command-line equivalent of the current Sive AppStore installation playbook. It covers the application installation and the parts you maintain after deployment. Platform provisioning, billing integration, and one-time orchestration are intentionally omitted.

Before you start

  • Use a clean, supported Ubuntu server with root or sudo access.
  • Point app.example.com to the server before requesting a public TLS certificate.
  • Replace every value written as CHANGE_ME and store the generated credentials in a password manager.
  • Take a snapshot before changing an existing installation.
  • A dedicated MariaDB database/user/password and a domain.
  • An email delivery provider configured after installation if newsletters or staff invitations are required.
Important: This playbook-aligned deployment uses MariaDB, not an interactive MySQL install. Keep the Ghost config and database credentials readable only by the Ghost service account/root.

What the AppStore installation creates

  • Node.js 22 and global ghost-cli
  • MariaDB database and dedicated ghost Linux user
  • Ghost below /var/www/app.example.com/ghost on port 2368
  • Custom systemd service, Nginx, Certbot, UFW, and Fail2ban

1. Install Node.js 22, MariaDB, and Nginx

sudo apt update
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo bash -
sudo apt install -y nodejs mariadb-server nginx certbot python3-certbot-nginx ufw fail2ban
sudo npm install -g ghost-cli
sudo systemctl enable --now mariadb nginx

2. Create the database and service user

sudo mysql
CREATE DATABASE ghost CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'ghostuser'@'localhost' IDENTIFIED BY 'CHANGE_ME_DB_PASSWORD';
GRANT ALL PRIVILEGES ON ghost.* TO 'ghostuser'@'localhost';
FLUSH PRIVILEGES;
EXIT;
sudo useradd --system --home /var/www/app.example.com/ghost --create-home --shell /bin/bash ghost
sudo chown -R ghost:ghost /var/www/app.example.com

3. Install Ghost non-interactively

Run Ghost CLI as the dedicated user and let the custom systemd/Nginx steps manage services.

sudo -iu ghost
cd /var/www/app.example.com/ghost
ghost install --no-prompt --no-setup-linux-user --no-setup-nginx --no-setup-ssl --no-setup-systemd \
  --url https://app.example.com \
  --db mysql --dbhost localhost --dbname ghost --dbuser ghostuser --dbpass 'CHANGE_ME_DB_PASSWORD'
exit

4. Create systemd, Nginx, and TLS

Create a systemd unit for the Ghost production process on localhost port 2368, then proxy it through Nginx.

sudo nano /etc/systemd/system/ghost-app-example-com.service
sudo systemctl daemon-reload
sudo systemctl enable --now ghost-app-example-com
sudo nano /etc/nginx/sites-available/ghost-app-example-com
sudo ln -s /etc/nginx/sites-available/ghost-app-example-com /etc/nginx/sites-enabled/ghost-app-example-com
sudo nginx -t
sudo systemctl reload nginx
sudo certbot --nginx -d app.example.com -m admin@example.com --agree-tos --redirect

Important files and data

  • Ghost installation and content: /var/www/app.example.com/ghost
  • Ghost production config: config.production.json
  • Service: /etc/systemd/system/ghost-app-example-com.service
  • Nginx site and MariaDB database

Health checks and logs

Run these checks after installation and after each upgrade:

sudo systemctl status ghost-app-example-com mariadb nginx --no-pager
sudo journalctl -u ghost-app-example-com -n 100 --no-pager
curl -I http://127.0.0.1:2368
sudo nginx -t

Routine maintenance

Review release notes and take a backup or snapshot before upgrading. Use the following playbook-aligned commands as the starting point:

sudo -iu ghost
cd /var/www/app.example.com/ghost
ghost backup
ghost update
exit
sudo systemctl status ghost-app-example-com --no-pager

Backup scope

  • MariaDB Ghost database
  • Ghost content directory and config.production.json
  • Systemd, Nginx, TLS, and mail-provider configuration

A usable backup needs both application files and application data. Test restoration on a separate server; an untested backup is not a recovery plan.

Troubleshooting

  • Confirm DNS with dig +short app.example.com before retrying Certbot.
  • Test the web-server configuration before reloading it: sudo nginx -t or sudo apache2ctl configtest.
  • Check free space with df -h and listening ports with sudo ss -ltnup.
  • If a service fails, inspect its systemd journal before changing configuration.
  • Ghost calls its MariaDB/MySQL-family driver mysql; that does not mean the host must run Oracle MySQL.
  • If Ghost CLI and the custom systemd unit disagree about service state, use systemd as the source of truth for this deployment.

Security notes

  • Do not paste passwords, API keys, repository credentials, private keys, or access tokens into tickets or public logs.
  • Expose only the documented public ports. Keep database and application backend ports bound to localhost or a private network.
  • Keep SSH access working before enabling UFW, then allow only the ports this guide lists.
  • Renewal can be tested safely with sudo certbot renew --dry-run where Certbot manages TLS.

Was this answer helpful?
Back