Production deployment Strapi + Gatsby app on VPS Shared Hosting: Deploy,  web hooks & https. (3)
Tags: react, javascript, webdev, gatsby
Published: 2021-04-23 09:50:33

# Production deployment Strapi + Gatsby app on VPS Shared Hosting: Deploy, web hooks & https.(3)

Welcome to the last part of Strapi + Gatsby deployment tutorial 👋 

If you don't like to read a lot of text, the finished project is [here](https://github.com/danielkrupnyy/Production-deployment-Strapi-Gatsby.git) 🤗

Let's go to work 💪

---

# Table Of Contents:
   * [Deployment Strapi and Gatsby](#deployment)
    * [Opening FTP/SFTP connection](#ftp)
    * [Preparing to upload](#preparing)
    * [Creating Authenticated Requests](#authenticated)
     * [Installing necessary dependencies](necessary_dependencies)
     * [Adjusting configs](#adjusting_configs)
    * [Uploading](#uploading)
    * [Installing Dependencies](#dependencies)
   * [Enabling SSL(HTTPS)](#ssl)
   * [Testing our apps](#testing)
   * [Automatisation with PM2](#pm2)
   * [Creating Webhooks](#webhooks)
    * [Installing GO Language](#go)
    * [Installing Webhook tool](#tool)
    * [Creating configs for webhook tool](#configs)
   
---

## Deployment Strapi and Gatsby <a name="deployment"></a>
Some hosts may provide you with a user interface to deploy data, but unfortunately not each. That's why in our case we will using classic FTP/SFTP connection.

### Opening FTP/SFTP connection <a name="ftp"></a>
All data for connection by FTP/SFTP you can find on your host.

I prefer to use [Cyberduck client](https://cyberduck.io/) for such purposes. You can use it or something like [FileZilla](https://filezilla-project.org/).

Here is the video how to open [FTP/SFTP connection using Cyberduck](https://www.youtube.com/watch?v=7c8SYE2ALRc).

### Preparing to upload <a name="preparing"></a>
Before you upload Gatsby files to server, you need to
install [fs-extra](https://www.npmjs.com/package/fs-extra) package:
```
npm install fs-extra
```

Then change "*gatsby-node.js*" file or create it and put this code inside:
```javascript
const fs = require("fs-extra");
const path = require("path");

// ...

exports.onPostBuild = () => {
  fs.copySync(
    path.join(__dirname, "public"),
    path.join(__dirname, "public_shtml"),
    { overwrite: true }
  );
  fs.removeSync(path.join(__dirname, "public"));
};
```
This code will change the name of the "*public*" folder to "*public_html*" so that VestaCP can read the statically generated files after build.

### Creating Authenticated Requests <a name="authenticated"></a>
In the [first part](https://dev.to/danielkrupnyy/production-deploying-strapi-gatsby-app-to-vps-share-hosting-preparing-authenticated-requests-1-4i86) we Configured Authenticated Requests in Strapi and created new Role and User for it.
Now is time to create Authenticated Requests.

#### Installing necessary dependencies <a name="necessary_dependencies">
First install all dependencies to Gatsby:
```bash
yarn add axios isomorphic-fetch gatsby-source-graphql @apollo/client
```
Then install dependencies for Strapi:
```bash
yarn strapi install graphql
```
Now explanations. Let's start with [ApolloClient](https://www.apollographql.com/docs/react/)(`@apollo/client`).

[ApolloClient](https://www.apollographql.com/docs/react/) is a comprehensive state management library for JavaScript that enables you to manage both local and remote data with GraphQL. **Use it to fetch, cache, and modify application data, all while automatically updating your UI**.

In our case that library will be helpful to get token from Strapi. 

Since Apollo working with GraphQL we installed to Strapi `graphql` [package that recreate data in GraphQL format](https://strapi.io/documentation/developer-docs/latest/development/plugins/graphql.html#registration). And also we installed `gatsby-source-graphql` in Gatsby to get data in this format.

Packages `axios` and `isomorphic-fetch` will be helpful for fetching data. 

#### Adjusting Configs <a name="adjusting_configs">
Go to `gatsby-config.js` file and find there `gatsby-source-strapi` plugin. Extend it add:
```javascript
    {
      resolve: "gatsby-source-strapi",
      options: {
        apiURL: process.env.API_URL || "http://localhost:1337",
        contentTypes: ["article", "category", "writer"],
        singleTypes: [`homepage`, `global`],
        queryLimit: 1000,
        // new ---
        loginData: {
          identifier: process.env.GATSBY_API_IDENTIFIER,
          password: process.env.GATSBY_API_PASS,
        },
        // new ---
      },
    },
```

Then add config for `gatsby-source-graphql` plugin:
```javascript
    {
      resolve: "gatsby-source-graphql",
      options: {
        typeName: "Strapi",
        fieldName: "strapi",
        url: process.env.API_GRAPHQL_ENDPOINT,
      },
    },
```

After go to the root folder of Gatsby and rename `.env.example` file to `.env` and change code inside to:
```
GATSBY_ROOT_URL=https://yoursite.com
API_URL=https://subdomain.yoursite.com
API_GRAPHQL_ENDPOINT=https://subdomain.yoursite.com/graphql
GATSBY_API_AUTH=https://subdomain.yoursite.com/auth/local
GATSBY_API_IDENTIFIER=user@mail.com
GATSBY_API_PASS=userPassword
```

Then in the root folder create of Gatsby file `gatsby-browser.js`:
```javascript
import React from "react";
import {
  ApolloClient,
  ApolloProvider,
  InMemoryCache,
  createHttpLink,
} from "@apollo/client";
import { setContext } from "@apollo/client/link/context";
import fetch from "isomorphic-fetch";

const httpLink = createHttpLink({
  uri: process.env.API_GRAPHQL_ENDPOINT,
  fetch,
});

const authLink = setContext(async (_, { headers }) => {
  const token = localStorage.getItem("token");

  return {
    headers: {
      ...headers,
      authorization: token ? `Bearer ${token}` : "",
    },
  };
});

const client = new ApolloClient({
  link: authLink.concat(httpLink),
  cache: new InMemoryCache(),
});

export const wrapRootElement = ({ element }) => (
  <ApolloProvider client={client}>{element}</ApolloProvider>
);
```
Inside this file Apollo will get token from Strapi and also get access to fetching authenticated data.

But if you remember the [first part](https://dev.to/danielkrupnyy/production-deploying-strapi-gatsby-app-to-vps-share-hosting-preparing-authenticated-requests-1-4i86), in order to get Token we need to sand POST request to Strapi with data about user email and password.

For that go to `src` folder in Gatsby and create there path: `helpers/getToken.js`:
```javascript
import axios from "axios";

const getToken = async () => {
  const { data } = await axios.post(`${process.env.GATSBY_API_AUTH}`, {
    identifier: `${process.env.GATSBY_API_IDENTIFIER}`,
    password: `${process.env.GATSBY_API_PASS}`,
  });

  return data.jwt;
};

export default getToken;
```
Function `getToken` takes url to Strapi auth, user email and password from `.env` file. Then it returns token. 

Since token refreshes, we can save it in LocalHost. The best way to do it get and save token in `layout.js` component:
```javascript
import React, { useEffect } from "react";
import PropTypes from "prop-types";
import { StaticQuery, graphql } from "gatsby";
import Nav from "./nav";
import Seo from "./seo";
import getToken from "../helpers/getToken";

const Layout = ({ children, seo }) => {
  // new ---
  useEffect(() => {
    async function fetchData() {
      const token = await getToken();
      localStorage.setItem("token", token);
    }
    fetchData();
  }, []);
  // new ---

  return (
    <StaticQuery
      query={graphql`
        query {
          strapiHomepage {
            seo {
              metaTitle
              metaDescription
              shareImage {
                publicURL
              }
            }
          }
        }
      `}
      render={(data) => (
        <>
          <Seo seo={seo} />
          <Nav />
          <main>{children}</main>
        </>
      )}
    />
  );
};

Layout.propTypes = {
  children: PropTypes.node.isRequired,
};

export default Layout;
```
Now, when `layout.js` component is gererated it get request to Strapi, gets token and save it in LocalStorage. In turn ApolloClient at file `gatsby-browser.js` get token from LocalStorage and gets with it help GraphQL data.

### Uploading <a name="uploading"></a>
When you connected to your server. You need to follow the path: `home/username/web/yoursite.com` and drop there your Gatsby app. Then delete "*public_shtml*" folder.

☝️ But don't forget to exclude *node_modules* if you don't want to wait all your life for the download to finish 🙄 

After follow the: `home/username/web/subdomainprefix.yoursite.com/public_shtml` and drop there Strapi app. 

☝️ In my case, I was using Strapi with its own SQLite database and forgot to upload it to the server because it was hidden on my system and after running on the server, Strapi created a new empty database. So if you don't want to lose your data, don't make my mistakes. Path:`.tmp/data.db` ☝️

If you want to use Strapi with another DB. Strapi has [excellent docs on this. ](https://strapi.io/documentation/developer-docs/latest/setup-deployment-guides/configurations.html#database). 

### Installing Dependencies <a name="dependencies"></a>
Then switch to your SSH and go to these paths and in each path write command `npm install` to install all projects dependencies *(if you forgot how to connecting by SSH you can find this info in [previous part](https://dev.to/danielkrupnyy/production-deployment-strapi-gatsby-app-on-vps-shared-hosting-installing-node-creating-configs-2-3d7h))*. 

## Enabling SSL(HTTPS) <a name="ssl"></a>
In VestaCP go to "*WEB*" choose your domain and there enable "*SSL Support*". 

Then in "*SSL Home*" select "*public_shtml*" folder.

Then fill in the following fields with your SSL details: "*SSL certificate*", "*SSL key*", "*SSL certificate/credentials*" or enable "*Lets Encrypt support*" if installed on your Vesta panel. 
Save all changes.
![](https://res.cloudinary.com/danilnotorious/image/upload/v1619077809/vcp3_vqapjg.webp)
Do the same with the subdomain.

## Testing our apps <a name="testing"></a>
Now you can connect by SSH in your terminal and try to fire projects. `npm run develop` for Strapi. 
Then open new terminal window and do the same for Gatsby.
All should be work.

## Automatisation with PM2 <a name="pm2"></a>
In order to your apps don't stops when you close terminal windows. You need to install PM2 — process manager that will help you manage and keep your application online.

In your SSH terminal go to the server root folder and type:
```bash
npm install pm2 -g
```

After installation go to Strapi app:
`home/username/web/subdomainprefix.yoursite.com/public_shtml` and create there file "*server.js*". 

Then put inside:
```javascript
const strapi = require("strapi");
strapi({ NODE_ENV: "production" }).start();
```

Now it terminal type:
```bash
pm2 start server.js
```
That's it! Strapi app is working 🤗

Also You must read [this awesome docs about pm2]  (https://pm2.keymetrics.io/docs/usage/quick-start/).
This docs will help you fast understand how to use pm2!

## Creating Weebhooks <a name="webhooks"></a>
Since Gatsby [Static Site Generator](https://www.gatsbyjs.com/docs/glossary/static-site-generator/). It generate html at build time. 

Whenever we change something in Strapi, it should send a request to Gatsby that the data has changed, and Gatsby should perform the rebuild.

In order to solve this problem and similar problems exists Webhooks.

### Installing GO <a name="go"></a>
First you need to install [GO language](https://golang.org/) in your server.

Like I sad in [previous part](https://dev.to/danielkrupnyy/production-deployment-strapi-gatsby-app-on-vps-shared-hosting-installing-node-creating-configs-2-3d7h), In my case on server was installed CentOS. 

I'll show you how you can install GO on it using yum:
```bash
sudo yum install go
```

If you have different OS you need to find out how to install app on your system. [Sample Ubuntu](https://linuxize.com/post/how-to-install-go-on-ubuntu-20-04/).

### Installing Webhook tool <a name="tool"></a>
Now install [webhook](https://github.com/adnanh/webhook) — is a lightweight configurable tool written in Go, that allows you to easily create HTTP endpoints (hooks) on your server.

Install weebhook on CentOS:
```bash
go build github.com/adnanh/webhook
```

[Install on another OS](https://github.com/adnanh/webhook#installation)

### Creating configs for webhook tool <a name="configs"></a>
In your server root directory create folder "*webhooks*" and put inside folder "*fronted-rebuild*" and file "*hooks.json*":
``` json
[
  {
    "id": "frontend-rebuild",
    "execute-command": "/root/webhooks/frontend-rebuild/rebuild.sh",
    "command-working-directory": "/home/username/web/yourdomain.com",
    "response-message": "Executing rebuild script..."
  }
]
```

After put in to the "*fronted-rebuild*" folder file rebuild.sh:
```bash
#!/bin/bash

yarn clean 
yarn build
```
You'll get structure:
![Structure Folder](https://res.cloudinary.com/danilnotorious/image/upload/v1619090574/Screenshot_2021-04-22_at_2.21.24_PM_gcxktl.png)

Then create file start.sh in the root folder:
``` bash
/root/go/bin/webhook -hooks /root/webhooks/hooks.json -ip "00.0.000.000" -port 0000 -verbose -hotreload
```
Instead "*00.0.000.000*" and "*0000*" put your ip and port.

After will read [this article](https://strapi.io/blog/webhooks) and you will find out how to add webhooks to Strapi.

Your webhook will be looks like:
```bash
http://00.0.00.000:0000/hooks/frontend-rebuild
```

And finally use pm2 command to start webhook:
```bash
pm2 start start.sh
```
---

That's it! 
You've deployed the Strapi and Gatsby apps on a VPS hosting with VestaCP installed 👏

If you like this series and you feeling thankfulness. You can support me 😉

<a href="https://www.buymeacoffee.com/danielkrupnyy" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/default-orange.png" alt="Buy Me A Coffee" height="41" width="174"></a>

Also if you have a question or want to add something, drop it in the comments 👇 or find me on [Twitter](https://twitter.com/danielkrupnyy).