How to deploy your GatsbyJS site on your own server

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 "Your Name"
git config --global ""

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 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


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:

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}`);


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


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:

Description=Github webhook

ExecStart=/usr/bin/nodejs /home/your-name/NodeWebHooks/webhook.js


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 and 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:


Setting up Server Blocks

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

sudo mkdir -p /var/www/

Assign ownership of the directory:

sudo chown -R $USER:$USER /var/www/

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/

Make a new server block at /etc/nginx/sites-available/

sudo nano /etc/nginx/sites-available/

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

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


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

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


    # 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/ /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 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.

First published September 23, 2022

0 Webmentions

Have you published a response to this? Send me a webmention by letting me know the URL.

Found no Webmentions yet. Be the first!

About The Author


Geospatial Developer

Hi, I'm Max (he/him). I am a geospatial developer, author and cyclist from Rosenheim, Germany. Support me

0 Virtual Thanks Sent.

Continue Reading