3.5: Application Deployment

If you have time, deploy your Bigfoot project to learn full-stack app deployment prior to Project 3. We will need to deploy the backend (Express && Sequelize) and frontend (React App) onto separate servers.

Backend

To test out and deploy our applications, you can deploy your own exercises or you can deploy this repo's code. Clone the application pull the correct branch, deployment_example.

cd inside the cloned directory and run the command below:

git fetch origin deployment_example

git checkout deployment_example

Context

We will be using Fly.io to host the backend of our application, Fly.io is similar to one of the most popular application hosting services, Heroku. We are unable to user Github Pages or Firebase Hosting to deploy our backend server as those tools only support static sites, i.e. applications that do not have a database. You are able to easily sign up for Fly.io, it offers easy deployment that can be achieved through the CLI.

Note: You made be asked for credit card credentials when deploying on fly.io, don't worry, sign up for the free tier service and you will not be charged. If you deploy multiple projects you may incur costs.

Instructions

Create a new account on Fly.io and follow the official Node.js deployment guide to set up and deploy our backend app to Fly.io. Refer to the instructions below while creating setting up your deployed application.

  • You will need to complete the prerequisites listed within the Fly guide. If you haven't already, create a free Fly account. Install the Fly CLI by following installation instructions.

  • Make sure you are logged in, on the Fly CLI.

  • Change directory to the root level of your backend project.

  • Run the command flyctl launch

  • Add an Application name: i.e. bigfootsqlrocket

  • Choose location: i.e. Singapore

  • Setup Postgresql database now? Type: 'y'.

  • Choose (use arrow keys): Development - Single node, 1x shared CPU, 256MB RAM, 1GB disk (press enter)

  • Scale single node pg to zero after one hour? (y/N) Type: 'N'.

  • Fly will link the an empty PostgreSQL Database straight to your deployed backend. Save the credential details they provide for you somewhere, you will not be able to access this information again. These credentials are vital if your backend needs to interface with your database.

  • Fly will create new fly.toml file within your application directory. If it doesn't please make it yourself.

  • It might ask you to use a Redis Deployment. Type "N".

  • It will ask you to deploy your application? Type: "N".

  • Alter the file config/database.js add in a production block that will be used to connect to your database when running Sequelize CLI commands. These env variables will be placed in our fly.toml file later on.

require("dotenv").config();
module.exports = {
  development: {
    username: process.env.DB_USERNAME,
    password: process.env.DB_PASSWORD,
    database: process.env.DB_NAME,
    host: process.env.DB_HOST,
    dialect: process.env.DB_DIALECT,
  },
  production: {
    username: process.env.USERNAME,
    password: process.env.PASSWORD,
    database: process.env.DATABASE,
    host: process.env.HOST,
    dialect: process.env.DIALECT,
  },
};
  • Alter your index.js within the model directory, we need to alter the Sequelize connection to connect to the newly deployed application. Replace the existing Sequelize connection block with the block below, ensure that you alter the env environment to production as well. These environmental variables will be provided within the fly.toml file.

const env = process.env.NODE_ENV || "production";
const config = require(__dirname + "/../../config/database.js")[env];

require('dotenv').config()
if (process.env.DATABASE_URL) {
  sequelize = new Sequelize(
  process.env.DATABASE,
  process.env.USERNAME,
  process.env.PASSWORD,
  {
    host: process.env.HOST,
    dialect: process.env.DIALECT,
  }
);
} else if (config.use_env_variable) {
  sequelize = new Sequelize(process.env[config.use_env_variable], config);
} else {
  sequelize = new Sequelize(
    config.database,
    config.username,
    config.password,
    config
  );
}
  • Alter the root index.js within this directory, we need to ensure that the application will use the environmental variables from fly, otherwise fly wont be able to test our application. Our backend must listen to port 3000 as this is what fly is expecting.

const PORT = process.env.PORT || 3000;
  • Alter the fly.toml file that was created, add in a deploy release_command, we will also need to set out our environmental variables for fly. Make up a Database name, this Database will be created, migrated and seeded.

 [build]
 
 [deploy]
  release_command = "sh ./release.sh"
 
 [env]
  PORT = "3000"
  USERNAME = "<Generated-Database-Username>"
  PASSWORD = "<Generated-Database-Password>"
  DATABASE = "<Database-Name>"
  HOST = "<Generated-Database-Host>"
  DIALECT = "postgres"
  NODE_ENV = "production"
  
[http_service]
  internal_port = 3000
  force_https = true
  auto_stop_machines = false
  auto_start_machines = true
  min_machines_running = 1
  processes = ["app"]
  • Change the above from '<Generated-.....> to the credentials that were given to you from fly.io when the database credentials were created above.

  • The DATABASE here needs to match the one you created when running flyctl launch, fly.io generates a database name from the name of your app. I.E. bigfootsqlrocket-db

  • NOTE: if you are hosting your own website you will need to add all of your .ENV variables into the toml.file

  • At this point we need to update the .gitignore such that we do not send our fly.toml file online with our database credentials.

release.sh

  • Create a release.sh file in the root of your project directory, within this file we need to place all the commands that will help us to setup our database, please create the file as below.

npx sequelize db:create
npx sequelize db:migrate
npx sequelize db:seed:all

We are able to run any CLI command from the release.sh, just make sure that you have installed the pre-requisite dependancies.

Dockerfile

When you ran flyctl launch a Dockerfile was generated, we will need to ensure that our release.sh file is used an ran within the fly.io envrioment. Alter the Docker file to the file below:

FROM debian:bullseye as builder

ENV PATH=/usr/local/node/bin:$PATH
ARG NODE_VERSION=16.15.1

RUN apt-get update; apt install -y curl python-is-python3 pkg-config build-essential && \
    curl -sL https://github.com/nodenv/node-build/archive/master.tar.gz | tar xz -C /tmp/ && \
    /tmp/node-build-master/bin/node-build "${NODE_VERSION}" /usr/local/node && \
rm -rf /tmp/node-build-master

RUN mkdir /app
WORKDIR /app

COPY . .

RUN npm install

FROM debian:bullseye-slim

LABEL fly_launch_runtime="nodejs"

COPY --from=builder /usr/local/node /usr/local/node
COPY --from=builder /app /app
COPY release.sh /release.sh

WORKDIR /app
ENV NODE_ENV production
ENV PATH /usr/local/node/bin:$PATH

CMD [ "npm", "run", "start" ]

If a .dockerignore file has been generated please ensure that the release.sh and fly.toml files are not ignored.

Run flyctl deploy, you are able to monitor the backend execution as well as the release commands through the fly.io dashboards.

  • Test our backend with Thunder Client! We should now be able to query our API server and retrieve results from our seed data.

  • You can find the deployed backend url on your fly.io dashboard as seen in the images below.

  • If this isn't working try to add in some secrets into the flyctl CLI

Extra Reading

What is a fly.toml for?

The Fly.io platform makes use of the fly.toml to configure the application during deployment. Within the fly.toml file we can control the configuration of the build, any environmental variables, exposed resources as well as any release commands. In the example application that you have just deployed you added fly.toml environmental variables. The express application can now interface with the deployed database, using the environmental variables just added. We also got you to develop a shell file that would be run from the release command within the fly.toml. These shell command are run within the deployed environment setting up the database and seeding it.

If you want to look in-depth at all of the configurations that you can create please have a read of this set of documentation.

Frontend

To deploy your frontend application we will be using Netlify, you can either deploy your own version of the bigfoot-sql-frontend or clone this repo. After cloning you will need to get the correct branch, deployment_example, cd inside the cloned directory and run the commands below:

git fetch origin deployment_example

git checkout deployment_example

Context

We will deploy our frontends to a simple static site deployment service called Netlify to give us exposure to another static site deployment service. We are unable to deploy Bigfoot to GitHub Pages because GitHub Pages does not support frontend routing, and Netlify is simpler and just as popular as Firebase.

Instructions

Update the BACKEND_URL we defined in src/constants.js from the Bigfoot JSON exercise to reference our deployed fly.io backend's URL in production. This URL should be the one that is seen on the fly.io dashboard. So please replace URL in the code below with your own! We can tell we're in production when the NODE_ENV environment variable is set to "production". Rocket's constants.js looks like the following:

constants.js
export const BACKEND_URL =
  process.env.NODE_ENV === "production"
    ? "https://bigfootsqlrocket.fly.dev"
    : "http://localhost:3000";

Create a production build of the app with npm run build from the Bigfoot Frontend repo folder. Then follow Create React App Netlify deploy instructions to deploy. You may need to create a Netlify account if you don't have one already.

Within the netlify deploy menu select the following options.

  1. Choose "Create & configure a new site"

  2. Choose a Netlify "team" you are on (can be your personal team)

  3. Can leave site name blank to let Netlify choose random name

  4. Enter build as the publish directory

  5. Once ready to deploy to prod, run netlify deploy --prod

That's it! The site should be up at the Website URL in the Netlify CLI output.

Note: If you are deploying your own website that uses auth0, you will need to alter the redirect URI and allowed callbacks to your deployed website.

Last updated