Easily Deploy Gatsby Site onto Shared Host With SFTP

Last Updated:
deploy Gatsby site onto hosting with sftp

Most Gatsby builds would be handled automatically by a platform such as Netlify or Amplify.

These tools listen to a git repository and build out the site each time a change is pushed.

However I recently came across a niche problem that meant that an automated git deployment was not going to work.

The Problem

A client has a shared hosting server that has a WordPress site in a folder in the /public_html folder on the root domain. They wanted to deploy a Gatsby homepage alongside the WordPress folder to use the two of them on the same domain.

The Gatsby files will also need to be removed, before the new ones are uploaded to make sure everything is always entirely up to date.

Directory Structure

/
|-- /public_html
  |-- .htaccess
  |-- /WP
  |-- /Gatsby

The Solution

I needed to create a way to easily deploy a Gatsby site onto shared hosting via SFTP.

Environment Variables

Firstly update the .env file with the server variables you want to deploy to. These details will be used by the deployment script.

These details are stored here as they should not be hard coded into the site which is possibly shared with others via Git.

The new additions to your .env file are:

SFTP_HOST = ftp.domain.com
SFTP_USERNAME = [email protected]
SFTP_PASSWORD = sftppassword
LIVE_DEPLOY = true

The LIVE_DEPLOY variable is used as a failsafe. It means that the code cannot be deployed unless explicitly set to true.

Install ssh2-sftp-client

The package this example uses to deploy a Gatsby site with sftp is called ssh2-sftp-client.

It is a great Node.js package that is an actively maintained wrapper around SSH2 which provides a high level abstraction as well as a Promise based API. It makes deploying with SFTP easy.

To install it run either:

yarn add ssh2-sftp-client

or

npm i ssh2-sftp-client

The Deploy Script

In the root of the Gatsby project create a file called deploy.js. This is where the deployment Node code will be written. It is here that we will use the ssh2-sftp-client package to upload the files generated by Gatsby to the server.

The deploy script looks like this:

// Get the enviroment variables.
require("dotenv").config({ path: ".env" });

// Import the SFPT package.
let Client = require("ssh2-sftp-client");
let sftp = new Client();

// If LIVE_DEPLOY variable isn't set then stop deployment.
if (process.env.LIVE_DEPLOY !== "true") {
  console.warn("Not Deploying. Env Var Not Set.");
  return;
}

// Set the public_html folder as a variable to use later.
const pubDir = "/public_html/";

try {
  // Connect to the SFTP server.
  await sftp.connect({
    host: process.env.HOST,
    username: process.env.USERNAME,
    password: process.env.PASSWORD,
  });

  // Get all pre-existing files/folders into a variable.
  const allFilesAndDirs = await sftp.list(pubDir);

  // Loop through and delete everything apart from .htaccess and the /WP directory.
  //
  // This example could delete the /Gatsby folder with one command,
  // but this code can be edited to allow Gatsby to be uploaded directly
  // to the public_html folder if needed.
  for (const item of allFilesAndDirs) {
    // Item is a file.
    if (item.type === "-") {
      if (item.name === ".htaccess") {
        // Ignore this file.
      } else {
        // Delete the file
        await sftp.delete(`${pubDir}${item.name}`);
        console.log(`Deleted file: ${item.name}`);
      }
    }

    // Item is a folder
    if (item.type === "d") {
      if (item.name === "WP") {
        // Ignore this directory
      } else {
        // Delete the dir
        await sftp.rmdir(`${pubDir}${item.name}`, true);
        console.log(`Deleted dir: ${item.name}`);
      }
    }
  }

  console.log("Begin Gatsby upload");

  // Now upload new Gatsby files.
  await sftp.uploadDir(__dirname + "/public", `${pubDir}gatsby/`);

  console.log("Deployment Complete");

  sftp.end();
} catch (error) {
  console.log("Deployment Error");
  console.log(err);

  sftp.end();
}

This script handles the clean up of the old Gatsby script without removing the .htaccess and WordPress folder, and then uploaded the /public folder (gatsby files).

The one thing we have not handled yet is linking this up with the Gatsby Build process.

Add Deployment to the Build Process

The last part of the puzzle is to make sure that a brand new /public folder is created by our build script, which can then be automatically deployed via SFTP. This is taken care of within the package.json file.

Add the following line to your scripts object within package.json.

"scripts": {
  "deploy": "gatsby clean && gatsby build && node deploy"
}

Now all you need to do is run npm run deploy or yarn deploy to deploy the Gatsby site to a server via SFTP!

Related Posts

Helpful Bits Straight Into Your Inbox

Subscribe to the newsletter for insights and helpful pieces on React, Gatsby, Next JS, Headless WordPress, and Jest testing.