Deploying Ghost on App Engine flexible environment
Contributed by Google employees.
This tutorial explains how to deploy and scale a Ghost blog on the App Engine flexible environment.
Ghost is a simple blogging platform that can be self-hosted. It's built with Node.js, and it can be customized or transformed into a bigger site. It serves as a template for a larger application.
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, including Cloud SQL, Cloud Source Repositories, Cloud 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 Google Cloud, including:
- Google Cloud SQL
- App Engine flexible environment
Use the pricing calculator to generate a cost estimate based on your projected usage.
Before you begin
- Select or create a Google Cloud project. Go to the projects page.
- Enable billing for your project. Enable billing.
- Install the Cloud SDK.
Authenticate
gcloud
with Google Cloud:gcloud init
Create a new Second Generation Cloud SQL instance. You can do this from the Cloud Console or via the Cloud SDK.
- 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
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
YOUR_INSTANCE_NAME
is the name you chose in step 1.YOUR_INSTANCE_ROOT_PASSWORD
is a password of your choice.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.
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 &
YOUR_INSTANCE_CONNECTION_NAME
is the connection name of your instance on its overview page in the Cloud Console, or useYOUR_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'@'%';
You will be asked to enter the root password you chose earlier.
Set the
MYSQL_USER
,MYSQL_PASSWORD
, andMYSQL_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.
Configure
Create a
config.development.json
file from the default configuration 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
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 tofalse
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 # Cloud 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 toautomatic_scaling
and configure according to the documentation.resources
: You didn't change this setting, but the default instance size corresponds to ag1.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:
NODE_ENV=production knex-migrator init --mgpath node_modules/ghost
Add
"socketPath": "/cloudsql/YOUR_INSTANCE_NAME"
in the connection properties section of yourconfig.production.json
, so you end up with the following:{ "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 App Engine, but it causes knex-migrator
to throw an error.
Deploy the app:
gcloud app deploy
After deployment completes, view your deployed app at
https://YOUR_PROJECT_ID.appspot.com
(in whichYOUR_PROJECT_ID
is your Google Cloud project ID).
What's next
Monitoring Ghost on App Engine flexible environment - Part 2
Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 4.0 License, and code samples are licensed under the Apache 2.0 License. For details, see our Site Policies. Java is a registered trademark of Oracle and/or its affiliates.