Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
275 changes: 275 additions & 0 deletions content/guides/tutorial-ghost-blog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
---
type: docs
title: Ghost Blog
description: This article shows you how to deploy a Ghost blog on Clever Cloud.
tags:
- deploy
keywords:
- node.js
- ghost
---

## Overview

[Ghost](https://ghost.org) is a modern, open-source publishing platform ideal for bloggers and content creators. This guide will walk you through the process of deploying a Ghost blog on Clever Cloud using Node.js.

Check warning on line 14 in content/guides/tutorial-ghost-blog.md

View workflow job for this annotation

GitHub Actions / vale

[vale] content/guides/tutorial-ghost-blog.md#L14

[Google.WordList] Use 'open source' instead of 'open-source'.
Raw output
{"message": "[Google.WordList] Use 'open source' instead of 'open-source'.", "location": {"path": "content/guides/tutorial-ghost-blog.md", "range": {"start": {"line": 14, "column": 41}}}, "severity": "WARNING"}

Check warning on line 14 in content/guides/tutorial-ghost-blog.md

View workflow job for this annotation

GitHub Actions / vale

[vale] content/guides/tutorial-ghost-blog.md#L14

[Google.Will] Avoid using 'will'.
Raw output
{"message": "[Google.Will] Avoid using 'will'.", "location": {"path": "content/guides/tutorial-ghost-blog.md", "range": {"start": {"line": 14, "column": 125}}}, "severity": "WARNING"}

### Prerequisites

- **Node.js 20**
- **MySQL**
- **Cellar S3**
- **Ghost-CLI**
- **Clever Tools CLI** ([documentation](https://www.clever-cloud.com/developers/doc/cli/))
- **Git**

## Installation and Configuration

### Initialize Your Project
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As this part is mostly moving files/editing config of the Ghost project, maybe we could just:

  • Do it in a Clever Cloud repo
  • Provide the preconfigured repo link, users just have to clone it
  • Provide users needing more info about Ghost and how it works a link to Ghost doc


Create a project folder and install Ghost locally:

```sh
# Create the project file
mkdir myblog && cd myblog
# Install Ghost-CLI
npm install -g ghost-cli@latest
nvm use 20 #to use node 20
# Install Ghost
ghost install local
ghost stop
```

Remove the default theme and add custom theme submodules:

```sh
rm -r content/themes/casper
cp -r current/content/themes/casper/ content/themes/
git init
cd content/themes/
git submodule add https://github.com/curiositry/mnml-ghost-theme
git submodule add https://github.com/zutrinken/attila/
wget https://github.com/TryGhost/Source/archive/refs/tags/<last-version>.zip -O source.zip #check and use the lastest version https://github.com/TryGhost/Source/releases
rm -R source
unzip source.zip -d temp
mkdir source
mv temp/*/* source/
rm -R temp source.zip
```

Add the S3 module:

```sh
npm install ghost-storage-adapter-s3
mkdir -p ./content/adapters/storage
cp -r ./node_modules/ghost-storage-adapter-s3 ./content/adapters/storage/s3
```

### Create and Configure Node Application and MySQL

Use the [Clever Tools CLI](/developers/doc/cli/install):

Create the Node.js app and a MySQL add-on on Clever Cloud:

```sh
# Create the Node.js app
clever create --type node myblog

# Create MySQL add-on
clever addon create mysql-addon --plan s_sml myblogsql
clever service link-addon myblogsql
Comment on lines +78 to +79
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can link it at add-on creation

```

The Ghost configuration file can't use direct environment variables. Set the following environment variables to connect your app to the database:

```sh
clever env set database__connection__host <ADDON_HOST>
clever env set database__connection__user <ADDON_USER>
clever env set database__connection__password <ADDON_PASSWORD>
clever env set database__connection__database <ADDON_DATABASE>
clever env set database__connection__port <ADDON_PORT>
clever env set url https://<domain_URL_blog>
Comment on lines +84 to +90
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use a binding script, as we do in oTree guide for example. If the user changes the add-on or if config changes, it will still work

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Create a .sh script with the env variables directly to make everything more persistent?

```

### Install and Configure Cellar S3

Create the Cellar S3 add-on on Clever Cloud:

```sh
# Create and link Cellar add-on
clever addon create cellar-addon --plan s_sml <cellar-app>
clever service link-addon <cellar-app>
Comment on lines +99 to +100
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Link at creation

If you use a binding script maybe you can:

  • Create add-ons
  • Create the binding script
  • Configure env

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand, you want me to put a script to execute directly?

```

In your Cellar S3 add-on console, create a bucket for your blog.

Add the environment variables to configure Ghost with Cellar:

```sh
clever env set storage__s3__accessKeyId <CELLAR_ACCESS_KEY>
clever env set storage__s3__secretAccessKey <CELLAR_SECRET_KEY>
clever ens set storage__s3__assetHost <CELLAR_ADDON_HOST>
clever env set storage__s3__bucket <your-bucket>
clever env set storage__s3__region fr
```

Make sure to configure public read access in your Cellar bucket:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what the user should do with this JSON ?


```json
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::<bucket>"
},
{
"Sid": "VisualEditor1",
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:PutObjectVersionAcl",
"s3:DeleteObject",
"s3:PutObjectAcl"
],
"Resource": "arn:aws:s3:::<bucket>/*"
},
{
"Sid": "PublicReadAccess",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::<bucket>/*",
"Principal": "*"
}
]
}
```

### Create a Pre-Run Hook

In the root folder of your project, create the file `.clevercloud-pre-run-hook.sh`:

```sh
#!/bin/sh
npm install -g ghost-cli
mkdir ghost
cd ghost
ghost install local
ghost stop
cp ../config.production.json .
npm install ghost-storage-adapter-s3
mkdir -p ./content/adapters/storage
cp -r ../content/adapters/storage/s3 content/adapters/storage/s3
rm -R content/themes/source
cp -r ../content/themes/source content/themes/
Comment on lines +152 to +166
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be in the app repo, not a hook

```

Grant execution permissions to the script:

```sh
sudo chmod +x clevercloud.sh
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why sudo here ?

```

### Configure Ghost

Create the file `config.production.json` in the root folder of your project:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Provide it in a source repo, explain that the config is in this file


```json
{
"url": "https://<your-url-app>/",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can put a placeholder here and replace it with sed (for example) after domain creation/configuration

"server": {
"port": 8080,
"host": "0.0.0.0"
},
"database": {
"client": "mysql"
},
"storage": {
"active": "s3"
},
"mail": {
"transport": "SMTP"
},
Comment on lines +192 to +194
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SMTP but no config, is it mandatory?

"process": "local",
"logging": {
"level": "debug",
"transports": ["stdout"]
},
"paths": {
"contentPath": "../../../content/"
}
}
```

### Create `package.json` and `.gitignore`

Create the file `package.json`:

```json
{
"name": "ghost",
"version": "0.1.0",
"description": "",
"scripts": {
"start": "ghost run --dir ghost"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

},
"devDependencies": {},
"dependencies": {}
Comment on lines +218 to +219
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you need to install Ghost, put it here

}
```

Create the file `.gitignore`:

```
.ghost-cli
config.development.json
current
versions
node_modules
```

### Set Other Environment Variables for Your Application

Before deploying your application on Clever Cloud, make sure to set the following environment variables:

```sh
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's wait for next week and update this ;) Is yarn mandatory ? Maybe we can use it we bun without any change for example ?

clever env set CC_NODE_BUILD_TOOL yarn2
clever env set CC_NODE_VERSION 20
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why Node 20 ? It's maintenance LTS and the next end-of-life version. If it's needed we can set it. If not, maybe we can just let the LTS system version to be used or set 22 (current LTS)

clever env set CC_PRE_RUN_HOOK "./.clevercloud-pre-run-build.sh"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need for the script to start with a . and the file name can be shorter I guess

clever env set NODE_ENV production
```

#### Optional: Configure Email Service

Check warning on line 244 in content/guides/tutorial-ghost-blog.md

View workflow job for this annotation

GitHub Actions / vale

[vale] content/guides/tutorial-ghost-blog.md#L244

[Google.WordList] Use 'email' instead of 'Email'.
Raw output
{"message": "[Google.WordList] Use 'email' instead of 'Email'.", "location": {"path": "content/guides/tutorial-ghost-blog.md", "range": {"start": {"line": 244, "column": 26}}}, "severity": "WARNING"}

Ghost allows you to configure an SMTP service for sending emails (such as invitations, password resets, etc.). You can set it up using the following environment variables:

Check notice on line 246 in content/guides/tutorial-ghost-blog.md

View workflow job for this annotation

GitHub Actions / vale

[vale] content/guides/tutorial-ghost-blog.md#L246

[Google.Acronyms] Spell out 'SMTP', if it's unfamiliar to the audience.
Raw output
{"message": "[Google.Acronyms] Spell out 'SMTP', if it's unfamiliar to the audience.", "location": {"path": "content/guides/tutorial-ghost-blog.md", "range": {"start": {"line": 246, "column": 34}}}, "severity": "INFO"}

```sh
clever env set mail__from "your-email@example.com"
clever env set mail__options__service "your-mail-service" # e.g. Mailgun, Gmail, etc.
clever env set mail__options__host "smtp.yourmail.com"
clever env set mail__options__port "587"
clever env set mail__options__secureConnection "false"
clever env set mail__options__auth__user "your-smtp-username"
clever env set mail__options__auth__pass "your-smtp-password"
Comment on lines +249 to +255
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way to use mailpace here ? Maybe we can use a tab to show how to setup both classic SMTP and Mailpace?

```

> 💡 > [!NOTE] Setup email service
> These environment variables allow Ghost to connect to your email service automatically, see the [official Ghost SMTP configuration docs](https://ghost.org/docs/config/#mail) for more information.

Check notice on line 259 in content/guides/tutorial-ghost-blog.md

View workflow job for this annotation

GitHub Actions / vale

[vale] content/guides/tutorial-ghost-blog.md#L259

[Google.Acronyms] Spell out 'SMTP', if it's unfamiliar to the audience.
Raw output
{"message": "[Google.Acronyms] Spell out 'SMTP', if it's unfamiliar to the audience.", "location": {"path": "content/guides/tutorial-ghost-blog.md", "range": {"start": {"line": 259, "column": 115}}}, "severity": "INFO"}

## Deploy on Clever Cloud

Initialize git, add files, and push:

```sh
git add clevercloud.sh package.json config.production.json content
git commit -m "Initial commit"
git remote add clever <CLEVER_GIT_URL>
git push clever <branch>:master
Comment on lines +268 to +269
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

user clever deploy

```

## More Information

For a small blog, you can use the XS or S Node.js plan.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe provide this info as a [!TIP] when we tell the user how to create the application