From WordPress to Hugo: My Setup Explained
Why I moved from WordPress to Hugo, and how the site runs today — GitHub Actions, GitHub Pages, and Cloudflare.
Note (Updated November 2025)
The site has since moved from Hugo to Astro. Everything below is what it ran on for a year, and the reasoning that got it off WordPress hasn’t changed.
Ten years of WordPress taught me enough to know when to leave. Tuning PHP configs, switching to LiteSpeed, keeping plugins patched — for a blog. Every plugin is another attack surface, and the database is a bottleneck a site with no logged-in users doesn’t need.

Known vulnerabilities tracked at wpscan.com.
The honest second reason is that the alternative is more interesting to run. A git push triggers a build, and the result deploys globally. Writing a post is a markdown file in a repo. If you spend your day in a terminal, that’s the version of a website you actually want to own.
Hugo
merox.dev ran on Hugo for over six months before I wrote this. Static files, no backend, free hosting on GitHub Pages, all of it in git. Hugo is Go, so builds are fast, and the output is clean enough that SEO scores came in above 80% with no extra work.

I went with the Blowfish theme. Forking it first and adding the fork as a submodule is what lets you take upstream updates later without losing your own changes:
git submodule add https://github.com/YOURUSERNAME/blowfish themes/blowfishThe real cost of Hugo is that there is no dashboard. If you’re not comfortable in a terminal and in Markdown, you will hate this, and WordPress is the correct answer for you.
GitHub Pages and Cloudflare
Source in a private repo, output in a public one:
- Push the Hugo project to the private repo
- Enable GitHub Pages on the public repo — branch
gh-pages, folder/ - In Cloudflare, add a CNAME for
www.yourdomain.com→yourusername.github.io, plus A records for the GitHub Pages IPs if you need the apex - Add a
CNAMEfile to the repo:
merox.devDeploys with GitHub Actions
Edit in VS Code, push to the private repo, Actions builds and pushes the output to the public one. Crossing the repo boundary needs a deploy key — the default GITHUB_TOKEN can’t write to a different repository.
Generate the pair:
ssh-keygen -t rsa -b 4096 -C "github-deploy" -f deploy_key -N ""The public half goes on the public repo, under Settings → Deploy Keys, with write access ticked. The private half goes on the private repo, under Settings → Secrets, as PRIVATE_KEY. Getting these two backwards is the usual reason the first run fails.
name: github pages
on: push: branches: - master
permissions: contents: write id-token: write
jobs: deploy: runs-on: ubuntu-22.04 steps:14 collapsed lines
- uses: actions/checkout@v4 with: submodules: true fetch-depth: 0
- name: Setup Hugo uses: peaceiris/actions-hugo@v3 with: hugo-version: 'latest' extended: true
- name: Build run: hugo --minify
- name: Deploy uses: peaceiris/actions-gh-pages@v3 with: deploy_key: ${{ secrets.PRIVATE_KEY }} external_repository: meroxdotdev/merox.dev publish_branch: gh-pages publish_dir: ./publicsubmodules: true matters — without it the theme isn’t checked out and the build fails on a missing layout rather than on anything that mentions submodules.


What it scored
No SEO configuration beyond what the theme ships with.


Measured with freetools.seobility.net and seositecheckup.com.
Six months in, the maintenance list was empty. No plugin updates, no PHP version to chase, nothing listening that could be broken into — the whole site is files on a CDN, and the only thing that can go wrong is a build I pushed myself.