Post

Deployment: GitHub Pages, Cloudflare Domains & PairDrop

Deploying PairDrop for local file transfer, launching on GitHub Pages, and migrating from jamcre.github.io to jamcre.dev behind Cloudflare.

Deployment: GitHub Pages, Cloudflare Domains & PairDrop

Overview

Two things happened after optiplex went live. I added a utility service to streamline the blog post creation. Then the site itself, which I’ve been populating with posts in private, finally has enough content to go public. This post covers both: the PairDrop deployment and the full process of launching the site on GitHub Pages with a custom domain behind Cloudflare.


PairDrop: Local File Transfer

When documenting hardware I faced a recurring issue: getting pictures taken by my iPhone onto my Windows workstation was VERY annoying. During my time in college I mostly worked on my Macbook so AirDrop handled Apple-to-Apple transfers natively; However, this wouldn’t work for me now that I primarily worked on my Windows Desktop.

PairDrop remedied this issue. It’s a self-hosted, browser-based file transfer tool that works across any device on the same network. Just open the URL on both devices and transfer directly.

It was deployed as an LXC container on optiplex using the Proxmox VE community helper scripts and made accessible through NPM at https://pairdrop.jamcre.dev.

Proxmox shell during PairDrop installation PairDrop LXC container installing in the Proxmox shell

PairDrop web UI PairDrop web UI — both devices visible and ready to transfer

File transfer confirmed Successful file deliveries to the workstation

The immediate use case was transferring the hardware photos from the V3-1 post. It worked on the first attempt with no configuration beyond the DNS record and proxy host.


Deploying the Site: GitHub Pages & Chirpy

The site has been running locally throughout V2 and V3. With enough posts published to represent the project meaningfully, I felt comfortable making it public.

Chirpy’s getting-started guide covers the deployment process in detail. In short: Chirpy ships with a GitHub Actions workflow that builds and publishes the site automatically on every push to the main branch. Enabling GitHub Pages on the repository and pointing it at the gh-pages branch is all that is required to activate it.

The default result was the site live at jamcre.github.io. That served as the staging point before the domain migration.


Domain Migration: jamcre.github.io → jamcre.dev

The jamcre.dev domain was already in use for internal lab services through NPM. So using it for the public site made sense.

The migration involved the following steps:

1. CNAME File

A CNAME file was added to the repository root containing the custom domain:

1
jamcre.dev

Committing this file triggers a GitHub Actions rebuild automatically. GitHub recognizes the file and begins expecting DNS to resolve the domain to its servers.

2. _config.yml Update

Two values were updated to reflect the new URL:

1
2
url: "https://jamcre.dev"
baseurl: ""

This ensures all internal links, tags, and sitemap entries generate against the correct domain rather than the .github.io address.

3. GitHub Pages Custom Domain

In the repository settings under Pages → Custom domain, jamcre.dev was entered. GitHub runs a DNS check at this point. It will not pass until the DNS records are in place.

4. Cloudflare DNS Records

Four A records point the apex domain to GitHub Pages’ IP addresses, and a CNAME maps the www subdomain to the original GitHub Pages hostname. All records are proxied through Cloudflare (orange cloud enabled):

1
2
3
4
5
A      @    185.199.108.153
A      @    185.199.109.153
A      @    185.199.110.153
A      @    185.199.111.153
CNAME  www  jamcre.github.io

Using all four A records is intentional. GitHub Pages is served from multiple edge IPs and recommends pointing to all four for reliability.

5. SSL/TLS Configuration

Two settings were applied in the Cloudflare dashboard:

SettingValue
SSL/TLS modeFull (strict)
Always Use HTTPSEnabled

Full (strict) mode requires a valid certificate on the origin and ensures the entire request path is encrypted end-to-end.

6. SSL 526 Error & Resolution

After enabling the Cloudflare proxy, the site returned an SSL 526 error (invalid SSL certificate on the origin).

The cause: Cloudflare’s proxy was intercepting the request before GitHub’s ACME challenge could complete, preventing Let’s Encrypt from issuing the origin certificate that Full (strict) mode requires.

Fix:

  1. Set all four A records to DNS-only (grey cloud), bypassing the Cloudflare proxy temporarily
  2. In the GitHub Pages settings, enable Enforce HTTPS
  3. Wait for GitHub to complete the Let’s Encrypt certificate issuance
  4. Re-enable the Cloudflare proxy (orange cloud) on all A records

The 526 error is a sequencing issue. GitHub needs a direct connection to its ACME server to issue the cert. The proxy has to come down first, then go back up after the cert exists.

7. Redirect Verification

With the cert issued and the proxy re-enabled, the original GitHub Pages URL was tested:

1
curl -I http://jamcre.github.io

GitHub returns a 301 to https://jamcre.dev/ automatically. The redirect is permanent and requires no manual configuration — GitHub handles it once a custom domain is set on the repository.

8. Google Search Console

The jamcre.dev property was already verified in Google Search Console via Cloudflare DNS. The sitemap was submitted:

1
https://jamcre.dev/sitemap.xml

Chirpy generates the sitemap automatically as part of its build process.


End State

ItemStatus
Public URLhttps://jamcre.dev — live
CDNCloudflare — proxied, HTTPS enforced
HostingGitHub Pages
CI/CDGitHub Actions — builds on every push
Legacy URLjamcre.github.io — 301 → jamcre.dev
Self-hosted infrastructureNot involved in serving the public site

The public site runs entirely on GitHub’s infrastructure with Cloudflare in front. optiplex handles nothing related to public traffic… for now.


What’s Next

The lab documentation is public and infrastructure is stable. Both sides of the project are in a state I feel comfortable sharing.

What’s next I’m still deciding at the moment, but will probably elaborate more on the next post.

This post is licensed under CC BY 4.0 by the author.