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:
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.
First published September 23, 2022
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