<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/"><channel><docs>https://blogs.law.harvard.edu/tech/rss</docs><title>Github on tkalp.dev</title><link>https://tkalp.dev/tags/github/</link><description>Recent content in Github on tkalp.dev</description><image><title>Github on tkalp.dev</title><link>https://tkalp.dev/tags/github/</link><url>https://source.unsplash.com/collection/983219/2000x1322</url></image><ttl>1440</ttl><generator>After Dark 10.1.0 (Hugo 0.163.1)</generator><language>en-US</language><copyright>Copyright &copy; blacksamsays. Licensed under CC-BY-ND-4.0.</copyright><lastBuildDate>Thu, 06 Aug 2026 12:39:48 UT</lastBuildDate><atom:link href="https://tkalp.dev/tags/github/index.xml" rel="self" type="application/rss+xml"/><item><title>A Cost-Effective Personal Blog with Hugo, GitHub, and Cloudflare Pages</title><link>https://tkalp.dev/post/cost-effective-personal-blog-hugo-github-cloudflare-pages/</link><pubDate>Thu, 06 Aug 2026 00:00:00 UT</pubDate><guid>https://tkalp.dev/post/cost-effective-personal-blog-hugo-github-cloudflare-pages/</guid><description>A personal blog does not need a database, a virtual server, or another monthly subscription. If the site is mostly articles, images, and a few static pages, a static-site stack can be simpler, faster, and almost free to run.
This setup uses Hugo to build the site, GitHub to store its source, and Cloudflare Pages to publish it. The only recurring cost is usually the domain renewal.</description><category domain="https://tkalp.dev/categories/tech">Tech</category><content:encoded><![CDATA[A personal blog does not need a database, a virtual server, or another monthly subscription. If the site is mostly articles, images, and a few static pages, a static-site stack can be simpler, faster, and almost free to run.
This setup uses Hugo to build the site, GitHub to store its source, and Cloudflare Pages to publish it. The only recurring cost is usually the domain renewal.
The short version: write a post, push it to GitHub, and Cloudflare automatically publishes it. Why a static blog? Traditional publishing platforms often bundle together a web server, database, admin panel, plugins, updates, and backups. That makes sense for a dynamic site, but it is a lot of machinery for a personal blog.
Hugo takes a different approach. It converts Markdown files into plain HTML, CSS, JavaScript, and images. The deployed site does not need a database or application server. There is less to maintain, and static files are easy to cache around the world.
The result is pleasantly boring:
no server operating system to patch no database to back up no WordPress plugins to babysit no idle virtual machine running all month very little attack surface fast page loads almost everywhere The stack Hugo Hugo is the site generator. Posts live as Markdown files in a Git repository, usually in a structure like this:
content/ post/ first-post/ index.md images/ cover.jpg A basic site configuration might include:
baseurl = &#34;https://tkalp.dev/&#34; languageCode = &#34;en-US&#34; title = &#34;tkalp.dev&#34; theme = [&#34;your-theme&#34;] enableRobotsTXT = true The baseurl value matters more than it first appears. Hugo uses it for canonical URLs, feeds, sitemaps, and other generated links. It should match the final HTTPS domain, including the trailing slash.
GitHub GitHub is the source of truth. It stores the Hugo configuration, theme, posts, and images while giving every change a useful history.
A normal publishing workflow is simply:
git add . git commit -m &#34;post: add a new article&#34; git push origin main There is no need to upload the generated public directory manually. Cloudflare can build it directly from the source repository.
Cloudflare Pages Cloudflare Pages connects to the GitHub repository. Every push to the production branch starts a build and, if it succeeds, publishes the result to Cloudflare&rsquo;s global network.
For this Hugo project, the important build settings are:
Production branch: main Build command: hugo --gc --minify --baseURL https://tkalp.dev/ Build output directory: public Environment variable: HUGO_VERSION=0.163.1 Pinning the Hugo version is a small but worthwhile detail. It prevents an unexpected generator update from changing the build or breaking an older theme. Cloudflare&rsquo;s official Hugo deployment guide covers the repository connection and build settings.
Connect the custom domain Cloudflare Pages provides a temporary project.pages.dev address, but a personal domain makes the site easier to remember and gives it a permanent identity.
In the Pages project:
Open Custom domains. Add the apex domain, such as tkalp.dev. Add www.tkalp.dev if it should also work. Wait for the DNS record and TLS certificate to become active. When the domain is already managed by Cloudflare, most of this is automatic. DNS and SSL do not require separate paid products.
Choose one canonical hostname, then redirect the other public versions to it:
www.tkalp.dev/* → https://tkalp.dev/:splat project.pages.dev/* → https://tkalp.dev/:splat Cloudflare&rsquo;s Bulk Redirects can preserve the path suffix and query string. A request for:
https://www.tkalp.dev/post/hello/?source=rss then lands on:
https://tkalp.dev/post/hello/?source=rss That avoids duplicate versions of the same page and keeps shared links predictable.
What publishing looks like Once Git integration is enabled, publishing becomes almost uneventful:
Write or edit a Markdown post. Preview it locally with hugo server. Commit the change. Push to main. Cloudflare installs the pinned Hugo version. It runs the build command. The contents of public are deployed automatically. A useful local check is:
hugo --gc --minify If that command works locally, the Cloudflare build will usually behave the same way. The Pages dashboard keeps build logs and previous deployments, so a broken release is easy to diagnose or roll back.
The actual cost For a purely static personal blog, the running cost can be close to zero.
Component Typical cost Hugo Free and open source GitHub repository Free for this use case Cloudflare Pages static hosting Free DNS and SSL Free Bulk Redirects Included in the Free plan Custom domain Annual registration and renewal Cloudflare&rsquo;s Free plan currently includes up to 500 builds per month, far more than a personal blog normally needs. Purely static asset requests are free and unlimited; Pages Functions instead count toward Workers quotas.
There is also no surprise compute bill because this setup does not need Pages Functions, Workers, R2, image transformations, or a database. Those products can be useful later, but they are not required for a straightforward blog.
A few SEO basics Static generation handles much of the plumbing, but it is worth checking the output before calling the site finished:
every page has a self-referencing canonical URL robots.txt allows normal crawling sitemap.xml contains the final domain RSS links use the final domain internal navigation uses the canonical hostname the www and pages.dev versions redirect to the canonical domain After launch, add the domain to Google Search Console and submit:
https://tkalp.dev/sitemap.xml Search Console is useful for spotting indexing errors, checking search queries, and confirming that Google can crawl the site.
Small gotchas worth avoiding Building with the wrong Hugo version Themes sometimes rely on a particular Hugo release. Pin HUGO_VERSION in Cloudflare rather than relying on whichever version happens to be the default.
Forgetting the production base URL A site can look fine while quietly generating canonical links and feeds for the wrong hostname. Set the domain in config.toml and include it in the Cloudflare build command.
Publishing generated files to Git The public and resources directories are build output. In most setups they should be ignored by Git and rebuilt on every deployment.
Adding dynamic features too early Comments, forms, server-side search, and analytics can introduce third-party services or dynamic compute. Add them only when they solve a real problem. A client-side search index is often enough for a small blog.
Forgetting the non-canonical domains The apex domain, www, and default pages.dev URL may all serve the same content unless redirects are configured. Pick one public address and redirect everything else to it.
Final thoughts This stack is a good fit for anyone who wants to own their content without turning a blog into a small infrastructure project.
Hugo keeps the content portable. GitHub provides version history. Cloudflare Pages handles builds, TLS, caching, and global delivery. The workflow stays simple: Markdown in, static files out.
Most importantly, it stays cheap. There is no server waiting for traffic and no monthly hosting plan to justify. For a straightforward personal blog, the domain renewal can genuinely be the only recurring bill.
Sources Hugo documentation Cloudflare Pages: deploy a Hugo site Cloudflare Pages limits Cloudflare Pages Functions routing and static asset requests Cloudflare Bulk Redirects ]]></content:encoded></item></channel></rss>