Publishing this site

From a local folder to a live site on your own domain

Runbook ~45 min active Plus up to 24h DNS wait

What you will do

  • Put the site under version control and push it to GitHub
  • Turn on GitHub Pages using the workflow already in this repository
  • Point a domain you own at the site
  • Force HTTPS and verify everything resolves
  • Learn the two-command routine for publishing changes afterwards

Before you start

You need How to check If missing
Git git --version git-scm.com/downloads
A GitHub account Sign in at github.com Free tier is sufficient
Quarto quarto --version quarto.org
A domain You have bought one Any registrar — see Part 3
The site renders locally quarto render completes Fix errors first
ImportantRender locally before you push
quarto render

If this fails on your machine it will fail in GitHub Actions, and debugging is slower there. Get a clean local render first.

Part 1 — Put the site on GitHub

1.1 Initialise the repository

From the project folder:

cd path/to/rlearning_site

git init
git branch -M main

git branch -M main renames the default branch to main, which is what the publishing workflow expects.

1.2 Check what will be committed

The repository already has a .gitignore that excludes _site/, .quarto/ and .Rproj.user/. Confirm nothing unwanted is staged:

git add .
git status --short

You should see roughly 60 files — the .qmd lessons, _quarto.yml, assets/, the workflow and the README. You should not see _site/, .quarto/ or any data files.

WarningCheck this before the first commit, not after

Anything committed stays in the history even if you delete it in a later commit. If a file with confidential content is ever pushed, treat it as disclosed. Removing it properly means rewriting history, which is disruptive and does not help if someone already cloned the repository.

1.3 First commit

git commit -m "Add R Learning Lab Quarto site

Four courses (R Programming, R Shiny, Python, Clinical Programming with R),
46 lessons plus landing, about, training and contact pages. Pharma-corporate
theme and a GitHub Pages publishing workflow."

If Git asks who you are:

git config --global user.name  "Your Name"
git config --global user.email "you@example.com"

1.4 Create the GitHub repository

With the GitHub CLI — one command, creates and pushes:

gh auth login          # first time only
gh repo create rlearning-site --public --source=. --remote=origin --push

Through the website — go to github.com/new and:

  • Repository name: rlearning-site
  • Public — required for GitHub Pages on the free tier
  • Do not add a README, .gitignore or licence; you already have them

Then connect and push:

git remote add origin https://github.com/YOUR-USERNAME/rlearning-site.git
git push -u origin main
NoteRepository name and the default URL

The repository name determines your default Pages URL:

Repository name Default URL Type
rlearning-site username.github.io/rlearning-site Project site
username.github.io username.github.io User site

Once a custom domain is attached, both serve from the domain root, so this choice stops mattering. Pick whichever you prefer.

Part 2 — Turn on GitHub Pages

2.1 Set the publishing source

In your repository on GitHub:

  1. Settings (top row of the repository, not your account settings)
  2. Pages in the left sidebar
  3. Under Build and deploymentSource, choose GitHub Actions

Do not choose “Deploy from a branch”. The workflow in .github/workflows/publish.yml uses the Actions method, and the two are mutually exclusive.

2.2 Watch the first deployment

Open the Actions tab. A run called Publish site should be in progress.

It does three things in order:

  1. Checks every internal link resolves — a broken cross-reference fails the build
  2. Renders the site with Quarto
  3. Uploads _site/ and deploys it

The first run takes two to three minutes. When it finishes, Settings → Pages shows the live URL.

2.3 If the run fails

Symptom Cause Fix
“Get Pages site failed” Source not set to GitHub Actions Do step 2.1 first
Link check fails A .qmd link points nowhere The log names the file and target
Quarto render error Same error you would see locally Reproduce with quarto render
“Resource not accessible” Workflow permissions Settings → Actions → General → Workflow permissions → Read and write

Part 3 — Connect your domain

3.1 Decide on the shape

You have three options. The third is what most sites use.

Option Visitors type DNS needed
Apex only example.com 4 A records (+ 4 AAAA for IPv6)
Subdomain only www.example.com 1 CNAME record
Both, apex redirects to www Either works A records and a CNAME

The third is recommended: www is a CNAME, which behaves better with CDNs and lets your DNS provider fail over cleanly, and GitHub creates the redirect between the two automatically once both are configured.

3.2 Add the DNS records

At your registrar’s DNS panel, add the following. Delete any existing A, AAAA, CNAME or parking records for the same names first — conflicting records are the most common reason this does not work.

For the apex domain (example.com), four A records:

Type Name / Host Value TTL
A @ 185.199.108.153 3600
A @ 185.199.109.153 3600
A @ 185.199.110.153 3600
A @ 185.199.111.153 3600

Optionally add IPv6, four AAAA records:

Type Name / Host Value
AAAA @ 2606:50c0:8000::153
AAAA @ 2606:50c0:8001::153
AAAA @ 2606:50c0:8002::153
AAAA @ 2606:50c0:8003::153

For the www subdomain, one CNAME record:

Type Name / Host Value TTL
CNAME www YOUR-USERNAME.github.io. 3600

The value is your GitHub username followed by .github.ionot the repository name, and not the full site URL. The trailing dot is required by some providers and ignored by others.

WarningVerify these addresses against GitHub’s documentation

The IP addresses above are GitHub’s published values, but they have changed before and could change again. Confirm them at Managing a custom domain for your GitHub Pages site before you rely on them.

3.3 Registrar-specific notes

Registrar Watch out for
Cloudflare Set the proxy status to DNS only (grey cloud), not Proxied (orange). Proxying breaks GitHub’s certificate issuance. You can turn it on later, after HTTPS is working.
Namecheap Use Advanced DNS. The host field is @ for apex, www for the subdomain. Remove the default “CNAME Record → parkingpage” entry.
GoDaddy Remove the default A record pointing at their parking IP. GoDaddy sometimes re-adds it — check after 24 hours.
Google Domains / Squarespace Under DNS → Custom records. Apex is a blank name or @.
Route 53 Use an Alias record for the apex if you prefer, or the four A records.

3.4 Tell GitHub about the domain

Back in Settings → Pages → Custom domain:

  1. Enter your domain — use www.example.com if you set up both
  2. Click Save
  3. GitHub runs a DNS check. A green tick means it resolved.
ImportantDo not create a CNAME file — it will be ignored

With branch-based publishing, GitHub stores the custom domain in a CNAME file, and workflows that overwrite it cause the domain to reset on every push. That is the cause of most “my custom domain keeps disappearing” reports.

This repository publishes with a GitHub Actions workflow, where a CNAME file is ignored and not required. The domain lives in the repository settings and persists across deployments. Adding a CNAME file to the project will do nothing — set the domain in Settings, and only there.

3.5 Wait, then enforce HTTPS

DNS changes take anywhere from a few minutes to 24 hours to propagate. GitHub also has to obtain a Let’s Encrypt certificate, which it does automatically once the DNS check passes.

Once the certificate is issued, return to Settings → Pages and tick Enforce HTTPS. The checkbox is greyed out until the certificate exists — if it is still grey after an hour, the DNS is not yet correct.

Part 4 — Point the site config at the domain

Quarto uses site-url for the sitemap, canonical URLs and social preview cards. Update it:

_quarto.yml
website:
  title: "R Learning Lab"
  site-url: https://www.example.com

Then publish the change:

quarto render                    # confirm it still builds
git add _quarto.yml
git commit -m "Set site-url to the custom domain"
git push

The push triggers the workflow and the site redeploys in about two minutes.

Part 5 — Verify

5.1 Check DNS resolution

# Apex should return the four GitHub IPs
dig +short example.com

# www should return the github.io alias, then the IPs
dig +short www.example.com

# On Windows
nslookup example.com

5.2 Check the site responds

# Should return HTTP/2 200
curl -sSI https://www.example.com | head -1

# Apex should return a 301 redirect to www
curl -sSI https://example.com | head -3

# HTTP should redirect to HTTPS
curl -sSI http://www.example.com | head -3

5.3 Final checklist

Routine updates

Once set up, publishing a change is two commands:

git add .
git commit -m "Describe what changed"
git push

The workflow renders and deploys automatically. Check the Actions tab if the change does not appear within a few minutes.

A safer habit for anything substantial — render locally first, so a mistake never reaches the live site:

quarto render          # catches errors before they reach CI
git add .
git commit -m "Add lesson on X"
git push

Troubleshooting

Symptom Likely cause Fix
404 at the custom domain DNS not propagated Wait; check with dig
404 at username.github.io/repo Pages source not set Settings → Pages → Source → GitHub Actions
“Domain does not resolve to the GitHub Pages server” Wrong or conflicting DNS records Remove old A/CNAME/parking records
“Enforce HTTPS” greyed out Certificate not yet issued Wait up to 24h after DNS is correct
Certificate warning in the browser Certificate issued for the other name Ensure both apex and www records exist
Custom domain keeps resetting Usually a branch-deploy problem Not applicable here — confirm Source is GitHub Actions
CSS missing, unstyled page Wrong site-url, or a stale cache Fix site-url; hard-refresh
Site not updating after a push Workflow failed Check the Actions tab
Cloudflare 522 or redirect loop Proxy enabled Set the record to DNS only (grey cloud)

Optional hardening

Verify the domain against takeover

If you later delete the repository but leave the DNS pointing at GitHub, someone else can claim the domain by creating a repository with the same name. GitHub’s domain verification prevents that.

Account settings → Pages → Add a domain, then add the TXT record it gives you. Do this once per domain.

Add a custom 404 page

Create 404.qmd at the project root:

404.qmd
---
title: "Page not found"
sidebar: false
toc: false
---

That page does not exist. Try the [course index](index.qmd), or use the search
box in the navigation bar.

Quarto renders it to 404.html and GitHub Pages serves it automatically.

Deploy on a tag instead of every push

For a site that should only update deliberately, change the trigger in .github/workflows/publish.yml:

.github/workflows/publish.yml
on:
  push:
    tags: ["v*"]
  workflow_dispatch:

Then publish with:

git tag -a v1.1 -m "Add Python testing lesson"
git push --tags

The short version

  1. git init, commit, push to a new public GitHub repository
  2. Settings → Pages → Source → GitHub Actions
  3. Add four A records for the apex and a CNAME for www
  4. Settings → Pages → Custom domain → enter it → Save
  5. Wait for the DNS check, then tick Enforce HTTPS
  6. Set site-url in _quarto.yml, commit and push
  7. Afterwards: git add . && git commit -m "..." && git push

Sources

Back to top