Chapter 5: GitHub Pages: Your Free Portfolio Site
One of the most exciting features of GitHub for creative technologists is GitHub Pages. It allows you to host a static website directly from your GitHub repository, completely free. This is perfect for portfolios, project showcases, documentation sites, or simple blogs.
The workshop highlighted this as "probably the most powerful bit from all of your point of view in terms of you can host your own stuff and it's free... everybody wants a free website, why wouldn't you?"
5.1 How GitHub Pages Works
GitHub Pages takes HTML, CSS, and JavaScript files (and Markdown files, which it can convert to HTML) from a specific branch and folder in your repository and publishes them as a website.
- Static Sites: GitHub Pages is designed for static sites. This means the content is pre-built and served as-is to users. It doesn't support server-side languages like PHP, Python (e.g., Django/Flask), or Node.js backends directly in the way traditional web hosts do. However, you can build very rich interactive experiences using client-side JavaScript frameworks (like React, Vue, Angular) and then deploy the static build output to GitHub Pages.
- URL Structure:
- User/Organization Site: If you name a repository
<username>.github.io(where<username>is your GitHub username or organization name), the content from itsmainbranch (usually from the root or a/docsfolder) will be served athttps://<username>.github.io. You can only have one such site per account/organization. - Project Site: For any other repository, you can enable GitHub Pages. The site will typically be available at
https://<username>.github.io/<repository-name>/.
- User/Organization Site: If you name a repository
5.2 Setting Up GitHub Pages for a Repository
Here's the general process, based on the workshop.md instructions:
-
Prepare Your Website Files:
- Your website needs at least an
index.htmlfile at the root of where it will be served from. You can also have CSS files, JavaScript files, images, etc. - For simplicity, you can place all your website files in the root of your repository or, more commonly, in a dedicated folder named
/docswithin your repository.
- Your website needs at least an
-
Push Your Files to GitHub:
- Ensure your website files (e.g.,
index.html, CSS, JS) are committed to your local Git repository and pushed to GitHub.
- Ensure your website files (e.g.,
-
Configure GitHub Pages Settings:
- On GitHub, navigate to your repository.
- Click on the "Settings" tab for that repository.
- In the left sidebar of the Settings page, scroll down and click on "Pages".
-
Choose a Source:
- Under "Build and deployment", for "Source", select "Deploy from a branch".
- Branch:
- Select the branch you want to deploy from (usually
main). - Select the folder within that branch:
- Choose
/(root)if your website files are in the root of the branch. - Choose
/docsif your website files are in a folder nameddocson that branch. This is a common and recommended practice.
- Choose
- Select the branch you want to deploy from (usually
- Click "Save".
-
Wait for Deployment:
- GitHub will start building and deploying your site. This might take a few minutes.
- The Pages settings page will update to show the URL where your site is published (e.g.,
https://<username>.github.io/<repository-name>/). - "Push any HTML/Markdown file into
/docs– site goes live athttps://<username>.github.io/<repo>/."
5.3 Example: Deploying a Simple Site
Let's imagine you have a repository named my-portfolio.
- Create a folder named
docsin your localmy-portfoliorepository. - Inside the
docsfolder, create anindex.htmlfile with simple content:<!DOCTYPE html> <html> <head> <title>My Awesome Portfolio</title> <link rel="stylesheet" href="style.css"> </head> <body> <h1>Welcome to My Portfolio!</h1> <p>Check out my amazing projects.</p> </body> </html> - Also inside
docs, create astyle.cssfile:body { font-family: sans-serif; margin: 20px; background-color: #f0f0f0; } h1 { color: navy; } - Commit these files and push them to GitHub:
git add docs/index.html docs/style.css git commit -m "Add initial website files for GitHub Pages" git push - Go to your
my-portfoliorepository settings on GitHub, then to "Pages." - Set the source to "Deploy from a branch," choose the
mainbranch, and the/docsfolder. Save. - After a few minutes, your site should be live at
https://yourusername.github.io/my-portfolio/.
The workshop.md included an exercise: "> Exercise – Use the provided template‑site/ folder. Copy it into /docs, push, share the link!" This encourages hands-on practice.
5.4 Using Custom Domains with GitHub Pages
While the default yourusername.github.io/repository-name URL is functional, using a custom domain (e.g., www.yourcreativeproject.com or portfolio.yourname.art) lends a more professional touch to your GitHub Pages site. This section details how to configure a custom domain.
Prerequisites:
- A Registered Domain Name: You need to have already purchased a domain name from a domain registrar (e.g., Namecheap, GoDaddy, Google Domains, Cloudflare Registrar).
- Access to DNS Settings: You must be able to manage the DNS (Domain Name System) records for your domain through your registrar's control panel.
Steps to Configure a Custom Domain:
1. Add Your Custom Domain in GitHub Pages Settings:
- Navigate to your repository on GitHub.
- Go to
Settings→Pages. - In the "Custom domain" section, type your full custom domain (e.g.,
www.yourcreativeproject.comoryourcreativeproject.comif you're using an apex domain) into the input field. - Click
Save.- GitHub may attempt to verify your domain and might show "DNS check in progress" or "DNS check successful."
- This step might also create a
CNAMEfile in the root of your publishing source (e.g., yourmainbranch's/docsfolder or thegh-pagesbranch) containing your custom domain. If you manage your site files locally, ensure thisCNAMEfile is pulled to your local repository and not accidentally overwritten or deleted.
2. Configure DNS Records with Your Domain Registrar:
This is the most crucial and often trickiest part, as the interface varies between domain registrars. You'll need to add specific DNS records to point your domain to GitHub's servers.
Types of DNS Records for GitHub Pages:
-
ARecords (for Apex Domains):- An apex domain (also known as a root domain or naked domain) is like
yourcreativeproject.com(withoutwww). - To configure an apex domain, you must use
Arecords pointing to GitHub's IP addresses. GitHub provides specific IP addresses for this purpose. - GitHub's IP Addresses for
ARecords:185.199.108.153185.199.109.153185.199.110.153185.199.111.153
- You should create four
Arecords, one for each of these IP addresses. - Example
ARecord Configuration (at your registrar):- Type:
A - Host/Name:
@(or leave blank, depending on your registrar –@usually signifies the apex domain) - Value/Points to:
185.199.108.153 - TTL (Time To Live): Typically 1 hour (or 3600 seconds), or your registrar's default.
- (Repeat for the other three IP addresses)
- Type:
- An apex domain (also known as a root domain or naked domain) is like
-
CNAMERecord (for Subdomains):- A subdomain is like
www.yourcreativeproject.com,blog.yourcreativeproject.com, orportfolio.yourname.art. - To configure a subdomain, you should use a
CNAME(Canonical Name) record. - The
CNAMErecord should point to your default GitHub Pages domain (i.e.,yourusername.github.io). Do not include the repository name here. - Example
CNAMERecord Configuration (at your registrar):- Type:
CNAME - Host/Name:
www(orblog,portfolio, etc. – the part of the subdomain before your apex domain) - Value/Points to:
yourusername.github.io(replaceyourusernamewith your actual GitHub username or organisation name) - TTL: Typically 1 hour or default.
- Type:
- A subdomain is like
-
ALIAS,ANAME, orFLATTENINGRecords (Alternative for Apex Domains):- Some DNS providers offer special record types like
ALIAS(e.g., DNSimple, Namecheap),ANAME(e.g., DNS Made Easy), or CNAME Flattening (e.g., Cloudflare). - These records behave like
CNAMErecords but can be used at the apex domain level. If your provider supports this, you can often point your apex domain (yourcreativeproject.com) directly toyourusername.github.io. This is generally preferred overArecords if available, as GitHub's IP addresses could theoretically change (though rarely). - Consult your DNS provider's documentation to see if they support this and how to configure it.
- Some DNS providers offer special record types like
Which to Use?
- For
www.yourdomain.com(or any other subdomain): Use aCNAMErecord pointing toyourusername.github.io. - For
yourdomain.com(apex domain):- Preferred: Use
ALIAS,ANAME, or CNAME Flattening if your DNS provider supports it, pointing toyourusername.github.io. - Alternative: Use four
Arecords pointing to the GitHub IP addresses listed above.
- Preferred: Use
- Using both
wwwand apex (e.g., redirectyourdomain.comtowww.yourdomain.com):- Configure your apex domain with
Arecords (orALIAS/ANAME). - Configure your
wwwsubdomain with aCNAMErecord. - GitHub Pages will typically handle redirecting traffic from the apex to the
wwwversion (or vice-versa) if both are configured and one is set as primary in the GitHub Pages settings, but this can sometimes depend on your registrar's forwarding options too.
- Configure your apex domain with
3. Wait for DNS Propagation:
- DNS changes are not instantaneous. They need to propagate across the internet, which can take anywhere from a few minutes to 24-48 hours (though usually much faster).
- You can use online tools like
dnschecker.orgto see how your DNS records are propagating across different global DNS servers.
4. Verify and Enforce HTTPS:
- Once your custom domain is correctly configured and DNS has propagated, GitHub will automatically attempt to provision an SSL/TLS certificate for your custom domain to enable HTTPS. This is provided by Let's Encrypt.
- In your repository's GitHub Pages settings (
Settings→Pages), you should see a message indicating the status of your custom domain and HTTPS. - Once HTTPS is enabled (you might see "Your site is published at
https://www.yourcreativeproject.com" and a green checkmark), you should tick the "Enforce HTTPS" checkbox. This ensures all visitors are redirected to the securehttps://version of your site.
Troubleshooting Custom Domains:
- DNS Check Fails in GitHub:
- Wait longer for DNS propagation.
- Double-check your DNS records at your registrar for typos or incorrect values/types.
- Ensure the custom domain entered in GitHub Pages settings exactly matches what you're configuring (e.g.,
www.domain.comvs.domain.com).
- Site Not Loading or Certificate Errors:
- Clear your browser cache or try an incognito window.
- Verify DNS propagation using an external tool.
- If HTTPS isn't enabling, ensure your DNS records are stable and correctly pointing to GitHub. Sometimes, removing and re-adding the custom domain in GitHub settings can trigger a new certificate provisioning attempt.
CNAMEFile Issues:- If GitHub created a
CNAMEfile in your repository, ensure it's present and contains only your custom domain (e.g.,www.yourcreativeproject.com).
- If GitHub created a
Using Claude Code for DNS and Custom Domains:
While Claude Code cannot directly configure your DNS settings (as that is done via your domain registrar's website), it can be a valuable assistant. Launch Claude Code and try:
- Understanding DNS Concepts:
- "Explain the difference between an A record and a CNAME record in DNS."
- "What is DNS propagation and why does it take time?"
- "What does TTL mean for a DNS record?"
- Generating Example Configurations:
- "Show me an example of how to configure A records for an apex domain pointing to GitHub Pages IPs."
- "What should a CNAME record look like for pointing
blog.mydomain.comtomyusername.github.io?"
- Troubleshooting Guidance:
- "My custom domain for GitHub Pages is not working. I have set up A records. What are common things to check?"
- "GitHub says 'DNS check failed' for my custom domain. What steps can I take to diagnose this?"
- Explaining Registrar-Specific Instructions:
- If you copy instructions from your domain registrar's help pages, you could ask Claude Code: "My registrar says to 'create an A record pointing to an IP address'. Can you explain what 'Host' and 'Value' fields typically mean in this context?"
Setting up a custom domain adds a layer of professionalism to your GitHub Pages site. While it involves interacting with DNS settings outside of GitHub, following these steps carefully will lead to a successful configuration.
5.5 Advanced: Publishing from a Private Repository using GitHub Actions
While GitHub Pages is excellent for public repositories, you might have scenarios where your website's source code needs to remain private, but you still want to publish the built static site publicly. This can be achieved using GitHub Actions to deploy from your private repository to a separate public repository dedicated to hosting the GitHub Pages site.
This approach ensures your source code, development history, and potentially sensitive information remain confidential, while the compiled static output (HTML, CSS, JavaScript) is made available to the world.
Approach Overview
The core idea is to:
- Keep your website's source code in a private GitHub repository.
- Create a public GitHub repository that will host the GitHub Pages site (e.g.,
yourusername/public-blog-site). - Set up a GitHub Actions workflow in your private repository. This workflow will:
- Trigger on pushes to your main branch (or any branch you designate).
- Build your static site (e.g., using Jekyll, Hugo, Next.js, or a simple HTML copy).
- Push the built static files to the
gh-pagesbranch (or another designated branch) of your public repository.
- Configure GitHub Pages in the public repository to serve from that
gh-pagesbranch.
Step-by-Step Guide
Here’s how to set this up:
1. Create a Personal Access Token (PAT)
To allow your GitHub Actions workflow in the private repository to push to the public repository, it needs authentication. A Personal Access Token (PAT) with appropriate permissions is commonly used for this.
- Navigate to PAT Settings: Go to your GitHub account settings (click your profile picture in the top-right) → Developer settings → Personal access tokens → Tokens (classic).
- Alternatively, you can use Fine-grained personal access tokens, which offer more precise permission control, but "Tokens (classic)" are often simpler for this use case.
- Generate New Token: Click "Generate new token" (or "Generate new token (classic)").
- Permissions (Scopes):
- Give your token a descriptive note (e.g., "GH Pages Deploy Private to Public").
- Select an expiration period.
- Crucially, assign the correct scopes:
repo: This grants full control of repositories, which is needed to push to your public repository.workflow: This allows the token to be used in GitHub Actions workflows, specifically to update workflow files if your action does so (though less common for this specific deployment).
- Save the Token: Click "Generate token". Copy the token immediately and store it securely (e.g., in a password manager). You will not be able to see it again after navigating away from the page. Let's assume your token is
TOKENXXX.
2. Configure the PAT in Your Private (Source) Repository
You must add this PAT as a secret in your private repository so the GitHub Actions workflow can access it securely.
- Go to your private repository on GitHub.
- Navigate to
Settings→Secrets and variables→Actions. - Click
New repository secret. - Name: Choose a name for the secret, for example,
DEPLOY_TOKEN. - Value: Paste the PAT (
TOKENXXX) you copied earlier. - Click
Add secret.
3. Create the GitHub Actions Workflow File
In your private repository, create a YAML file for your workflow. For example, .github/workflows/deploy-to-public-ghpages.yml:
name: Deploy Website to Public GitHub Pages
on:
push:
branches:
- main # Or your default branch, e.g., master
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v4 # Checks out your private repository's code
- name: Set up Node.js (Example for a Node-based SSG)
if: true # Condition this step if needed, e.g., for specific SSGs
uses: actions/setup-node@v4
with:
node-version: '20' # Specify your Node.js version
- name: Build your static site
run: |
# Replace these commands with your actual build process
# For a simple HTML/CSS/JS site, you might just copy files
# mkdir ./public
# cp -r * ./public/
# Example for a Node.js project (e.g., Next.js, Vue, React)
# npm install
# npm run build # Ensure your build output goes to a directory like 'public', 'dist', or 'build'
# Example for Hugo
# hugo --minify # Assumes Hugo is installed or use peaceiris/actions-hugo
echo "Build process complete. Files are in ./public" # Adjust if your output is elsewhere
- name: Deploy to public repository's gh-pages branch
uses: peaceiris/actions-gh-pages@v4
with:
personal_token: ${{ secrets.DEPLOY_TOKEN }}
external_repository: yourusername/your-public-repo-name # IMPORTANT: Change this!
publish_branch: gh-pages # The branch in the public repo to deploy to
publish_dir: ./public # The directory containing your built static site
# user_name: 'github-actions[bot]' # Optional: Custom committer name
# user_email: 'github-actions[bot]@users.noreply.github.com' # Optional: Custom committer email
commit_message: ${{ github.event.head_commit.message }} # Uses the commit message from the trigger
# allow_empty_commit: false # Optional: Prevents empty commits if no changes
# force_orphan: true # Optional: Creates a fresh branch history each time
Key Configuration Notes for the Workflow:
external_repository: Crucially, replaceyourusername/your-public-repo-namewith the actual path to your public repository (e.g.,CreativeTechUser/MyPublicPortfolio).publish_dir: Adjust./publicto match the directory where your static site generator (SSG) or build process outputs the final static files (common alternatives include./dist,./build,./_sitefor Jekyll).- Build Steps: Customise the "Build your static site" step.
- If you're using a specific SSG like Hugo, Jekyll, Next.js, Eleventy, etc., you'll need to include steps to install its dependencies and run its build command.
- For Hugo, you might use an action like
peaceiris/actions-hugobefore your build command. - For Node.js based SSGs, ensure you have a
actions/setup-node@v4step.
4. Enable GitHub Pages in the Public Repository
Finally, configure your public repository to serve GitHub Pages from the branch your action deploys to:
- Go to your public repository on GitHub.
- Navigate to
Settings→Pages. - Under "Build and deployment":
- For "Source", select "Deploy from a branch".
- For "Branch", select the
gh-pagesbranch (or whateverpublish_branchyou specified in your workflow). Ensure the folder is set to/(root).
- Click
Save.
Your site should be live at https://yourusername.github.io/your-public-repo-name/ after the first successful workflow run.
Leveraging Claude Code for This Workflow
Setting up GitHub Actions, especially for the first time, can be intricate. Here is how Claude Code can assist you:
- Generating the Workflow File:
- Ask Claude Code: "Create a GitHub Actions workflow to build a [Your SSG, e.g., Hugo, Next.js] site from this private repository and deploy it to the
gh-pagesbranch of a public repository namedyourusername/public-repo-nameusing a PAT stored asDEPLOY_TOKEN. The build output is in the./builddirectory." - Claude Code can generate a well-structured starting point for your
deploy-to-public-ghpages.ymlfile and write it directly to your project.
- Ask Claude Code: "Create a GitHub Actions workflow to build a [Your SSG, e.g., Hugo, Next.js] site from this private repository and deploy it to the
- Understanding YAML and Actions Syntax:
- "Explain what
uses: actions/checkout@v4does in the workflow file."
- "Explain what
- Customising Build Steps:
- If you are unsure about the build commands for your specific SSG, ask: "What are the typical build commands for a [Your SSG] project, and how do I ensure the output goes to a
./publicdirectory?"
- If you are unsure about the build commands for your specific SSG, ask: "What are the typical build commands for a [Your SSG] project, and how do I ensure the output goes to a
- Finding Specific Actions:
- "I need to use Hugo to build my site in a GitHub Action. Is there a recommended action for setting up Hugo?"
- Troubleshooting Workflow Failures:
- If your GitHub Action fails, copy the error messages from the Actions log and ask Claude Code: "My GitHub Action failed with this error:
[paste error log]. What could be the cause, and how can I fix it?" - Claude Code can help decipher cryptic error messages related to PAT permissions, incorrect paths, or build failures.
- If your GitHub Action fails, copy the error messages from the Actions log and ask Claude Code: "My GitHub Action failed with this error:
- PAT Security and Scopes:
- "What are the security best practices for using Personal Access Tokens in GitHub Actions?"
- "Explain the
repoandworkflowscopes for a GitHub PAT."
Troubleshooting Common Issues
- Permission Errors:
- Double-check that your PAT has the
reposcope. - Ensure the PAT was correctly copied and added as the
DEPLOY_TOKENsecret in the private repository's Actions settings. - Verify the
external_repositoryname is exact.
- Double-check that your PAT has the
- Empty Deployments or "File Not Found":
- Confirm that the
publish_dirin your workflow YAML correctly points to the directory where your build process outputs the static files. Inspect the build logs in your GitHub Actions run to see where files are being placed.
- Confirm that the
- Workflow Not Triggering:
- Ensure the
on: push: branches:section in your workflow correctly lists the branch you are pushing to in your private repository (e.g.,main).
- Ensure the
- SSH-based Deployments (Alternative):
- For SSH key-based deployments (instead of PATs), you would use
deploy_keyin thepeaceiris/actions-gh-pagesaction and configure SSH deploy keys. This is generally more complex to set up initially.
- For SSH key-based deployments (instead of PATs), you would use
This advanced method provides a robust way to manage private source code while still leveraging the power and convenience of GitHub Pages for public-facing sites. Remember to commit your workflow file to your private repository to activate it. Subsequent pushes to your specified branch will then trigger the automated deployment.