Github Pages With Multiple Custom Subdomains

GitHub Pages are an easy and free way to host a web site (like this one!). By default, GitHub will host your site at <your_username> The Pages documentation also covers setting up a custom domain for your site, which can be any of the following combinations:

  1. your apex domain (e.g.
  2. the www subdomain (e.g.
  3. both the apex and www domains
  4. a custom subdomain (e.g.

If you have a site like mine, where all the content is a non-www subdomain (i.e., you probably want users who type in your apex domain (i.e. or the www subdomain to reach your subdomain. You may not have more than one custom subdomain for a GitHub Pages website, but you can make visitors reach your content succesfully, as I explain at the bottom of the post.

Why you can’t have multiple custom subdomains

To understand why two subdomains can not point to the same GitHub pages site, we have to understand some details about shared web hosting and DNS.

Many websites, one server

Shared web hosting allows one single web server to host multiple websites with their own domain name. So, and might have one single web server providing different content for each site. This server can determine which content to show because the HTTP request from a browser to a server includes the hostname (e.g. as part of the request.

But web browsers do not send their requests to a domain name – they send their requests to an IP address. When a user browses to, the web browser needs to find the correct IP address to send a request to. The browser makes a DNS request to a DNS server, which responds with the correct IP address. The browser then makes its HTTP request (with as part of the request) to this IP address.

Turning a name into an address

There are several types of DNS records, but only 2 are important for this post: A and CNAME records. A records are easy to understand: they map domain name like to an IP address like CNAME records, on the other hand, point to another domain name. For example, has a CNAME pointing to, which has an A record pointing to You can see these records by using the dig command:

⚡⇒ dig

; <<>> DiG 9.8.3-P1 <<>>
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 36963
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0

;       IN  A

;; ANSWER SECTION:    323258  IN  CNAME 36 IN  A

It is important to understand that every DNS requests results in an IP address. So, if I create a CNAME record for which maps to, the IP address in the DNS response for and will be the same – they will both give the IP address for the shared web host that GitHub is using for GitHub Pages. This IP address is the same for all sites running on GitHub Pages.

Where there’s a problem

Recall from earlier in this post that the shared web host uses the domain name in the HTTP request to determine which content to display. GitHub Pages only allows one single domain name to be configured for a site. I have chosen Even if I make a CNAME record for which maps to, when my browser makes the request to the GitHub Pages IP address, it will include in the header, which GitHub Pages will not know how to interpret.

The solution: HTTP redirects

The solution is to host a site which has a HTTP 301 redirect to Then, I can set the DNS records for and to this new site. Any requests to this site will be redirected to

One of the advantages of using GitHub Pages for this web site is that I do not need to maintain a web server, so I do not want to run a web server just to serve my HTTP redirect.

Instead, we can use to create a static web site for and, and then configure that web site to redirect all traffic to

The complete picture

The final result looks like this:

  • An AWS S3 bucket named and, both configured for static web hosting to redirect all requests to another host name.
  • A DNS CNAME record for and, both pointing to their respective AWS S3 static web sites.
  • A DNS CNAME record for, pointing to

With this setup, a user who enters in their web browser will get redirected to, which will be served by my GitHub Pages web site.