# Ghost

Ghost is an open source publishing platform for blogs, newsletters and paid memberships

[Ghost](https://github.com/TryGhost/Ghost) is a Node.js application that replaces WordPress, Substack and Medium for independent publishers. It requires MySQL 8 in production. Upstream&#39;s supported install method is Ghost-CLI, which downloads each release from npm rather than cloning the Git repository. On Hatchbox you deploy a small Git repository of your own with a build script that does the same download, so you keep Hatchbox&#39;s deploys and rollbacks without committing Ghost&#39;s source.

## Requirements

Create a MySQL database on the app&#39;s Databases tab. Ghost reads its database settings as separate values, so copy the host, port, user, password and database name out of the `DATABASE_URL` Hatchbox shows you into the variables below.

## Repository

Create a new Git repository with these three files, push it, and set it as the app&#39;s Git URL with the `main` branch.

`.nvmrc` pins Node to the 22 line Ghost supports:

```
22
```

`package.json` tells Hatchbox this is a Node app. It stays minimal because the build script replaces it with Ghost&#39;s own:

```
{
  &quot;name&quot;: &quot;my-ghost&quot;,
  &quot;private&quot;: true
}
```

The third file is the build script below.

## Environment Variables

```
NODE_ENV=production
url=https://blog.example.com
database__client=mysql
database__connection__host=10.0.0.5
database__connection__port=3306
database__connection__user=ghost
database__connection__password=your-password
database__connection__database=ghost
```

Ghost reads any config key from the environment with `__` separating the levels, so these map to `database.connection.host` and so on in `config.production.json`. `url` must be the full public URL with its scheme. Hatchbox exposes the MySQL database as `DATABASE_URL`; split it into the five `database__connection__*` values.

To send email, which Ghost needs for staff invites, member signups and newsletters, add its SMTP settings the same way, for example `mail__transport=SMTP`, `mail__options__host`, `mail__options__port`, `mail__options__auth__user` and `mail__options__auth__pass`.

## Build Scripts

### .hatchbox/build

```
#!/usr/bin/env bash
set -e

GHOST_VERSION=&quot;6.67.0&quot;

# Download the release Ghost publishes to npm, the same tarball Ghost-CLI installs
TMP_DIR=&quot;$(mktemp -d)&quot;
(cd &quot;$TMP_DIR&quot; &amp;&amp; npm pack &quot;ghost@${GHOST_VERSION}&quot;)
tar -xzf &quot;$TMP_DIR&quot;/ghost-*.tgz --strip-components=1 -C .
rm -rf &quot;$TMP_DIR&quot;

# Install Ghost&#39;s dependencies with the pnpm version it pins in package.json
NODE_ENV=production COREPACK_ENABLE_DOWNLOAD_PROMPT=0 COREPACK_DEFAULT_TO_LATEST=0 \
  pnpm install --prod --reporter=append-only

# Keep the content directory outside the release so it persists across deploys
SHARED_CONTENT=&quot;$DIR/shared/content&quot;
mkdir -p &quot;$SHARED_CONTENT&quot;/{adapters,apps,data,files,images,logs,media,public,settings,themes}
cp -Rn content/. &quot;$SHARED_CONTENT/&quot;
cp -R content/themes/casper content/themes/source &quot;$SHARED_CONTENT/themes/&quot;
rm -rf content
ln -s &quot;$SHARED_CONTENT&quot; content
```

The script replaces Hatchbox&#39;s automatic build. It extracts the Ghost package over the release directory so the release becomes a normal Ghost install, installs production dependencies with pnpm through Corepack, and symlinks `content` to `shared/content`. The bundled Casper and Source themes are refreshed on every deploy; everything else in `content` is only seeded the first time.

To upgrade Ghost, change `GHOST_VERSION` and deploy. Ghost runs its database migrations when it starts.

## Processes

Add one process for the web servers:

```
server__port=$PORT node index.js
```

Ghost listens on `server.port`, so the command passes Hatchbox&#39;s `PORT` through the matching environment variable. It binds to `127.0.0.1` by default, which is where Caddy proxies to.

## First Login

Open `https://blog.example.com/ghost` after the first deploy. Ghost shows its setup screen, where you create the owner account. There are no default credentials.

## Notes

Uploads, themes, routes, redirects and logs live in `content`, which lives on the server&#39;s disk under `shared/content`, so run Ghost on a single web server or move uploads to S3 with a storage adapter.

Ghost writes its production logs to `content/logs` by default. Set `logging__transports=[&quot;stdout&quot;]` to send them to Hatchbox&#39;s logs instead.
