This tutorial explains how to deploy and scale a Ghost blog on Google App Engine Flexible Environment.

Ghost is a simple blogging platform that can be self hosted. It’s built with Node.js, and can be customized or transformed into a bigger site. It serves as a template for a larger application.

Google App Engine makes it easy to run web applications that must scale to meet worldwide demand. It lets you focus on your code without having to worry about operations, load balancing, servers, or scaling to satisfy incoming traffic.

App Engine can take a Ghost web application and scale it to handle your growing global demand, while giving you all the benefits of Google Cloud Platform, including Cloud SQL, Cloud Source Repositories, Stackdriver Debugger, Error Reporting, Logging, Monitoring, Trace, and more.

Objectives

  • Create a Cloud SQL instance, a database, and a user.
  • Download Ghost.
  • Run Ghost locally.
  • Configure Ghost for App Engine.
  • Deploy Ghost to App Engine.

Costs

This tutorial uses billable components of Cloud Platform, including:

  • Google Cloud SQL
  • Google App Engine Flexible Environment

Use the Pricing Calculator to generate a cost estimate based on your projected usage.

Before you begin

  1. Select or create a Google Cloud Platform Console project. Go to the projects page.
  2. Enable billing for your project. Enable billing.
  3. Install the Google Cloud SDK.

Authenticate gcloud with Google Cloud Platform.gcloud init

Create a new Second Generation Cloud SQL instance. You can do this from the Cloud Console or via the Cloud SDK.

  1. In order for some of the commands below to work, you need to enable the Cloud SQL Admin API.

Create it via the following SDK command:gcloud sql instances create YOUR_INSTANCE_NAME \
    --activation-policy=ALWAYS \
    --tier=db-f1-micro

where YOUR_INSTANCE_NAME is a name of your choice. *You may want to set your region –region=YOUR_REGION_NAME

Set the root password on your Cloud SQL instance:gcloud sql instances set-root-password root% YOUR_INSTANCE_NAME --password YOUR_INSTANCE_ROOT_PASSWORD

where YOUR_INSTANCE_NAME is the name you chose in step 1 and YOUR_INSTANCE_ROOT_PASSWORD is a password of your choice.

  1. Create and download a Service Account key file for your project. You will use this service account to connect to your Cloud SQL instance locally.
  2. Download and install the Cloud SQL Proxy.

Start the proxy to allow connecting to your instance from your local machine:./cloud_sql_proxy \
    -instances=YOUR_INSTANCE_CONNECTION_NAME=tcp:3306 \
    -credential_file=PATH_TO_YOUR_SERVICE_ACCOUNT_JSON_FILE &

where YOUR_INSTANCE_CONNECTION_NAME is the connection name of your instance on its Overview page in the Google Cloud Platform Console, or use YOUR_PROJECT_ID:YOUR_REGION:YOUR_INSTANCE_NAME.

Use the MySQL command line tools (or a management tool of your choice) to create a new user and database for your application:mysql -u root -p -h 127.0.0.1
  mysql> create database `YOUR_DATABASE`;
  mysql> create user 'YOUR_USER'@'%' identified by 'PASSWORD';
  mysql> grant all on YOUR_DATABASE.* to 'YOUR_USER'@'%';

  1. Set the MYSQL_USERMYSQL_PASSWORD, and MYSQL_DATABASE environment variables (see below). This allows your local Ghost app to connect to your Cloud SQL instance through the proxy.

In adding Cloud SQL, dependencies need to be added in package.json for Google Cloud Node."dependencies": {
  "express": "^4.16.3",
  "mysql": "^2.15.0",
  "prompt": "^1.0.0"
}

Install Ghost as an NPM Module

Follow the instructions on the Ghost website to install Ghost as an NPM Module.

Configure

Create a config.development.json file from the default config file:cp node_modules/ghost/core/server/config/env/config.development.json config.development.json

Create a config.production.json file from the default config file:cp node_modules/ghost/core/server/config/env/config.production.json config.production.json

Run the app locally

Edit config.development.json and set it to the following:{
    "url": "http://localhost:2368",
    "fileStorage": false,
    "mail": {},
    "database": {
        "client": "mysql",
        "connection": {
            "host": "127.0.0.1",
            "user": "YOUR_MYSQL_USERNAME",
            "password": "YOUR_MYSQL_PASSWORD",
            "database": "YOUR_MYSQL_DATABASE_NAME",
            "charset": "utf8"
        },
        "debug": false
    },
    "paths": {
        "contentPath": "content/"
    },
    "privacy": {
        "useRpcPing": false,
        "useUpdateCheck": true
    },
    "useMinFiles": false,
    "caching": {
        "theme": {
            "maxAge": 0
        },
        "admin": {
            "maxAge": 0
        }
    }
}

Install Dependencies:npm install --production

Start the app:npm start

To view the app, browse to:http://localhost:2368

  1. Now stop your app by pressing Ctrl+C.

Deploy

Edit config.production.json and set it to the following:{
    "url": "https://YOUR_PROJECT_ID.appspot.com",
    "fileStorage": false,
    "mail": {},
    "database": {
        "client": "mysql",
        "connection": {
            "user": "YOUR_MYSQL_USERNAME",
            "password": "YOUR_MYSQL_PASSWORD",
            "database": "YOUR_MYSQL_DATABASE_NAME",
            "charset": "utf8"
        },
        "debug": false
    },
    "server": {
        "host": "0.0.0.0",
        "port": "8080"
    },
    "paths": {
        "contentPath": "content/"
    },
    "logging": {
        "level": "info",
        "rotation": {
            "enabled": true
        },
        "transports": ["file", "stdout"]
    }
}

Here’s some information about each setting:

  • url – The url at which the blog will be deployed. This is the url users will use to access the blog.
  • fileStorage – Setting this value to false forces image uploads to use an image url because App Engine doesn’t have persistent disks. Without this setting, any photos uploaded to the blog will eventually disappear.
  • mail – Configure this setting according to the instructions at http://support.ghost.org/mail/.
  • database – Tells Ghost how to connect to the Cloud SQL instance.
  • server – Tells Ghost how to listen for web traffic.

Prepare for deployment. Create an app.yaml file with the following contents:runtime: nodejs
env: flex
manual_scaling:
  instances: 1
env_variables:
  MYSQL_USER: YOUR_MYSQL_USER
  MYSQL_PASSWORD: YOUR_MYSQL_PASSWORD
  MYSQL_DATABASE: YOUR_MYSQL_DATABASE
  # e.g. my-awesome-project:us-central1:my-cloud-sql-instance-name
  INSTANCE_CONNECTION_NAME: YOUR_PROJECT_ID:YOUR_REGION:YOUR_INSTANCE_NAME
beta_settings:
  # The connection name of your instance on its Overview page in the Google
  # Cloud Platform Console, or use `YOUR_PROJECT_ID:YOUR_REGION:YOUR_INSTANCE_NAME`
  cloud_sql_instances: YOUR_PROJECT_ID:YOUR_REGION:YOUR_INSTANCE_NAME
skip_files:
  - ^(.*/)?#.*#$
  - ^(.*/)?.*~$
  - ^(.*/)?.*\.py[co]$
  - ^(.*/)?.*/RCS/.*$
  - ^(.*/)?\..*$
  - ^(.*/)?.*\.ts$
  - ^(.*/)?config\.development\.json$

Here’s some information about each setting:

  • runtime – Tells App Engine to use the Node.js runtime.
  • manual_scaling – Forces App Engine to run one and only one instance. To automatically scale, remove this setting or change to automatic_scaling and configure according to the documentation.
  • resources – You didn’t change this setting, but the default instance size corresponds to a g1.small virtual machine. You can configure smaller or larger instances sizes as required. See the documentation.Read more about using app.yaml.

Migrate the database to allow use in production, with:NODE_ENV=production knex-migrator init --mgpath node_modules/ghost

Add "socketPath": "/cloudsql/YOUR_INSTANCE_NAME" in the connection properties section of your config.production.json, so you end up with:{
    "url": "http://YOUR_PROJECT_ID.appspot.com",
    "fileStorage": false,
    "mail": {},
    "database": {
        "client": "mysql",
        "connection": {
            "socketPath": "/cloudsql/YOUR_INSTANCE_NAME",
            "user": YOUR_MYSQL_USERNAME,
            "password": YOUR_MYSQL_PASSWORD,
            "database": YOUR_MYSQL_DATABASE_NAME,
            "charset": "utf8"
        },
        "debug": false
    },
    "server": {
        "host": "0.0.0.0",
        "port": "8080"
    },
    "paths": {
        "contentPath": "content/"
    },
    "logging": {
        "level": "info",
        "rotation": {
            "enabled": true
        },
        "transports": ["file", "stdout"]
    }
}

It’s very important that you only do this step after migrating the database. The socketPath property is required to deploy on Google App Engine, but it causes knex-migrator to throw an error.

Run the following command to deploy the app:gcloud app deploy

After deployment completes, view your deployed app at:https://YOUR_PROJECT_ID.appspot.com

Where YOUR_PROJECT_ID is your Google Cloud Platform project ID.

What’s next

Monitoring Ghost on App Engine Flexible Environment – Part 2

See more by @jmdobry @hnipps @amensah and more tagged App EngineGhostNode.js