In this blog post, let’s learn how to set up a CI/CD workflow for your blog with CircleCI, GitHub, and a Linux Virtual Private Server (VPS) with NGINX installed.
Note that I’m using Eleventy as a static site generator for my blog.
Prerequisites
- A CircleCI account.
- A GitHub account.
- A Linux VPS from AWS / Azure / DigitalOcean / etc. (just make sure you have set up SSH and create a new sudo user for it).
Setup user for deployment
- SSH into your VPS (as a sudo user) and create a new user called
circleci
. Run:
sudo useradd -m -d /home/circleci -s /bin/bash circleci
- Setting up SSH for the new
circleci
user.
- On your local machine, to generate an SSH key pair, run:
ssh-keygen -m PEM -t rsa -f ~/.ssh/circleci
- Copy & paste the content of the public key
.pub
and add it your VPS/home/circleci/.ssh/authorized_keys
file.
sudo nano /home/circleci/.ssh/authorized_keys
- If the directory
/.ssh
doesn’t exist, create it with:
sudo mkdir /home/circleci/.ssh
then create the authorized_keys
file:
sudo touch /home/circleci/.ssh/authorized_keys
- Give the
circleci
user its directory permissions so that it doesn’t run into permission issues during deployment.
sudo chown -R circleci:circleci /home/circleci
- On your local machine, test the new
circleci
setup with:
ssh circleci@<your_server_ip> -i ~/.ssh/circleci
If it works, you are now logged in as circleci
!
- Setup SSH connection with GitHub. This allows us to do
git fetch
,git pull
, and cloning private repos.
Install Node
-
SSH to your VPS with the user
circleci
as we’ve set up above. -
Install
node
(I find installing Node using the Node Version Manager to be more convenient).
- Run
node -v
to make surenode
is installed - Run
npm -v
to make surenpm
is installed.
- Run
npm i -g pnpm
to installpnpm
globally.
- Run
pnpm -v
to make surepnpm
is installed.
Setup deployment environment
- Create a folder for our deployment, then move to that folder:
mkdir web && cd web
- Clone your blog from GitHub:
git clone <repo-url / ssh-string>
Eg: git clone git@github.com:KhoiUna/my-blog.git
(I prefer using an SSH string since we’ve setup SSH connection with GitHub).
- Note that in my GitHub repo, I’ve created a
.circleci/
folder with aconfig.yml
file.
# .circleci/config.yml
version: 2.1
# Define the jobs we want to run for this project
jobs:
pull-and-build:
docker:
- image: arvindr226/alpine-ssh
steps:
- checkout
- run: ssh -o StrictHostKeyChecking=no $USER@$IP "./deploy-blog.sh"
# I tell CircleCI to SSH to my VPS,
# and run my `deploy-blog.sh` script.
# Orchestrate our job run sequence
workflows:
version: 2
build-project:
jobs:
- pull-and-build:
filters:
branches:
only:
- main
- Create
deploy-blog.sh
script:vi ~/deploy-blog.sh
with this content:
# /home/circle/deploy-blog.sh
#!/bin/bash
# replace this with the path of your project on the VPS
cd ~/web/my-blog
# pull from the branch
git pull origin main
# followed by instructions specific to your project that you used to do manually
export PNPM_HOME="/home/circleci/.local/share/pnpm"
export PATH="$PNPM_HOME:$PATH"
# Install dependencies
pnpm i
# Build my static blog.
# I'm using 11ty so the out dir will be `_site/`
pnpm build
-
Login to your CircleCI account, create a new project and connect it to your blog repo.
-
Go to your Project Settings, create 2 environment variables:
USER=circleci
andIP=<your_server_ip>
. -
Under Additional SSH Keys, add your private key that you’ve created for
circleci
user.
Setup NGINX
-
SSH into your server as a
sudo
user, not as usercircleci
. -
Make sure NGINX has been installed and is running:
- To make sure NGINX has been installed:
nginx -v
- To make sure NGINX is running:
sudo systemctl status nginx
- If it says Active, proceed to the next step. If not, start NGINX with:
sudo systemctl enable nginx && sudo systemctl start nginx
- Create our NGINX site config file at
/etc/ngixn/sites-available/
:
sudo vi /etc/nginx/sites-available/my-blog.conf
with this content:
# /etc/nginx/sites-available/my-blog.conf
server {
listen 80;
listen [::]:80;
root /home/circleci/web/my-blog/_site;
index index.html index.htm index.nginx-debian.html;
server_name yourdomain.com;
error_page 404 = /404.html;
location /404.html {
internal;
}
location / {
try_files $uri $uri/ =404;
}
}
- Check our NGINX config file:
sudo nginx -t
If it says OK, proceed to the next step!
- Restart NGINX:
sudo systemctl restart nginx
Your blog is now live at yourdomain.com
!
A few notes
- From now on, each time you
git push
successfully to themain
branch, CircleCI will run the steps in our.circleci/config.yml
file in our repo. - Make sure to not make user
circleci
asudo user
for security purposes. - Make sure to have
export PATH
in yourdeploy-blog.sh
script. This is important as CircleCI won’t have access to usercircleci
’s$PATH
when SSH to our VPS (p/s: I spent hours fixing this bug).
References
How To Automate Deployment Using CircleCI and GitHub on Ubuntu 18.04 | DigitalOcean