How to deploy your GatsbyJS site on your own server

With Gatsby 4 bringing in Server-Side Rendering (SSR) and Deferred Static Generation (DSG) you need an alternative methode to just hosting static files. Each page using SSR or DSG will be rendererd after a user requests it so there has be a server in the background which will handle these requests and build the pages if needed.

In this post i will show you how you can deploy your Gatsby site with SSR and/or DSG on your own server with a CI/CD pipeline via PM2 and Github Webhooks.

Therefore i will be using

Gatsby 4,Nginx,

Nginx

PM2 and

Github webhooks.

Setup your server

First of all you need an server with root access. I strongly recommend to have a look at the guide "Initial Server Setup with Ubuntu 18.04" from the DigitalOcean community which will lead you through the process of:

Logging in and set up root user access to your server with SSH

Creating a new user

Granting Administrative Privileges to the new user

Setting up a basic firewall

Giving your regular user access to the server with SSH key authentication.

After you have done that you can continue by installing all necessary dependencies on your server. Install Node.js

Again there is an guide by DigitalOcean which will help you installing Node.js using PPA.

After completing

install Node.js, NPM and

the "build-essential package"

you will have to change npm's default directory.

Create a .npm-global directory and set the path to this directory for node_modules:

cd ~
mkdir ~/.npm-global
npm config set prefix '~/.npm-global'

Create (or modify) a ~/.profile and add the following line:

sudo nano ~/.profile

# set PATH so global node modules install without permission issues
export PATH=~/.npm-global/bin:$PATH

Now you have to update your system variables:

source ~/.profile

Now you should be able to check your installed Node.js version with:

node -v

Install git

Check if git is already installed with:

git --version

If it isn't installed yet you can install it with

sudo apt install git

and configure Git with

git config --global user.name "Your Name"
git config --global user.email "youremail@domain.com"

After git is installed and configured you can deploy your Gatsby site by cloning it from Github.

Deploy from Github

It is important that you are loggin in as non-root user for the following steps.

cd ~
git clone https://github.com/your-githubuser/your-gatsby-repo.git path your-gatsby-site

After you have deployed your project (optionally with environment variables) you can install all dependencies and build your Gatsby site with:

cd ./your-gatsby-site/
npm install
npm run build

Now you should have a copy of your local project/Gatsby site on your remote server.

Next you are going to setup PM2 which will be used to keep your site alive and restart it with every reboot.

Setup PM2

You can install PM2 with:

npm install pm2@latest -g

You will need to create/configure an ecosystem.config.js file which will restart the default Gatsby server.

cd ~
pm2 init
sudo nano ecosystem.config.js

Copy/paste the template and replace the content.

module.exports = {
apps: [
{
name: 'gatsby-site',
cwd: ' /home/your-name/my-gatsby-site',
script: 'npm',
args: 'serve',
env: {
//NODE_ENV: 'production',
},
},
// optionally a second project
],};

With

cd ~
pm2 start ecosystem.config.js

you can start your server which will run on the Port 9000.

You can always check the status with:

pm2 status

After the server reboots this PM2 should be always automatically be restarted. For that you are going to need a small Startup script which you can also copy/paste. Generate and configure a startup script to launch PM2:

cd ~
pm2 startup systemd

[PM2] Init System found: systemd
[PM2] To setup the Startup Script, copy/paste the following command:
**sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u your-name --hp /home/your-name**

Copy/paste the generated command:

**sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u your-name --hp /home/your-name**

[PM2] Init System found: systemd
Platform systemd

. . .

[PM2] [v] Command successfully executed.
+---------------------------------------+
[PM2] Freeze a process list on reboot via:
$ pm2 save

[PM2] Remove init script via:
$ pm2 unstartup systemd

And save the new PM2 process list and environments. Then Start the service with systemctl.

pm2 save

[PM2] Saving current process list...
[PM2] Successfully saved in /home/your-name/.pm2/dump.pm2

If you reboot your server now with sudo reboot the script should be automatically restart your Gatsby site. Give it a try!

Setup Github Webhook

One thing missing now is an continuos integration and continuos delivery (CI/CD) pipeline which you will setup using Github webhooks.

Therefore you need to create a new Webhook in your repository.

The following articles provide additional information to the steps below:

GitHub Creating Webhooks Guide and

DigitalOcean Guide to GitHub WebHooks.

You need to create a server script which will do something if it is triggered by the Github webhook.

cd ~
mkdir NodeWebHooks
cd NodeWebHooks
sudo nano webhook.js

The script is going to create a server running on Port 8100. (Your Github webhook should be of course sending the webhook to something like http://server-ip:8100.)

If it gets triggered by a webhook it will

go into your repo ~/my-gatsby-site/,

pull the latest commits,

install all dependencies,

build a new version of the site and

restart the server via the PM2 script.

const secret = "your-secret-key";
const repo = "~/my-gatsby-site/";

const http = require('http');
const crypto = require('crypto');
const exec = require('child_process').exec;

const BUILD_CMD = 'npm run build';
const PM2_CMD = 'pm2 restart gatsby-site';

http.createServer(function (req, res) {
req.on('data', function(chunk) {
let sig = "sha1=" + crypto.createHmac('sha1', secret).update(chunk.toString()).digest('hex');

if (req.headers['x-hub-signature'] == sig) {
exec('cd ' + repo + ` && git pull && npm install && ${BUILD_CMD} && ${PM2_CMD}`);
}
});

res.end();
}).listen(8100);

You will need to allow communication on Port 8100 with:

sudo ufw allow 8100/tcp
sudo ufw enable

Command may disrupt existing ssh connections. Proceed with operation (y|n)? y Firewall is active and enabled on system startup

Earlier you setup PM2 to restart your Gatsby site whenever the server reboots or is started. You will now do the same for the webhook script.

Run echo $PATH and copy the output for use in the next step.

echo $PATH

/home/your-name/.npm-global/bin:/home/your-name/bin:/home/your-name/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin

Create a webhook.service file:

cd ~
sudo nano /etc/systemd/system/webhook.service

In the editor, copy/paste the following script, but make sure to replace your-name in two places with your username. Earlier, you ran echo $PATH, copy this to the Environment=PATH= variable, then save and exit:

[Unit]
Description=Github webhook
After=network.target

[Service]
Environment=PATH=your_path
Type=simple
User=your-name
ExecStart=/usr/bin/nodejs /home/your-name/NodeWebHooks/webhook.js
Restart=on-failure

[Install]
WantedBy=multi-user.target

Enable and start the new service so it starts when the system boots:

sudo systemctl enable webhook.service
sudo systemctl start webhook

Check the status of the webhook:

sudo systemctl status webhook

You can test your webhook with these instructions.

The Gatsby server is now running on your-ip:9000 and you implemented a CI/CD pipeline via PM2 and Github Webhooks but you still can't access your website via a domain because you need to configure a webserver like Nginx.

Configure Nginx

I am using Cloudflare to manage DNS for my domains but you can do this with every other provider also.

Create two A Records which will point your-domain.com and www.your-domain.com to the IP-adress of your server.

After that you will need to configure Nginx.

The following instructions are based on How To Install Nginx on Ubuntu 18.04 [Quickstart].

Update your local package index:

sudo apt update

install Nginx:

sudo apt install nginx

and adjust the Firewall:

sudo ufw allow 'Nginx Full'
sudo ufw delete allow 'Nginx HTTP'

You should now be able to see the Nginx landing page on http://your_server_ip.

Setting up Server Blocks

Create the directory for your-domain.com, using the -p flag to create any necessary parent directories:

sudo mkdir -p /var/www/your-domain.com/html

Assign ownership of the directory:

sudo chown -R $USER:$USER /var/www/your-domain.com/html

The permissions of your web roots should be correct if you haven’t modified your umask value, but you can make sure by typing:

sudo chmod -R 755 /var/www/example.com

Make a new server block at /etc/nginx/sites-available/your-domain.com:

sudo nano /etc/nginx/sites-available/example.com

Copy/Paste the following Gatsby-nginx configuration and update the server_name sections:

server {
# Listen HTTP
listen 80;
listen [::]:80;

server_name your-domain.com www.your-domain.com;

# Redirect HTTP to HTTPS
return 301 https://$host$request_uri;
}

server {
# Listen HTTP
listen 443 ssl;
listen [::]:443 ssl;

server_name your-domain.com www.your-domain.com;

# SSL config
include snippets/self-signed.conf;
include snippets/ssl-params.conf;

# Proxy Config
location / {
proxy_pass http://localhost:9000
proxy_http_version 1.1;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_pass_request_headers on;
}
location ~ /.well-known {
allow all;
}
}

Save the file and close it when you are finished.

Enable the file by creating a link from it to the sites-enabled directory:

sudo ln -s /etc/nginx/sites-available/your-domain.com /etc/nginx/sites-enabled/

Test for syntax errors:

sudo nginx -t

and finally enable the changes:

sudo systemctl restart nginx

Nginx should now be serving your gatsby site on your domain name. That means if you have a look at http://your-domain.com you should see your Gatsby site.

In the end should deny traffic to Port 9000 because Nginx is handling the requests with:

cd ~
sudo ufw deny 9000

To install SSL, you will need to install and run Certbot by Let's Encrypt.