When deploying updated contents from local machine to server, copying files via rsync
or scp
to remote server is not good enough. Version control is necessary to keep track of the incremental changes, for roll-back or debugging. The ideal workflow would start with editing local files, git push
that to a git repository (hosted on a local or remote server), then use the git repository to prompt the hosting server to update contents on the website. While this logic is fairly straightforward, it's not easy to find a good guide to do this right. Available guides returned from Google search either bring in too many idiosyncrasies that are not common denominators for such exercise, or are outdated with inaccurate references, or miss out important details, or are just plagued with bad graphics.
There are just simply too many stack choices at every step of the way. There are professional services that claim to handle the entire workflow end-to-end, such as Heroku, which seems like an overkill for small, hobby projects. There are various front-end frameworks that intend to keep the workflow entirely on the server so that they can eventually charge storage for a fee, such as good old Workpress, Wix and Gatsby, which would deprive the freedom of managing source files locally. There are different platforms for hosting git server, such as Github vs Gitlab, which leads to the debate between Github Actions vs Gitlab CI. Deployment scripts abound from the Internet, but often they are tied to specific backend such as AWS, Azure or GCP. The sheer number of possible combinations is mind-boggling.
Eventually I got it figured out though, for a simple deployment workflow that served my use case, which is the simplest setup involving a bare-bone static webpage on local machine, Github repo, and a virtual instance hosted on Digital Ocean, intended to be the smallest common denominator of any website/online application. When updating the website, all the edits shall be made locally to the content source files stored on local machine, then they are git push
to Github's repo, which has an Github Action
configured. Github Action will use stored secrets to essentially login to Digital Ocean instance and update the files on server.
1) Create a Github repo (under dummy user name sammy
) that will host the content/application files for the website my-site
. The folder should have a structure like
my-site
|---public_html
|---index.html
|---img
|---js
At this point, the index.html
can be just a dummy page with minimum content. The real content, static or dynamic, can be added later on once the deployment workflow is up and running.
<html>
<body>
Hello World!
</body>
</html>
On local machine, clone this repo to production environment in development environment
git clone git@github.com:sammy/my-site.git
2) Create SSH key pairs on VPS
Next we need to create an SSH key pairs on the VPS. Login to VPS' terminal via user dora
(assuming you can do this by SSH from local machine without using password) and create a new pair of keys with ssh-keygen
. Two new files, id_rsa
and id_rsa.pub
will be generated in the default folder .ssh
.
We need to enable this Digital Ocean VPS instance to access Github. So the SSH key pair is created under user dora
on VPS to allow dora
to login to Github repo to perform git clone
and git pull
to update its own directory on the server.
On server terminal, copy the content of the public key cat ~/.ssh/id_rsa.pub
. Open the ssh configuration file with sudo vim ~/.ssh/authorized_keys
, paste the copied public ssh key to the end of the file. Enter :wq
in vim editor to save the file and exit.
Give the configuration file proper permission so that ssh tasks can be performed:
chmod 700 ~/.ssh/authorized_keys
3) Enable VPS to access Github repo
Go to Github's user setting for sammy
, in tab SSH and GPG keys
, press New SSH key
and save the copied ssh public key for VPS user dora
, so that when dora
calls Github for git clone
or git pull
with encrypted private key, Github server can recognize dora
and allow passwordless login via ssh by matching its stored public key to the transmitted (and encrypted) private key.
Click on tab Settings
of the Github repo my-site
, go to Secrets
section. Click New repository secret
to create 3 Action secrets and name them as below. It's important to note that the SSH_KEY here is the private key, NOT the public key.
Name | Value |
---|---|
SSH_HOST | IP for VPS instance (12.34.56.78 ) |
SSH_KEY | content from private key id_rsa for dora |
SSH_USERNAME | dora |
Note that, the secrets' name MUST be identical to SSH_HOST
, SSH_KEY
and SSH_USERNAME
. We'll be using a popular script created by a Github user. These three are the variables defined by this script so they must match.
4) Initialize file directory on hosting server
We now have all the necessary ingredients to initialize the directory on the server that will host the files for my-site
. Let's go back to the server terminal.
This step can be quite tricky, as it involves making decision on the path of the folder that shall host the files. Assuming you have followed through this guide Set Up Nginx Server on Ubuntu, go to your Nginx server directory,
cd /etc/nginx/sites-enabled
Open the Nginx configuration file for my-site
with vim my-site
. Use sudo
if necessary. Verify that in the first block of server
:
- The
root
path formy-site
is configured as/var/www/my-site/public_html
. - The default file to be loaded in this folder
index
shall beindex.html
Make sure these two parameters are consistent with the file structure created on the local machine/Github repo. If not, Nginx server will not be able to work properly. Place other relevant files into the public_html
folder as needed.
Now, enter into the CORRECT path for hosting the website cd /var/www
. Note that it is NOT /var/www/my-site
.
In /var/www
, initialize the directory for my-site
by git clone
the files from Github repo
git clone git@github.com:sammy/my-site.git
Now on the hosting server 12.34.56.78
, in directory /var/www
, a new sub-directory /var/www/my-site
(along with other sites like my-site-A
, my-site-B
, all under /var/www
) is created. Based on Nginx's configuration in /etc/nginx/sites-enabled/my-site
, visiting 12.34.56.78
will display the content on /var/www/my-site/public_html/index.html
.
This git clone
is a one-time action. All subsequent updates on VPS will be achieved via git pull
command.
5) Create a Github Action to handle CI/CD pipeline to VPS
Switch back to Github, in the newly created repo my-site
, click on the Actions
tab and create a yaml
file deploy.yml
(or any other sensible file name with .yml
extension). This file will define the workflow and tell Github how to send updated files to VPS. Copy and paste the below script into the yml file:
# This is a basic workflow to help you get started with Actions
name: Build & Deploy
# Controls when the workflow will run on:
# Triggers the workflow on push or pull request events but only for the main branch
push:
branches: [ main ]
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
deploy:
# The type of runner that the job will run on
runs-on: ubuntu-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- name: Deploy Bootstrap 5 static webpage for my-site
uses: appleboy/ssh-action@master # call a custom script by user appleboy for SSH on github
with: # all below inputs are specifically defined in ssh-action script
host: ${{secrets.SSH_HOST}} # IP address of the server
key: ${{secrets.SSH_KEY}} #private key of the server
username: ${{secrets.SSH_USERNAME}} # user of the server
script: |
cd /var/www/my-site # enter into the folder that will host the landing page for the first time
git pull # update the working directory with the latest from the github repo
echo 'Deployment successful to Digital Ocean' # Display message to reflect deployment status
Let's try to understand what is happening here. Read up Github Actions' official documentation to understand its syntax and common uses. The key portion of the script that kicks off the deployment workflow starts with steps:
.
First, the script calls a custom script ssh-action made by Github user appleboy from master
branch of his repo with command uses:
. This particular script then uses 3 parameters host
, key
and username
, which point to the 3 secrets already stored SSH_HOST
, SSH_KEY
, and SSH_USERNAME
with command with:
. The objective of this script is to establishes SSH access between VPS and Github. There are many similar custom deployment scripts on Github. They all come in different shapes and forms and could use entirely different parameters that don't look like host
, key
or username
. I just happened to stumble upon this one made by appleboy
and it worked well. This script carries 1.4K stars at the moment, demonstrating wide popularity and strong community support. For casual personal website projects, it's fine to rely on such third-party open-sourced script to avoid the hassle of recreating the wheel. For more serious business endeavors, it would be ideal to write your own deployment script.
Second, after VPS establishes passwordless SSH access to Github (via user dora
with the ssh key pair created on VPS), user dora
enters into the right path /var/www/my-site
and performs a git pull
with an onscreen status message. Given the file structure in my-site.git
repo, this action will pull all the incremental changes in sub-directory public_html
.
That's it! With Github Action and a very helpful third-party script, a full deployment workflow is created. Going forward, you just make all the edits in the repo folder in the local machine, git push
to Github repo my-site.git
, and Github Action will automatically trigger subsequent steps to SSH into the hosting server and sync up contents there via git pull
from the same Github repo.
You can now go ahead to do something fancy on the plain vanilla index.html
.
1. Thanks for reading! 1082.xyz newsletter shares the learning and discovery for aspiring polymath, on crypto, blockchain, investment, startups, productivity hacks and technology in general. If you're forwarded this email, you can sign up for the free 1082.xyz newsletter here or just press the "Subscribe" button to receive the latest articles directly in your inbox. The free tier would be just fine to receive all available contents.
2. You're welcome to share your feedback and comments in the comment section. No email registration is needed. You can even do so anonymously.
3. If you find this article helpful, please share it with like-minded friends. Thank you.
1082
Read more posts by this author.