Production deployment Strapi + Gatsby app on VPS Shared Hosting: Deploy, web hooks & https. (3)
Daniel Krupnyy
Posted on April 23, 2021
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 š¤
Let's go to work šŖ
Table Of Contents:
- Deployment Strapi and Gatsby
- Enabling SSL(HTTPS)
- Testing our apps
- Automatisation with PM2
- Creating Webhooks
Deployment Strapi and Gatsby
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
All data for connection by FTP/SFTP you can find on your host.
I prefer to use Cyberduck client for such purposes. You can use it or something like FileZilla.
Here is the video how to open FTP/SFTP connection using Cyberduck.
Preparing to upload
Before you upload Gatsby files to server, you need to
install fs-extra package:
npm install fs-extra
Then change "gatsby-node.js" file or create it and put this code inside:
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
In the first part we Configured Authenticated Requests in Strapi and created new Role and User for it.
Now is time to create Authenticated Requests.
Installing necessary dependencies
First install all dependencies to Gatsby:
yarn add axios isomorphic-fetch gatsby-source-graphql @apollo/client
Then install dependencies for Strapi:
yarn strapi install graphql
Now explanations. Let's start with ApolloClient(@apollo/client
).
ApolloClient 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. 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
Go to gatsby-config.js
file and find there gatsby-source-strapi
plugin. Extend it add:
{
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:
{
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
:
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, 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
:
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:
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
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. .
Installing Dependencies
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).
Enabling SSL(HTTPS)
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.
Do the same with the subdomain.
Testing our apps
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
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:
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:
const strapi = require("strapi");
strapi({ NODE_ENV: "production" }).start();
Now it terminal type:
pm2 start server.js
That's it! Strapi app is working š¤
Also You must read this awesome docs about pm2.
This docs will help you fast understand how to use pm2!
Creating Weebhooks
Since Gatsby 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
First you need to install GO language in your server.
Like I sad in previous part, In my case on server was installed CentOS.
I'll show you how you can install GO on it using yum:
sudo yum install go
If you have different OS you need to find out how to install app on your system. Sample Ubuntu.
Installing Webhook tool
Now install 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:
go build github.com/adnanh/webhook
Creating configs for webhook tool
In your server root directory create folder "webhooks" and put inside folder "fronted-rebuild" and file "hooks.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:
#!/bin/bash
yarn clean
yarn build
Then create file start.sh in the root folder:
/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 and you will find out how to add webhooks to Strapi.
Your webhook will be looks like:
http://00.0.00.000:0000/hooks/frontend-rebuild
And finally use pm2 command to start webhook:
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 š
Also if you have a question or want to add something, drop it in the comments š or find me on Twitter.
Posted on April 23, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.