Google Cloud - App Engine

Google Cloud App Engine is a fully managed serverless platform.

Requirements

App Engine Files

The configuration for the App Engine server is placed at the app-engine.environment.yaml file.

backend/app-engine.production.yaml

backend/app-engine.staging.yaml

runtime: nodejs10
instance_class: F4_1G
env_variables:
# MongoDB only
DATABASE_CONNECTION: ''
DATABASE_TRANSACTIONS: false
# END - MongoDB only
# SQL only
DATABASE_USERNAME: 'postgres'
DATABASE_DIALECT: 'postgres'
DATABASE_PASSWORD: ''
DATABASE_DATABASE: 'production'
DATABASE_HOST: ''
DATABASE_LOGGING: 'true'
# END - SQL only
DATABASE_INDIVIDUAL_CONNECTIONS_PER_REQUEST: 'false'
TENANT_MODE: 'multi'
AUTH_JWT_SECRET: 'GENERATE_SOME_RANDOM_UUID_HERE'
AUTH_JWT_EXPIRES_IN: '7 days'
SENDGRID_EMAIL_FROM: ''
SENDGRID_KEY: ''
SENDGRID_TEMPLATE_EMAIL_ADDRESS_VERIFICATION: ''
SENDGRID_TEMPLATE_INVITATION: ''
SENDGRID_TEMPLATE_PASSWORD_RESET: ''
FRONTEND_URL: 'https://domain.com:<port>'
FRONTEND_URL_WITH_SUBDOMAIN: 'https://[subdomain].domain.com:<port>'
BACKEND_URL: 'https://YOUR_SERVER_URL/api'
PLAN_STRIPE_SECRET_KEY: ''
PLAN_STRIPE_WEBHOOK_SIGNIN_SECRET: ''
PLAN_STRIPE_PRICES_GROWTH: ''
PLAN_STRIPE_PRICES_ENTERPRISE: ''
FILE_STORAGE_PROVIDER: 'gcp'
FILE_STORAGE_BUCKET: ''
GOOGLE_CLOUD_PLATFORM_CREDENTIALS: '{ "type": "service_account", "project_id": "...", "private_key_id": "...", "private_key": "...", "client_email": "...", "client_id": "...", "auth_uri": "...", "token_uri": "...", "auth_provider_x509_cert_url": "...", "client_x509_cert_url": "..." }'
AWS_ACCESS_KEY_ID: ''
AWS_SECRET_ACCESS_KEY: ''

FRONTEND_URL and FRONTEND_URL_WITH_SUBDOMAIN

Set this to your hosted frontend URL (if you have one already).

BACKEND_URL

Set this one with the URL you received after the first deployment. Don't forget to add the /api suffix. It will be something like https://project-id.appspot.com/api.

Git Ignore

Because that the app-engine.environment.yaml contains sensitive information, is recommended to add it to .gitignore.

backend/.gitignore

node_modules/
/data
dist/
app-engine.staging.yml
app-engine.production.yml

Files ignored by Git are different from the ones ignored by the Google Cloud Platform, so you must create a .gcloudignore file.

backend/.gcloudignore

.gcloudignore
.git
.gitignore
node_modules/

Google Cloud Project

Go to https://cloud.google.com/ and create an account.

Create a new project for the production environment. To create a staging environment the steps are the same.

Enable billing

The project needs the billing enabled: https://cloud.google.com/billing/docs/how-to/modify-project.

Google SDK

Install the https://cloud.google.com/sdk.

Sign in to your account calling gcloud auth login.

Build

Before deploying, you must install the dependencies and build the application:

npm install
npm run build

Replace the start script

App Engine uses the start script to run the application, but our start script also compiles and watches for changes, which isn't needed for production.

Let's replace the original for npm run start:watch, that we will run on localhost, and leave the npm start for the App Engine.

backend/package.json

{
"scripts": {
...
"start": "node ./dist/server.js",
"start:watch": "nodemon --watch \"src/**/*.ts\" -e ts,json --exec \"ts-node --transpile-only ./src/server.ts\"",
...
}
}

Deployment Script

To deploy the application you must run this command:

gcloud app deploy app-engine.staging.yaml --project PROJECT-ID

Let's create deployment scripts to automate this:

backend/package.json

{
...
"scripts": {
...
"deploy:staging": "npm run build && gcloud app deploy app-engine.staging.yaml --project PROJECT-ID-STAGING",
"deploy:production": "npm run build && gcloud app deploy app-engine.production.yaml --project PROJECT-ID-PRODUCTION"
}
...
}

Now run:

npm run deploy:staging
// or
npm run deploy:production