Archival Notice
This guide was written for legacy Node.js 14 environments and Terraform 1.0 workflows. Please note that Node.js 14 has reached End of Life (EOL), and modern container deployments should utilize updated base images (node:20-alpine or node:22-bookworm-slim). Please adapt package manifests and syntax to current environment standards.
Modern cloud-native engineering requires combining application development with robust Infrastructure as Code (IaC). When deploying full-stack applications that rely on third-party OAuth authentication and persistent database storage, containerizing the architecture and managing the underlying cloud resources via code is standard practice.
In this guide, I will walk you through a complete deployment workflow: installing HashiCorp Terraform and Google Cloud SDK on Enterprise Linux, cloning and configuring a Node.js Google OAuth application (Storybooks), containerizing the Express API and MongoDB database via Docker Compose, and establishing a secure Terraform remote state backend on Google Cloud Storage (GCS).
Prerequisites
You will need an Enterprise Linux server (CentOS/RHEL or Amazon Linux) with root access, alongside a Google Cloud Platform account to configure OAuth consent screens and Service Account credentials.
Step 1: Installing HashiCorp Terraform and Google Cloud SDK
First, configure the official HashiCorp and Google Cloud repositories to install Terraform and the gcloud CLI.
Installing Terraform (CentOS / RHEL)
yum install -y yum-utils
yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
yum -y install terraform
Installing Terraform (Amazon Linux)
yum install -y yum-utils
yum-config-manager --add-repo https://rpm.releases.hashicorp.com/AmazonLinux/hashicorp.repo
yum -y install terraform
Installing Google Cloud SDK
Inject the Google Cloud repository manifest and install the SDK:
tee -a /etc/yum.repos.d/google-cloud-sdk.repo << "EOF"
[google-cloud-sdk]
name=Google Cloud SDK
baseurl=https://packages.cloud.google.com/yum/repos/cloud-sdk-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg
https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
EOF
yum install -y google-cloud-sdk
Initialize your GCP environment and authenticate:
gcloud init
Step 2: Cloning the Application and Configuring OAuth
We will deploy the open-source Storybooks application, a Node.js Express app that allows users to publish public and private stories authenticated via Google OAuth.
# Install Git and Node.js prerequisites
yum install -y git epel-release make
curl -sL https://rpm.nodesource.com/setup_14.x | sudo bash -
yum install -y nodejs
# Clone Storybooks repository
git clone https://github.com/induslevel/storybooks.git
cd /root/storybooks
# Install NPM dependencies
npm install
npm audit fix
Configuring Environment Variables
To enable Google OAuth login, create the environment configuration file /root/storybooks/config/config.env. Ensure you supply your own OAuth Client ID and Secret generated from the Google Cloud Console:
PORT = 3000
MONGO_URI=mongodb://mongo:27017/storybooks
GOOGLE_CLIENT_ID = 737957259903-sampleclientid.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET = GOCSPX-samplesecret
Step 3: Containerizing the Stack (Dockerfile and Compose)
To run the Node.js application and MongoDB database together without local host conflicts, we build a custom container image and coordinate networking via Docker Compose.
Structuring the Dockerfile
Create /root/storybooks/Dockerfile:
FROM node:14-slim
WORKDIR /usr/src/app
COPY ./package*.json ./
RUN npm install
COPY . .
USER node
EXPOSE 3000
CMD ["npm", "start"]
Build the application image:
docker build -t storybook-app .
Structuring docker-compose.yml
Create the orchestration manifest to link the API server with MongoDB:
version: '3'
services:
api-server:
build: ./
entrypoint: [ "npm", "run", "dev" ]
env_file: ./config/config.env
ports:
- '3000:3000'
networks:
- storybooks-app
volumes:
- ./:/usr/src/app
- /usr/src/app/node_modules
depends_on:
- mongo
mongo:
image: mongo:3.6-xenial
environment:
- MONGO_INITDB_DATABASE=storybooks
ports:
- '27017:27017'
networks:
- storybooks-app
volumes:
- mongo-data:/data/db
networks:
storybooks-app:
driver: bridge
volumes:
mongo-data:
driver: local
Spin up the container stack:
docker-compose up -d
Step 4: Establishing Terraform GCP Remote State
When provisioning cloud infrastructure for the Storybooks app via Terraform, storing state files locally risks secrets exposure and team concurrency conflicts. We configure a secure remote state backend on Google Cloud Storage (GCS).
1. Securing Keys (.gitignore and .dockerignore)
Generate a GCP Service Account key (terraform-sa-key.json) with Object Storage Admin privileges. Ensure this key is strictly excluded from source control and container builds:
# .gitignore
node_modules
config/config.env
*.key.json
# .dockerignore
node_modules
*.key.json
Export the credentials to your shell environment:
export GOOGLE_APPLICATION_CREDENTIALS=$PWD/terraform-sa-key.json
2. Provisioning the GCS Backend Bucket
Authenticate and create a globally unique GCS bucket to store your Terraform state:
gcloud auth login
gcloud config set project storybooks-338209
# Provision GCS bucket
gsutil mb -p storybooks-338209 gs://storybooks-338209-terraform
Global Bucket Naming
GCS bucket names must be globally unique across all Google Cloud users worldwide. If gsutil mb returns a 409 Conflict error, choose a unique naming prefix for your organization.
3. Initializing Terraform Remote State
Create your Terraform configuration (main.tf) referencing the provisioned GCS bucket:
# /root/storybooks/terraform/main.tf
terraform {
backend "gcs" {
bucket = "storybooks-338209-terraform"
prefix = "/state/storybooks"
}
}
Initialize your Terraform working directory:
terraform init
Your Node.js OAuth application is now fully containerized, orchestrated, and backed by enterprise-grade Terraform cloud infrastructure!