Easily Deploy Gatsby Site onto Shared Host 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!