Ok, the title is a little bit misleading. We are not truly building this from scratch, as much as we are taking a Ubuntu Server, and slapping a prebuilt Gatsby Starter onto it. We absolutely could choose to build out the whole thing from scratch instead, using the Gatsby framework, but I wanted to build a blog, and having a blog-shaped starting point makes that way easier! In fact, I used these steps to build this blog, plus some customization and tweaks to fit my personal preferences of course.
Disclaimer: This guide assumes a lot of things. For me, I am hosting this stuff in a homelab, on my home network, so the focus of this guide will be in that context. If you have the budget or desire to do things in AWS, for instance, some of this will look very different to my setup.
Pre-Requisites
For this, I am starting with a Proxmox Host, running Proxmox 8.2. I am also using an unprivileged LXC container, using the Ubuntu 24.04 template from Proxmox as the base for my Gatsby Blog. Really, you just need a Ubuntu host of some sort to follow along with this. Preferably one that is x86, as I can’t guarantee that this will work on an ARM system, due to the dependencies that are required for the Gatsby starter.
If you are following along on a different Ubuntu host, simply skip to the next section.
Creating a Proxmox Container for Ubuntu 24.04
First, I made sure to download the Proxmox Template for a Ubuntu 24.04 container.
Then I selected Create Container
and started provisioning it.
I am using an Unprivileged container, with Firewall enabled.
You can name it whatever you like here, but I would suggest something that lets it stand out from any other hosts. I will be using gatsby-blog
, for instance.
Key Based SSH
I also want to use key based authentication for SSH, since the default user is root
here. We can paste a public key into the SSH key field. It should look something like this:
ssh-ed25519 AEFBD3NzaV1lADV1NTE5AAOAIL2dAPZ+yOo/sC5C+wxQAjajanMLNPRwXSWR742fzDKM
To generate a key, I used Termius, which is an excellent iOS/iPadOS Terminal Client. You can also use 1Password to generate a key though, or your computer terminal, etc. Just make sure not to loose your key, as it will be the only way to get into the machine remotely. Thankfully, though Proxmox also has a web based console for each container and VM, so we always have that available as a fallback.
Hardware Requirements
Here I am going with fairly minimal hardware specs. I am going to use the following:
- CPU: 2 cores, 1 socket
- RAM: 2048 MB
- Swap: 0 MB
- Storage: 32 GB
Since Gatsby generates static sites, once the site is running, the compute requirements for this container are going to be minimal. The 2 cores, and 2 GB of RAM are mostly going to be helpful when we are installing packages, or compiling a new version of the website.
I am not using Swap, since that degrades your storage life more quickly, and I have plenty of RAM provisioned.
As for total storage space, I am going to start with 32 GB. If you will be hosting many photos or videos, etc. you may want to add more storage to yours.
For networking, give yourself a static IP on your network. This should be something like 192.168.1.123/24
.
Since it is a CIDR we need to include the
/24
to indicate that our addressable range is only the last octet. More info about CIDR notation can be found here
We will also want to set our gateway here. This should be the IP address of your home router, likely 192.168.1.1
or something similar. If you don’t know what your router IP/Gateway should be, check the network info of a device that is already connected to your network, it will probably have it set automatically by DHCP!
Also, setup your DNS. If you don’t want to use custom DNS, it is most likely safe to just use your host’s DNS settings.
Installing Packages
Now we get to the fun part! Open the web console for your container in Proxmox, or SSH into it.
Run the following two commands in the command line of your container.
We are starting with the apt
update and upgrade commands to make sure that our container’s packages are all the most recent ones. This helps to make sure we are running the most secure packages that we can, and that we are able to use all the latest features as well.
The second command uses apt
to install a few helpful packages for us, with the -y
flag indicating that we don’t want it to ask us for confirmation before installing the packages.
sudo apt update && sudo apt full-upgrade -y && \
sudo apt install git gh nodejs npm -y
All done with this part for now, until we setup autostart at the end!
Setting up Git
For me, I have a private repository setup already that I am going to use to control versions of the website. Additionally, it makes working on the site very easy, as I can work on it from multiple locations and have them sync to each other.
First, I need to tell my container’s git client who is using it. It’s me! We will use the following command to login to GitHub from the command line, though you may need to complete the login process on a device with a web browser.
If you are going to use a public repo, then this step is not really necessary, though you will want to setup your username and email later for the purpose of being able to publish changes.
gh auth login
The above command will likely have you go to https://github/login/device
and paste a code in order to permit your server to access your git repositories. You can do this on another device, it does not need to be your Gatsby container.
Installing gatsby-cli
Still in the container command line, we are going to use NPM to install the gatsby-cli
. This is Gatsby’s command line tool, and is what is going to let us build and host our blog. We are installing using the -g
flag, which tells NPM to install the tool globally, rather than installing only to the current working directory.
npm install -g gatsby-cli
Getting Our Blog Files
If you have not already, and you wish to use git to control versioning of your blog, you will want to create a new blank project on GitHub. Then, we will want to clone the project onto our container, so that we can work with the files locally.
Since we have setup our GitHub auth, we can clone our private repo down.
gh repo clone GitHubUser/My-Gatsby-Project
GitHub should have a gh
option that will let you copy the clone command to use.
Using Starter Project
use the following command to change directories into the GitHub repo that you just cloned:
cd My-Gatsby-Project
Then, we are going to use the gatsby-cli
that we installed earlier to get the Starter Blog files.
This will handle pulling all the files and packages, and will setup a new folder named gatsby-starter-blog
that will contain all the things needed to run your blog.
npx gatsby new gatsby-starter-blog https://github.com/gatsbyjs/gatsby-starter-blog
At this point, your folder structure should look something like this:
- My-Gatsby-Project
- gatsby-starter-blog
- README.md
Use cd
to get into the gatsby-starter-blog
folder.
cd gatsby-starter-blog
You will likely need to modify the permissions of the copied files, so that they are executable.
sudo chmod +x package* && sudo chmod +x gatsby*
Then we will use npm
to install the dependencies:
npm install
Lastly, for now, we will run the following to put up a DEV version of your site, hosted at http://localhost:8000
.
gatsby develop
We can use this cheatsheet of gatsby commands to get us started
Since we are building this on a container that does not have a web browser, we will want to specify the host (-H
) and port (-p
) like so using the container’s static IP address that we set earlier:
gatsby develop -H 192.168.1.123 -p 3000
Congratulations! You have a Gatsby Blog running!
Using another device on the same network, navigate to http://192.168.1.123:3000
and you should see your site running!
This is just a dev version, but it makes it very easy to troubleshoot problems, and test new things. If you edit the files in gatsby-starter-blog
you will see the updates take place in your browser in real time!
Building Gatsby Site for Production
To build the production site, with all of its optimizations, we will want to run gatsby build
instead.
Unlike gatsby develop
, the build command does not host anything, it just compiles all the stuff to be hosted.
We need to use gatsby serve
to actually host the site. We can combine the two commands like so to build and serve the site in one go:
gatsby build && \
gatsby serve -H 192.168.1.123 -P 80
A production site will run even faster than the dev site, and will often have more stable handling of images and other elements than the dev version does.
Also, since we are hosting on port 80, we can now just go to http://192.168.1.123
and we will see the blog.
Editing the Blog
Editing Author Info and Site Metadata
First, we want to make sure that we don’t have boilerplate author info lying around. The first thing we need to update is gatsby-config.js
in the gatsby-starter-blog
folder.
Editing this file allows us to set our Author name, the site title, description, and a little info about ourselves.
It also provides the option to link directly to Twitter (currently X).
Editing Blog Posts
THe starter blog comes with a few blog posts baked in to give us a good idea of what it supports.
To edit the content of the blog, we just need to edit the Markdown files under gatsby-starter-blog/content/blog
.
There is a separate folder for each blog post, containing an index.md
and any resources that relate to that post, such as pictures, etc.
Each folder for a blog post is named after the post title, with all lowercase, hyphenated titles. For example, the post titled Hello World
has a folder name of hello-world
.
Each blog post index.md
file gets the following metadata header with the title, creation date, and description:
---
title: Hello World
date: "2015-05-01T22:12:03.284Z"
description: "Hello World"
---
The title here is what will be used on your home page to show what the blog post should be named. Ideally, it will match your H1 header within the index.md
file itself, but it doesn’t need to.
The description is totally separate from the content of the blog, and will also appear on the homepage to give a site visitor an idea of what they will find in the post.
The date
field is a generated timestamp, and can be typed out manually, or you can get something to generate a stamp for you. This stamp indicates the index.md
file creation date.
Pushing Changes back to Git
TO get all the changes we have made, and get them back into git, we are going to run the following commands inside the My-Gatsby-Project
folder.
git add * && \
git commit -a -m “I just made a Gatsby Blog!” && \
git push
This should commit and push any of your changes right back into the git repository. If you view the repository on github.com
, you should see the changes appear there, though a page refresh may be necessary.
Getting it to Start on Reboot
We are going to use cron
, along with a simple script to allow the site to pull any new information from git, build the production site, and host it, every time it reboots.
First, we are going back to using apt
:
sudo apt update && sudo apt install cron -y
Then, we will edit the cron configuration using crontab -e
.
The first time cron
runs, it will ask you which editor you want to use. If you do not know, using the default 1. nano
is good.
Since we are root already, there should be no problem with user
cron vs root
cron.
Once we are into cron
, we can add this line at the bottom, making sure to leave one line of blank space after it.
@reboot cd /root/My-Gatsby-Prject && git pull && cd gatsby-starter-blog && gatsby build && gatsby serve --host 192.168.1.123 --port 80
If using nano
, press CTRL + X
followed by y
and ENTER
to exit.
This works totally fine as is. However, it is a brittle solution, and gives us very little flexibility.
Instead, we can make a little script that will let us come back and edit variables later if we need to move things around, or if file names change, etc.
I am going to name it start-gatsby.sh
.
Run this command in the container
cd ~ && nano start-gatsby.sh
Paste in the following text, then use CTRL + X
, y
, and ENTER
, just like we did with cron
.
#!/bin/sh
# Set up our variables
# Full path to the git repo for the site
FULL_REPO_PATH="/root/My-Gatbsy-Project"
# Blog Root Path
BLOG_ROOT_PATH="$FULL_REPO_PATH/gatsby-starter-blog"
# Public IP or FQDN for the site
PUBLIC_HOST="192.168.1.123"
# Port that it will be hosted on
PORT=80
# Go to the repository
cd $FULL_REPO_PATH
# Get any updates from git
git pull
# Go to the blog folder
cd $BLOG_ROOT_PATH
# Build the new site
gatsby build
# Host the site
gatsby serve --host $PUBLIC_HOST --port $PORT
This script can live in the /root
directory.
We can give it permissions to run by running the following command:
chmod +x start-gatsby.sh
Now, we can go back to cron
using:
crontab -e
And edit it to run the script, rather than a string of commands.
@reboot bash /root/start-gatsby.sh
Then save with CTRL +X
, y
, ENTER
.
Now if you reboot your container, you should see in your browser that the page becomes unavailable temporarily while it reboots. Then within a few minutes, the site should be up again with any changes made now being visible.