Continuous deployment via git and cPanel for your Gatsby (or other static) blog

Do you run your own static site / blog? Do you still have a shared web hosting service you pay for? Would you like to jump into continuous deployment using just your web host?

Sections

  1. Today’s manual steps to update site on my web host
  2. The automated way I would like
  3. How to enable continuous deployment using git and cPanel
    1. Prerequisites
    2. Create an empty repository on your cPanel Git Version Control interface
    3. Connect cPanel your local development machine via ssh
    4. Add the cPanel managed repository as a remote on your local repository
    5. .gitignore issues
    6. Setup automatic deployment via post-receive git hook
    7. Sending an email once the copy is completed.
  4. Final Process
  5. Links I used to research and implement this

Today’s manual steps to update site on my web host

I host my blog my domain. I use Gatsby to build this blog. The source code is hosted on Bitbucket. Once built, the static files are hosted on Webhosting Hub .

Today, my process is follows:

  1. Draft and edit post on Obsidian
  2. Use VSCode to update my Gatsby blog repository with this post.
  3. Test locally. Build. Test the build
  4. Push the source changes up to Bitbucket.
  5. UseFilezilla to FTP to my webhost’s file system and navigate to the correct folder
  6. Drag + drop the recently updated distribution files (the ‘public’ folder for Gatsby) to Filezilla.
  7. Refresh and test my live site.

The automated way I would like

While this works, I was looking to automate Steps 6 to 9. Once I push the source changes, I would like to have the web host files updated with the new build .I have setup Netlify pipelines for my Booknotes site which does exactly that.

However once I realized that thanks to Git + cPanel, one push deployment can be done, I wanted to try it out. Why - I like the idea of trying something new - I like the idea of relying /maintaining one less service - for my small needs.

Visually, this is the flow I want. Basically, what cPanel calls ”Push Deployment

Desired automated deployment using git and cPanel
No
Yes
No
Yes
Yes
Test locally
Make local changes
Working?
Build
Test build
Build working?
All changes except
distribution or public files
Push to Bitbucket
All files including
distribution or public files
Push to cPanel Git Version Control
cPanel deploys automatically
Freshly deployed blog!

How to enable continuous deployment using git and cPanel

1. Here are the prerequisites:

  1. Your web host offer shell access?
  2. Your web host offer terminal access?
  3. Your repo host allow ssh access? (Github, Bitbucket, Gitlab do.)
  4. You have a way to build and compile your site to generate static files (Gatsby or Next JS or Create-React-App or some such)
  5. You know where the built / distribution files live.

Then

2. Create an empty repository on your cPanel Git Version Control interface

youtube instructions

  1. Go to your cPanel. Navigate to ‘Git Version Control’. Click on ‘Create’.
  2. Make sure that the ‘toggle’ panel is turned OFF.
  3. In the form, add the repository path - I use /repositories/repository-name
  4. In the form, fill in the repository name
  5. Click ‘Create.’
  6. In the window which pops up, copy the remote / Clone Url

3. Connect cPanel your local development machine via ssh

  1. In your local repository, check what your git user.name and user.email are.
git config --local user.name
git config --local user.email

If the username and email are not set, you can choose to set it or use the global email. To set it, use the same commands with the values you want to set

 git config --local user.name "My Name"
 git config --local user.email "my_git_email@example.com"

Make a note of this email address.

  1. Create SSH keys on your system, using this email address and add it to the ssh-agent. Github has great instructions for this. Use the following command for generating the ssh key.
$ ssh-keygen -t rsa -b 4096 -C  "my_git_email@example.com"
  1. Give the file a unique name.
  2. After you run this command, the system will prompt you to enter a passphrase. Do not enter a passphrase, and press Enter to continue.
  3. Add your SSH key to the ssh-agent.
    1. Start agent in the background eval "$(ssh-agent -s)"
    2. For Macs, modify your ssh.config open ~/.ssh/config
    3. Add the following lines to it
    4. AddKeysToAgent yes
      UseKeychain yes
       IdentityFile ~/.ssh/<your file name> ```
    5. Add your key to the SSH agent. ssh-add ~/.ssh/<your file name>
  4. Add these keys to your cPanel SSH Keys
    1. Go to ‘SSH Keys’. Click on Import Key.
    2. In the form which shows up, fill the following:
      1. name - I use the same name as the file
      2. Paste the private key (from the file generated without the .pub extension)
      3. Leave the passphrase empty
      4. Paste the public key (from the .pub generated file)
      5. Click import.

4. Add the cPanel managed repository as a remote on your local repository

  1. Update the Clone URL you had copied in the last step of Section 1 with the port.
    For example, if your URL was ssh://username@domain.com/home/{username}/repositories/{reponame} and your port is 2222, your new URL will be ssh://username@domain.com:2222/home/{username}/repositories/{reponame}

  2. Go to your local repository and add this as a remote. To do this, run the command
    git remote add <remotename> <cloneurl>.
    <remotename> needs to be unique. Like many others, I use ‘cpanel’ for cPanel, and ‘origin’ for Bitbucket.
    <cloneurl> is the clone URL you copied over form Git Version Control. Note: the instructions mentioned in cPanel name the remote as ‘origin’. However, I use ‘origin’ for my Github/Bitbucket accounts, and name this remote as ‘cpanel’

  3. Push your changes to the cpanel repository.
    git push -u cpanel main This should fail at this point with a timeout error

  4. .gitignore setup for checking out publci only

5. .gitignore issues

Generally, for Gatsby repos, the ‘public’ directory is included in the .gitignore file and is ignored and these files are not pushed to the repo. In my case, I want my Bitbucket repo to stay clean, as they are. However I want the public files to get pushed to the cPanel repo. For this, I have to use a slightly clunky mechanism - branches.

  1. The main branch with clean code remains ‘main’.
  2. Create a new branch named deployment. git checkout -b deployment.
  3. In the deployment branch, remove ‘public’ from .gitignore.
  4. Commit the changes in deployment.
  5. Push the ‘deployment’ branch to cPanel. git push cpanel deployment.
  6. In cPanel, in Git Version Control, go to the repository and set the the ‘Checked-out branch’ to ‘deployment.

6. Setup automatic deployment via post-receive git hook

The official way using a .cpanel.yml did not work for me. I kept seeing the following error:

[username@domain hooks]$ ./post-receive
./post-receive: line 17: /dev/stdin: Operation not permitted

Digging on forums, I realized others had similar issue

Instead, inspired by here and here, I just re-use the post-receive git hook to

  • checkout the correct branch, ‘deployment’ in our case
  • copy the contents of the public folder in the repository to my deploy path.
  • send me an email
  1. Create a file called ‘post-receive’ with no extension.
  2. Open the file in a text-editor and use the following code
#!/bin/sh

# post-receive hook
echo "Received a push to repo. Checking out deployment branch via work tree"
git --work-tree=/home/{username}/repositories/{reponame} --git-dir=/home/{username}/repositories/{reponame}/.git checkout -f deployment

echo "copy updated files from repo public to deploy path - public_html/blog"
export DEPLOYPATH=/home/{username}/public_html/blog/
/bin/cp -R -u /home/{username}/repositories/{reponame}/public/* $DEPLOYPATH

echo "copy done"

In your script, replace {username} with your username,{reponame} with your repository name, and set the DEPLOYPATH to where you want to deploy.

  1. Move this file into your web host folder under home/{username}/repositories/{reponame}/.git/hooks
  2. Login in terminal in cPanel and make sure the git hook has executable permissions by running chmod +x /home/{username}/repositories/{reponame}/.git/hooks/post-receive

Now, when you push a file to cPanel from your local repository using git push cpanel deployment, this will automatically move the files over to where you want it to be.

7. Sending an email once the copy is completed.

I haven’t implemented it yet. https://forums.cpanel.net/threads/git-update-notification.645649/ has more information to do this.

4. Final Process:

Here is what my process looks like.

  1. In VSCode, git checkout main
  2. Make changes. Test. Commit changes.
  3. Build using gatsby build. Test build
  4. Push changes to Bitbucket. git push origin main
  5. Update the deployment branch with these changes and commit.
    git checkout deployment
    git merge master
    git commit -m "update: new blog post"
  6. Push the deployment branch changes to cPanel git push cpanel deployment

And there you go! Easy-peasy.

5. Links I used to research and implement this.

I would love to hear from you (tweet @suprada) if you have an even better way of leveraging cpanel!


April 25, 2021