Skip to content
This repository was archived by the owner on Jul 7, 2025. It is now read-only.

Deployment

Enrique Vidal edited this page Jan 8, 2019 · 6 revisions

There's multiple ways to deploy your apps depending on your current application setup worry not for we will cover a couple here in hopes you find any of these convenient for you.

Setting up a Proxy with Nginx

This is important since we're running an express app you'll need a reverse proxy to send request from port 80 to your node app(s).

We're going to assume you've already installed nginx and you're just missing the configuration for this app.

server {
  listen 80;
  listen [::]:80;

  server_name webapp.com www.webapp.com;

  location / {
    proxy_pass http://localhost:8080;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;
  }
}

Deployment via PM2

You can install PM2 to manage your app, it's got a simple configuration and you can use it to power multiple apps at the same time and use nginx to proxy said apps.

Setting the app

First make sure you got enough rights to install pm2 globally in the server, then:

npm install pm2 -g

You can create config file for all your apps in your home directory:

// $HOME/ecosystem.config.js

module.exports = {
  apps: [
    {
      name: 'webapp',
      script: 'build/bundle.js', // this is the server bundle
      cwd: 'webapp',
      instances: 1,
      autorestart: true,
      max_memory_restart: '1G',
      env: {
        NODE_ENV: 'production',
        PORT: 8080,
      }
    }
  ]
};

We're going to assume that your web app will live in $HOME/webapp so once you've clone and built or clone and upload into $HOME/webapp run:

pm2 start

Set up the nginx config posted above in your server's available sites directory and restart nginx, and that's it you should now be able to browse your app through port 80.

Docker

This boilerplate comes with a Dockerfile for running the app in production, so to run this app in Docker containers you only need to do the following:

Make sure you save the nginx config posted above into config/nginx.conf then you'll need to create a docker-compose.yml file in your projects root directory with the following content:

version: "3"
services:
  proxy:
    image: "nginx:alpine"
    command: ["nginx-debug", "-g", "daemon off;"]
    ports:
      - 80:80
    environment:
      - NGINX_HOST=webapp.dev
      - NGINX_PORT=80
    volumes:
      - ./config/nginx.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - webapp

  webapp:
    build:
      context: .
      dockerfile: Dockerfile
    image: "webapp:boiler"
    env_file: .env

Afterwards simply run:

docker-compose build # this builds your app into a docker container
docker-compose up # spins up your app and the proxy server

You should now be able to visit your web app via port 80.

Github Pages

Github pages don't have support for a backend server, for such instances, only the client code is needed. In order to do so, we need to install a webpack plugin that uses an html template.

Keep in mind that for routing to work with multiple pages you'll need to use <HashRouter />. You can obtain more information here (HashRouter API Docs @ reacttraining.com).

First let's start by installing one dependency:

npm install -D html-webpack-plugin@latest

Then we'll need to create an html template for our github page so under src/gh-pages.html save:

<!doctype html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <link rel="stylesheet" href="vendors.css">
    <link rel="stylesheet" href="styles.css">
    <script src="vendors.js"></script>
  </head>
  <body>
    <div id="app">
    </div>
    <script src="bundle.js"></script>
  </body>
</html>

Now to get to the meat of this we'll need github pages webpack recipe, this will be basically identical to the client's production recipe and given that the webpack recipes are nothing more than objects we can import we can make use of node modules to extend the production config, save the following to config/webpack/gh-pages.js:

const path = require('path');
const production = require('./production');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const bundlePath = path.join(__dirname, '../../gh-pages');

const plugins =  production.plugins.concat([
  new HtmlWebpackPlugin({
    template: path.resolve(__dirname, '../../src/gh-pages.html'),
  }),
]);

const output = Object.assign(production.output, { path: bundlePath });

module.exports =  Object.assign(production, { output, plugins });

You can see that we've only injected html-webpack-plugin and changed the output dir, everything else intact.

Lastly we'll add a new environment to our webpack.client.js, adding environments is actually really simple here's how:

const prodConfig = require('./config/webpack/production');
const devConfig = require('./config/webpack/development');
const ghPages = require('./config/webpack/gh-pages');

const PRODUCTION = 'production';
const GH_PAGES = 'gh-pages';

const reduceEnv = function(environment) {
  switch(environment) {
    case PRODUCTION:
      return prodConfig;

    case GH_PAGES:
      return ghPages;

    default:
      return devConfig;
  }
};

module.exports = reduceEnv(process.env.NODE_ENV);

The moment of truth, we compile our gh-pages bundle like this:

NODE_ENV=gh-pages npx webpack --config webpack.client.js

You can put this in the scripts section of package.json for faster access if you like.

Now it's just a matter of using git subtree to push your bundled code to gh-pages:

git add gh-pages && git commit -m "My gh-pages commit"
git subtree push --prefix gh-pages origin gh-pages

Clone this wiki locally