Tools like Travis CI and Netlify offer some pretty nifty features, like seamlessly deploying your GitHub Pages site when changes are pushed to its repository. Along with a static site generator like Hugo, keeping a blog up to date is pretty painless.

I’ve used Hugo to build my site for years, but until this past week I’d never hooked up my Pages repository to any deployment service. Why? Because using a tool that built my site before deploying it seemed to require having the whole recipe in one place - and if you’re using GitHub Pages with the free version of GitHub, that place is public. That means that all my three-in-the-morning bright ideas and messy unfinished (and unfunny) drafts would be publicly available - and no amount of continuous convenience was going to convince me to do that.

So I kept things separated, with Hugo’s messy behind-the-scenes stuff in a local Git repository, and the generated public/ folder pushing to my GitHub Pages remote repository. Each time I wanted to deploy my site, I’d have to get on my laptop and hugo to build my site, then cd public/ && git add . && git commit… etc etc. And all was well, except for the nagging feeling that there was a better way to do this.

I wrote another article a little while back about using GitHub and Working Copy to make changes to my repositories on my iPad whenever I’m out and about. It seemed off to me that I could do everything except deploy my site from my iPad, so I set out to change that.

A couple three-in-the-morning bright ideas and a revoked access token later (oops), I now have not one but two ways to deploy to my public GitHub Pages repository from an entirely separated, private GitHub repository. In this post, I’ll take you through achieving this with Travis CI or using Netlify and Make.

There’s nothing hackish about it - my public GitHub Pages repository still looks the same as it does when I pushed to it locally from my terminal. Only now, I’m able to take advantage of a couple great deployment tools to have the site update whenever I push to my private repo, whether I’m on my laptop or out and about with my iPad.

Private-to-public GitHub Pages deployment with Travis CI

Travis CI has the built-in ability (♪) to deploy to GitHub Pages following a successful build. They do a decent job in the docs of explaining how to add this feature, especially if you’ve used Travis CI before… which I haven’t. Don’t worry, I did the bulk of the figuring-things-out for you.

Travis CI gets all its instructions from a configuration file in the root of your repository called .travis.yml

Once your script successfully finishes doing what you’ve told it to do (not necessarily what you want it to do but that’s a whole other blog post), Travis will deploy your build directory to a repository you can specify with the repo configuration variable.

Setting up the Travis configuration file

Create a new configuration file for Travis with the filename .travis.yml (note the leading “."). These scripts are very customizable and I struggled to find a relevant example to use as a starting point - luckily, you don’t have that problem!

This script downloads and installs Hugo, builds the site with the garbage collection and minify flags, then deploys the public/ directory to the specified repo - in this example, your public GitHub Pages repository. You can read about each of the deploy configuration options here.

Your encrypted token magically appears in the file. Once you’ve committed .travis.yml to your private Hugo repository, Travis CI will run the script and if the build succeeds, will deploy your site to your public GitHub Pages repo. Magic!

To preserve the Git history of our separate GitHub Pages repository, we’ll first clone it, build our new Hugo site to it, and then push it back to the Pages repository. This script first removes any existing public/ folder that might contain files or a Git history. It then clones our Pages repository to public/, builds our Hugo site (essentially updating the files in public/), then takes care of committing the new site to the Pages repository.

In the deploy section, you’ll notice lines starting with &&. These are chained commands. Since Make invokes a new sub-shell for each line, it starts over with every new line from our root directory. To get our cd to stick and avoid running our Git commands in the project root directory, we’re chaining the commands and using the backslash character to break long lines for readability.

Similarly to using Travis CI, we’ll need to pass in a GitHub personal access token to push to our public GitHub Pages repository - only Netlify doesn’t provide a straightforward way to encrypt the token in our Makefile.

Instead, we’ll use Netlify’s Build Environment Variables, which live safely in our site settings in the Netlify app. We can then call our token variable in the Makefile. We use it to push (quietly, to avoid printing the token in logs) to our Pages repository by passing it in the remote URL.

To avoid printing the token in Netlify’s logs, we suppress recipe echoing for that line with the leading @ character.

With your Makefile in the root of your private GitHub repository, you can set up Netlify to run it for you.

Setting up Netlify

Getting set up with Netlify via the web UI is straightforward. Once you sign in with GitHub, choose the private GitHub repository where your Hugo site lives. The next page Netlify takes you to lets you enter deploy settings:

You can specify the build command that will run your Makefile (make all for this example). The branch to deploy and the publish directory don’t matter too much in our specific case, since we’re only concerned with pushing to a separate repository. You can enter the typical master deploy branch and public publish directory.

Under “Advanced build settings” click “New variable” to add your GitHub personal access token as a Build Environment Variable. In our example, the variable name is GITHUB_TOKEN. Click “Deploy site” to make the magic happen.

If you’ve already previously set up your repository with Netlify, find the settings for Continuous Deployment under Settings > Build & deploy.

Same same but different

One effect of using Netlify this way is that your site will be built in two places: one is the separate, public GitHub Pages repository that the Makefile pushes to, and the other is your Netlify site that deploys on their CDN from your linked private GitHub repository. The latter is useful if you’re going to play with Deploy Previews and other Netlify features, but those are outside the scope of this post.

The main point is that your GitHub Pages site is now updated in your public repo. Yay!

Go forth and deploy fearlessly

I hope the effect of this new information is that you feel more able to update your sites, wherever you happen to be. The possibilities are endless - at home on your couch with your laptop, out cafe-hopping with your iPad, or in the middle of a first date on your phone. Endless!

Don’t do stuff on your phone when you’re on a date. Not if you want a second one, anyway.

Victoria Drake is a senior software developer in Washington, DC. She is a twice-awarded annual Top Contributor to the freeCodeCamp non-profit, and a recognized Distinguished Author on the DEV.to developer platform. She currently contributes to the Open Web Application Security Project as a core maintainer and co-author for the Web Security Testing Guide. She writes about software development, cybersecurity, and information security awareness.