Moving rupin.dev to Cloudflare
// Published On: Aug 23, 2026
This site used to run on GitHub Pages, with the domain sitting over at IONOS. Today I moved both to Cloudflare: hosting on Cloudflare Pages, DNS on Cloudflare. Took about 3 hours including the research.
Why move
- IONOS’s UI was overwhelming and didn’t work well in English. It just wasn’t a pleasant tool to use.
- One dashboard for DNS, SSL, and hosting instead of splitting that across IONOS and GitHub.
- Wanted
rupinr.github.iofree for other things instead of it being tied up hosting this site. - Cloudflare’s web analytics.
Step 1: Move the domain from IONOS to Cloudflare
This is the step where the domain itself changes hands, so I did it first.
-
Added
rupin.devas a site in Cloudflare. It scans existing DNS records from IONOS and imports them automatically. -
Reviewed the imported records. I don’t send or receive email on this domain, so I added two
TXTrecords to stop anyone from spoofing mail asrupin.dev:Name Value @v=spf1 -all_dmarcv=DMARC1; p=reject; adkim=s; aspf=s -
Cloudflare gave me two nameservers,
bowen.ns.cloudflare.comandannalise.ns.cloudflare.com. Logged into IONOS and swapped them in under the domain’s DNS/nameserver settings. -
Waited for propagation. Cloudflare emails you once it picks up the change; mine took minutes.
-
Once active, transferred the domain registration itself from IONOS to Cloudflare Registrar. Had to grab the “Domain-Autorisierungscode” (IONOS’s name for the auth/EPP code) and hand it to Cloudflare to authorize the transfer. I still had several months left on the IONOS registration and was worried about losing that. Turns out Cloudflare charges for a fresh year on transfer, but the remaining IONOS validity just gets added on top. Nothing lost.
Step 2: Create a Cloudflare Pages project and deploy via CLI
Created a new Pages project (rupin-dev) under Workers & Pages in the dashboard. Also created an API token scoped to Pages with Read and Write access and grabbed the account ID, set both as CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID in my local shell env. Then just deployed the built site straight to the project with Wrangler, to make sure it worked before touching CI at all:
npm run build
npx wrangler pages deploy ./dist --project-name=rupin-dev
Working site at rupin-dev.pages.dev.
Step 3: Add the custom domains
Domain was already on Cloudflare at this point, so adding it to the Pages project was easy. From the Custom Domains tab I added rupin.dev and www.rupin.dev. SSL certs for both, handled automatically.
Step 4: Automate deploys with GitHub Actions
Manual CLI deploy worked, so I moved it into CI. Reused the same Pages Read/Write token and account ID as GitHub repo secrets: CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID.
The old workflow built with npm run build and pushed ./dist to rupinr/rupinr.github.io using peaceiris/actions-gh-pages:
- name: Deploy to rupinr.github.io
uses: peaceiris/actions-gh-pages@v4
with:
personal_token: ${{ secrets.PAGES_DEPLOY_TOKEN }}
external_repository: rupinr/rupinr.github.io
publish_branch: main
publish_dir: ./dist
Swapped it for wrangler-action, which deploys straight to the Pages project from the build output:
- name: Deploy to Cloudflare Pages
uses: cloudflare/wrangler-action@v4.0.0
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: pages deploy ./dist --project-name=rupin-dev
Old GitHub Pages step out, Cloudflare deploy step in.
Step 5: Clean up GitHub Pages remnants
- Deleted the now-unused
rupinr.github.iorepo and thePAGES_DEPLOY_TOKENsecret. - Went back afterward and cleared out the leftover IONOS DNS records that Cloudflare had auto-imported but weren’t actually needed.
Step 6: Verify and cut over
- Site loads fine over HTTPS on the new hosting.
- DNS records, especially
MX/TXT, resolve correctly through Cloudflare. - A push to
maintriggers the workflow and deploys throughwrangler-actionwithout issues.
A broken comment section
A few minutes later comments broke: giscus is not installed on this repository. Giscus was still pointed at rupinr/rupinr.github.io, the repo I’d just deleted. Giscus needs its GitHub App installed on the exact repo it targets, so once that repo was gone, comments went with it.
Didn’t want to resurrect a repo I was trying to get rid of, so I gave giscus its own dedicated repo instead, one that only exists to back comments and won’t get swept up in some future cleanup: rupinr/rupin-dev-discussions.
- Created the new public repo.
- Enabled Discussions under Settings → General → Features.
- Installed the giscus app on it.
- Went to giscus.app, pointed it at the new repo, picked the same pathname mapping and an “Announcements” category, copied the generated
data-repo-idanddata-category-id. - Updated the giscus settings in the component I used to render it.
Domain, DNS, and hosting are all on Cloudflare now, and comments are back up running through the new repo.