# GitHub Pages HTTPS for custom domains: setup and fixes

> Enable HTTPS on a GitHub Pages custom domain: the four A and AAAA records, www CNAME, letsencrypt.org CAA, Enforce HTTPS and certificate errors.

Source: https://ssl.sh/guides/github-pages-https/
Last updated: 2026-11-10

GitHub Pages gets a free Let's Encrypt certificate for your custom domain automatically. When you save the domain in the repository's Pages settings, GitHub checks DNS, requests and installs the certificate, and shows a check mark next to the domain within an hour. Then you can tick **Enforce HTTPS**.

There is no option to upload your own certificate, and GitHub strongly discourages wildcard DNS. Steps follow GitHub's documentation as of November 2026; `octocat.github.io` and `example.com` stand for your account and domain.

## At a glance

| Question | GitHub Pages |
|---|---|
| CA for automatic certificates | Let's Encrypt |
| Apex (`example.com`) | four `A` records (plus optional four `AAAA`), or ALIAS/ANAME to `octocat.github.io` |
| `www` and other subdomains | `CNAME` to `octocat.github.io` (no repository name) |
| CAA must allow | `letsencrypt.org` |
| Wildcard certificates | Not offered; wildcard DNS records are strongly discouraged |
| Upload your own certificate | Not documented |
| Time to HTTPS | Up to an hour after DNS is correct |

## Step 1: Verify the domain and set it in the repository

GitHub recommends verifying the domain for your account or organization before adding it to a repository. Verification stops someone else from claiming the name for their Pages site if your DNS ever points at GitHub without a repository behind it.

Then open the repository, go to **Settings > Pages**, enter `example.com` (or `www.example.com`) under **Custom domain** and click **Save**. The automatic DNS check starts immediately.

## Step 2: Create the DNS records

The apex needs four `A` records (and optionally four `AAAA` records) pointing at GitHub, and `www` needs a CNAME to your `github.io` address. For an apex domain, create all four `A` records:

```dns
example.com.  3600  IN  A     185.199.108.153
example.com.  3600  IN  A     185.199.109.153
example.com.  3600  IN  A     185.199.110.153
example.com.  3600  IN  A     185.199.111.153
```

For IPv6, add the matching `AAAA` records `2606:50c0:8000::153`, `2606:50c0:8001::153`, `2606:50c0:8002::153` and `2606:50c0:8003::153`. If your DNS provider supports ALIAS or ANAME, you can point the apex at `octocat.github.io` instead.

For `www` or any other subdomain, create a `CNAME` to `octocat.github.io`. Do not include the repository name in the target.

Set up both the apex and `www`: GitHub then creates the redirect between them automatically. If the custom domain is `example.com`, a visitor to `www.example.com` is redirected to `example.com`, and the other way round.

Extra records break certificate issuance. GitHub warns that any additional `A`, `AAAA`, `ALIAS` or `ANAME` records on `@`, or `CNAME` records for the subdomain that point elsewhere, may prevent the certificate from being generated. Check:

```bash
dig example.com +noall +answer -t A
dig example.com +noall +answer -t AAAA
dig www.example.com +noall +answer -t CNAME
```

## Step 3: Allow Let's Encrypt in CAA

If you publish CAA records, at least one must have the value `letsencrypt.org`, otherwise the site is not served over HTTPS:

```dns
example.com.  3600  IN  CAA  0 issue "letsencrypt.org"
```

No CAA records at all is also fine. Check the live policy with the [CAA checker](https://ssl.sh/tools/caa-checker/); the background is in [CAA records explained](https://ssl.sh/learn/caa-records/).

## Step 4: Enforce HTTPS

Once the check mark appears, select **Enforce HTTPS** under **Settings > Pages**. HTTP requests are then transparently redirected to HTTPS. Sites on `github.io` created after June 15, 2016 already get HTTPS automatically.

If pages still show a broken padlock, they load images, CSS or JavaScript over `http://`. Change those URLs to `https://` (in Jekyll sites, look in `_layouts`), or find them with the [mixed content scanner](https://ssl.sh/tools/mixed-content-scanner/). See [mixed content warnings](https://ssl.sh/errors/mixed-content-warning/).

## Wildcards and your own certificate

GitHub Pages issues certificates only for the names you configure. Its documentation has no option for uploading a certificate and strongly recommends against wildcard DNS records such as `*.example.com`, because they expose you to domain takeover. If you need an OV or EV certificate, a certificate from another CA, or a wildcard, put a CDN or reverse proxy that accepts custom certificates in front of the site.

## Verify

A working custom domain presents a Let's Encrypt certificate for the exact name you saved, and HTTP redirects once **Enforce HTTPS** is on. Check it with the [SSL checker](https://ssl.sh/tools/ssl-checker/), or from a terminal:

```bash
curl ssl.sh/example.com
```

Inspect the certificate GitHub serves for your name:

```bash
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
  | openssl x509 -noout -issuer -subject -ext subjectAltName -dates
```

The issuer should be a Let's Encrypt intermediate and the SAN list should contain your domain. If your domain is missing from the SAN list, provisioning has not finished or the DNS check failed.

## Renewal

Renewal is GitHub's job: nothing in Pages settings asks you to renew, and there is no upload option. GitHub's documentation describes how the certificate is requested and installed, but not how it is renewed. What you control is the DNS: keep the records pointed at GitHub and keep `letsencrypt.org` in CAA. Let's Encrypt certificates get shorter (64 days from February 10, 2027 and 45 days from February 16, 2028) and Let's Encrypt has sent no expiry emails since June 4, 2025, so watch the domain with [ssl.sh monitoring](https://ssl.sh/monitor/) (in development).

## Troubleshooting

- **Certificate not yet created**: this is the error GitHub's documentation names for stalled provisioning. If it has not cleared several minutes after you clicked **Save**, click **Remove** next to the custom domain, type the name again and click **Save**. That cancels and restarts provisioning.
- **Enforce HTTPS unavailable**: the certificate is not ready yet. Allow up to an hour, then repeat the remove-and-save step.
- **HTTPS stopped after you changed DNS**: GitHub notes you may need to remove and re-add the custom domain to trigger HTTPS again after changing existing DNS settings.
- **CAA blocks issuance**: add `0 issue "letsencrypt.org"`; see [CAA record prevents issuance](https://ssl.sh/errors/caa-record-prevents-issuance/).
- **Long domain names**: the full domain must be shorter than 64 characters for a certificate to be created.
- **Wrong certificate in the browser** ([NET::ERR_CERT_COMMON_NAME_INVALID](https://ssl.sh/errors/net-err-cert-common-name-invalid/)): extra `A`/`AAAA` records or a stale CNAME are sending some visitors elsewhere. Remove every record that does not point at GitHub.
