Felix Kling

Custom GitHub pages redirect with nginx

I migrated my personal website from GitHub Pages to my own web server a while ago. VPS’ are cheap and I enjoy managing my own web server.

However, there is one feature GitHub pages provides that I wanted to preserve: When you have a user page with a custom domain (might also work without a custom domain, not sure), every project page is available under http://example.net/<project>/ (where example.net is the custom user page domain).

I wanted to preserve this behavior, primarily because I didn’t want to break existing links, but I also wanted to do this in an automated way.

The GitHub API #

The first step was to get information about which of my repositories have GitHub pages enabled.

GitHub provides an API to access information about repositories. Some information is publicly accessible without authentication. That makes getting the information much easier. Unauthenticated access is subject to stricter rate limits, but that is not an issue in my case.

The endpoint to use is https://api.github.com/users/<user>/repos which returns a (JSON) array of repo objects. You can curl the URL for your own user account to see all the data available.

The properties we are most interested in are name and has_pages: name is the value to be used in URL to redirect to, has_pages tells us whether the repo has GitHub pages enabled.

jq to the rescue #

jq is a powerful little utility for processing JSON data. To filter the array for repos that have a GitHub page and get there name’s, I use the following command:

curl <url> | jq -r '.[] | select(.has_pages) | .name'

Creating nginx directives #

I use nginx as my webserver. In order to redirect requests to GitHub I have to create location directives that look like

location /the-repo/ {
  proxy-pass https://<user>.github.io/the-repo/;
}

This is pretty easy to do with awk or sed:

awk '{ printf "location /%s/ {\n proxy_pass https://<user>.github.io/%s/;\n}\n", $0, $0}' > github-pages-redirect

The created file just needs to be included in the main nginx configuration file for the site and the server needs to be reloaded:

# /etc/nginx/sites-enabled/<site>

server {
 ...

 include path/to/github-pages-redirect;
}

Complete script #

Here is the complete script with placeholders. It also checks whether the generated file not empty because I got invalid responses from the GitHub API from time to time.

#!/bin/sh

GH_ACCOUNT=account
FILE=$HOME/github-pages-redirect

curl --silent https://api.github.com/users/${GH_ACCOUNT}/repos |
	jq -r '.[] | select (.has_pages==true) | .name' |
		sort |
			awk '{ printf "location /%s/ {\n proxy_pass https://${GH_ACCOUNT}.github.io/%s/;\n}\n", $0, $0}' > $FILE.new

if diff --new-file $FILE $FILE.new; then
	exit 0
fi

mv $FILE.new $FILE
sudo systemctl reload nginx