How to Deploy a MERN Application on Ubuntu 20.04

Updated on March 23, 2021
How to Deploy a MERN Application on Ubuntu 20.04 header image

The MERN stack consists of MongoDB, Express, React, and Node.js. Together, they allow developers to build applications on the web.

Prerequisites

1. Install Node.JS

Install the latest LTS version of Node.js via the NodeSource repository to ensure maximum compatibility with any packages or dependencies in the app.

  1. Import the package signing key.

     $ wget -qO- https://deb.nodesource.com/gpgkey/nodesource.gpg.key | sudo apt-key add -
  2. Add the NodeSource repository.

     $ echo 'deb https://deb.nodesource.com/node_14.x focal main' | sudo tee -a /etc/apt/sources.list
  3. Update package lists.

     $ sudo apt update
  4. Install Node.JS.

     $ sudo apt install -y nodejs

2. Install MongoDB

MongoDB is the database that stores all the data for the application. MongoDB also provides a recommended repository for Ubuntu with the latest version.

  1. Import package signing key.

     $ wget -qO- https://www.mongodb.org/static/pgp/server-4.4.asc | sudo apt-key add -
  2. Add MongoDB repository.

     $ echo 'deb [arch=amd64] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/4.4 multiverse' | sudo tee -a /etc/apt/sources.list
  3. Update package lists.

     $ sudo apt update
  4. Install MongoDB Community Edition.

     $ sudo apt install -y mongodb-org
  5. Enable and start MongoDB.

     $ sudo systemctl enable --now mongod

3. Setup the NPM Project

  1. Create a new directory for the app.

     $ mkdir -p app && cd app
  2. Create a package.json file.

     $ npm init -y
  3. Install the project dependencies: Express web framework, MongoDB driver, React, React DOM, Webpack, Babel, and Dotenv.

     $ npm i express mongodb react react-dom webpack webpack-cli html-webpack-plugin @babel/core @babel/preset-env @babel/preset-react babel-loader dotenv
  4. Create directories for the code.

     $ mkdir src
     $ mkdir src/public
  5. Create src/index.js, which contains the main server code for Express.

     $ nano src/index.js

    Paste the following:

     if (process.env.NODE_ENV !== "production") {
       require("dotenv").config();
     }
    
     const path = require("path");
     const express = require("express");
     const app = express();
     const { MongoClient } = require("mongodb");
    
     (async () => {
       const mongo = new MongoClient(process.env.MONGODB);
    
       try {
         await mongo.connect();
       } catch (e) {
         console.log("Failed connecting to MongoDB");
         console.log(e);
         process.exit(1);
       }
    
       console.log("Connected to MongoDB");
    
       app.use(express.static(path.join(__dirname, "../dist")));
       app.listen(process.env.PORT);
    
       console.log(`HTTP listening on ${process.env.PORT}`);
     })();
  6. Save and exit the file.

  7. Create src/public/App.jsx, which includes the main code for the React portion of the app.

     $ nano src/public/App.jsx

    Paste the following:

     import React from "react";
     import ReactDOM from "react-dom";
    
     const App = () => (
       <div>
         <h1>App</h1>
       </div>
     );
    
     ReactDOM.render(<App />, document.querySelector("#app"));
  8. Save and exit the file.

  9. Create src/public/index.html, which includes the base HTML which the compiled React code will be injected into. It also has the root element that it will render in.

     $ nano src/public/index.html

    Paste the following:

     <!DOCTYPE html>
     <html lang="en">
     <head>
         <meta charset="UTF-8">
         <title>MERN App</title>
     </head>
     <body>
         <div id="app"></div>
     </body>
     </html>
  10. Save and exit the file.

  11. Create webpack.config.js, which tells Webpack how to bundle the project.

     $ nano webpack.config.js

    Paste the following:

     module.exports = {
       entry: "./src/public/App.jsx",
       module: {
         rules: [
           {
             test: /\.(js|jsx)$/,
             use: "babel-loader",
           },
         ],
       },
       plugins: [
         new (require("html-webpack-plugin"))({
           template: "./src/public/index.html",
         }),
       ],
     };
  12. Save and exit the file.

  13. Create .babelrc, which configures Babel to compile the React code.

     $ nano .babelrc

    Paste the following:

     {
       "presets": ["@babel/preset-env", "@babel/preset-react"]
     }
  14. Save and exit the file.

  15. Create .env, which configures the port and MongoDB database URL.

     $ nano .env

    Paste the following:

     PORT=8080
     MONGODB=mongodb://localhost
  16. Save and exit the file.

  17. Build the app.

     $ npx webpack
  18. Start the app.

     $ node src/index.js

The app should now be available on port 8080.