<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://mustafaturansaglam.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://mustafaturansaglam.com/" rel="alternate" type="text/html" /><updated>2026-09-16T10:39:33+00:00</updated><id>https://mustafaturansaglam.com/feed.xml</id><title type="html">Mustafa Turan Sağlam</title><subtitle>Research Assistant &amp; PhD Student in Astronomy and Space Sciences at Erciyes University</subtitle><author><name>Mustafa Turan Sağlam</name><email>mustafaturansaglam@gmail.com</email></author><entry><title type="html">How I Built This Academic Website with Jekyll, GitHub Pages and a Custom Domain</title><link href="https://mustafaturansaglam.com/posts/2026/09/building-this-academic-website/" rel="alternate" type="text/html" title="How I Built This Academic Website with Jekyll, GitHub Pages and a Custom Domain" /><published>2026-09-15T00:00:00+00:00</published><updated>2026-09-15T00:00:00+00:00</updated><id>https://mustafaturansaglam.com/posts/2026/09/building-this-academic-website</id><content type="html" xml:base="https://mustafaturansaglam.com/posts/2026/09/building-this-academic-website/"><![CDATA[<p>This site runs on <a href="https://github.com/academicpages/academicpages.github.io">AcademicPages</a>, a Jekyll template built for researchers, hosted for free on GitHub Pages and served from my own domain. Setting it up took an afternoon of work and one long wait for DNS to propagate. Since a lot of colleagues in astronomy ask me how to put together a personal academic page without paying for hosting or learning a CMS, I am writing down exactly what I did, including the parts that went wrong.</p>

<h2 id="why-this-stack">Why this stack</h2>

<p>An academic homepage has modest requirements: a publication list, a CV, talks, teaching, and somewhere to write. It needs to survive for years without maintenance, load quickly from anywhere, and cost nothing to keep online. A static site generator fits that shape well. Jekyll turns a folder of Markdown files into plain HTML, GitHub Pages builds and serves it automatically on every push, and the whole site lives in a Git repository, which means it is versioned, backed up, and easy to move somewhere else if GitHub ever stops being a good host. There is no database to migrate and no plugin to update.</p>

<p>AcademicPages goes one step further than a generic Jekyll theme. It ships with collections that match how academics actually organise their work — <code class="language-plaintext highlighter-rouge">_publications</code>, <code class="language-plaintext highlighter-rouge">_talks</code>, <code class="language-plaintext highlighter-rouge">_teaching</code>, <code class="language-plaintext highlighter-rouge">_portfolio</code> — so a new paper is a new Markdown file rather than a layout problem.</p>

<h2 id="getting-the-site-online">Getting the site online</h2>

<p>The starting point is forking the AcademicPages repository and renaming the fork to <code class="language-plaintext highlighter-rouge">username.github.io</code>. GitHub treats a repository with that exact name as a user site and publishes it at <code class="language-plaintext highlighter-rouge">https://username.github.io</code> automatically, with no configuration beyond choosing the branch under Settings → Pages. Mine deploys from <code class="language-plaintext highlighter-rouge">main</code> at the root of the repository.</p>

<p>Almost everything identifying the site lives in <code class="language-plaintext highlighter-rouge">_config.yml</code>: the site title, the author block that feeds the sidebar (name, position, institution, location, and every profile link), and the <code class="language-plaintext highlighter-rouge">url</code> field, which matters more than it looks — I will come back to it. The navigation bar is a separate file, <code class="language-plaintext highlighter-rouge">_data/navigation.yml</code>, where each entry is a title and a URL. Deleting an entry removes it from the header without deleting the page itself, which is convenient for pages you want to keep but not advertise. I removed the template’s built-in Markdown guide page this way.</p>

<p>Content is Markdown with YAML front matter. A publication is a file in <code class="language-plaintext highlighter-rouge">_publications</code> with fields for the venue, date, citation and PDF link; a blog post is a file in <code class="language-plaintext highlighter-rouge">_posts</code> named <code class="language-plaintext highlighter-rouge">YYYY-MM-DD-slug.md</code>. The template ships with sample posts and sample publications, and clearing those out is the first real editing task — leaving “Blog Post number 1” online is the clearest sign of a site nobody has touched.</p>

<p>To preview changes before pushing, run the site locally:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>bundle <span class="nb">install
</span>bundle <span class="nb">exec </span>jekyll serve <span class="nt">--livereload</span>
</code></pre></div></div>

<p>It builds into <code class="language-plaintext highlighter-rouge">_site</code> and serves at <code class="language-plaintext highlighter-rouge">http://localhost:4000</code>. GitHub runs the same build after every push, so if it works locally it will almost certainly work in production.</p>

<h2 id="pointing-a-custom-domain-at-github-pages">Pointing a custom domain at GitHub Pages</h2>

<p>I registered <code class="language-plaintext highlighter-rouge">mustafaturansaglam.com</code> through a Turkish registrar and wanted it to serve the GitHub Pages site directly, not through a redirect. This is where most of the time went, so here is the configuration that works.</p>

<p>For an apex domain (the bare <code class="language-plaintext highlighter-rouge">example.com</code>, with no subdomain), GitHub requires four A records pointing at their servers:</p>

<table>
  <thead>
    <tr>
      <th>Type</th>
      <th>Name</th>
      <th>Value</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>A</td>
      <td>@</td>
      <td>185.199.108.153</td>
    </tr>
    <tr>
      <td>A</td>
      <td>@</td>
      <td>185.199.109.153</td>
    </tr>
    <tr>
      <td>A</td>
      <td>@</td>
      <td>185.199.110.153</td>
    </tr>
    <tr>
      <td>A</td>
      <td>@</td>
      <td>185.199.111.153</td>
    </tr>
    <tr>
      <td>CNAME</td>
      <td>www</td>
      <td>username.github.io</td>
    </tr>
  </tbody>
</table>

<p>All four A records are needed; they are separate load-balanced endpoints, not alternatives. The <code class="language-plaintext highlighter-rouge">www</code> entry is a CNAME rather than an A record, and it can point either at your GitHub Pages subdomain or at the apex domain — GitHub accepts both, and it exists so that visitors who type <code class="language-plaintext highlighter-rouge">www.</code> in front of the address are not met with an error.</p>

<p>On the GitHub side, the domain goes into Settings → Pages → Custom domain. Saving it writes a file called <code class="language-plaintext highlighter-rouge">CNAME</code> at the root of the repository containing the domain name. That file is part of the site: if a later commit deletes it, the custom domain silently detaches, so it should be left alone. GitHub then runs a DNS check, and once that passes, <strong>Enforce HTTPS</strong> becomes available. It issues a Let’s Encrypt certificate automatically, which usually takes a few minutes after the DNS check succeeds.</p>

<h3 id="what-went-wrong">What went wrong</h3>

<p>Three things, all of them mundane, and all of them worth knowing about because they produce error messages that point in the wrong direction.</p>

<p><strong>A typo in one IP address.</strong> I entered <code class="language-plaintext highlighter-rouge">195.199.111.153</code> instead of <code class="language-plaintext highlighter-rouge">185.199.111.153</code>. Three records were correct and one was not, so the site sometimes loaded and sometimes did not, depending on which endpoint the resolver picked. Worth checking each digit rather than trusting a glance.</p>

<p><strong>Too many CNAME records.</strong> My registrar had pre-populated CNAME entries for <code class="language-plaintext highlighter-rouge">mail</code> and <code class="language-plaintext highlighter-rouge">ftp</code> alongside the one I added. GitHub’s DNS check rejected the configuration outright. Removing the records I was not using resolved it. A domain used only for a static site does not need mail or FTP entries.</p>

<p><strong>Impatience with propagation.</strong> For several hours, <code class="language-plaintext highlighter-rouge">nslookup mustafaturansaglam.com 8.8.8.8</code> returned <code class="language-plaintext highlighter-rouge">SERVFAIL</code>, and GitHub reported the DNS check as unsuccessful. Nothing was wrong; the records simply had not propagated. DNS changes can take up to 48 hours, and a record’s TTL — 14400 seconds, four hours, in my case — is a lower bound on how long stale answers keep circulating. The check I kept running was:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nslookup mustafaturansaglam.com 8.8.8.8
</code></pre></div></div>

<p>Once it returns the four GitHub IP addresses instead of <code class="language-plaintext highlighter-rouge">SERVFAIL</code>, the configuration is live and GitHub’s check will pass on the next attempt. <a href="https://www.whatsmydns.net/">whatsmydns.net</a> is useful for the same question from multiple locations at once, since propagation is uneven across resolvers.</p>

<h3 id="one-subtle-mistake-worth-avoiding">One subtle mistake worth avoiding</h3>

<p>After the domain was working, the theme’s JavaScript stopped running: the light/dark toggle did nothing and the mobile menu would not open. The cause was in <code class="language-plaintext highlighter-rouge">_config.yml</code>, where <code class="language-plaintext highlighter-rouge">url</code> was still set to the old <code class="language-plaintext highlighter-rouge">https://username.github.io</code>. Jekyll uses that value to build absolute paths for assets, so the browser was loading the site from one origin and its JavaScript module from another. Modules are subject to CORS, the request was blocked, and the console showed:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Access to script at 'https://username.github.io/assets/js/main.min.js'
from origin 'https://example.com' has been blocked by CORS policy
</code></pre></div></div>

<p>Updating <code class="language-plaintext highlighter-rouge">url</code> to the custom domain fixed it. If something on a Jekyll site breaks immediately after moving to a custom domain, that field is the first place to look — and the browser console will usually name the problem outright.</p>

<h2 id="what-it-costs">What it costs</h2>

<p>The domain is the only recurring expense, roughly the price of a coffee per month depending on the TLD. GitHub Pages is free for public repositories, includes the TLS certificate, and has been reliable enough that I have not thought about uptime since launch. For a personal academic site, that is a reasonable trade: a small annual fee for an address you own and can point anywhere later.</p>

<p>If you are building something similar and get stuck, the two places worth checking first are GitHub’s own <a href="https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-github-pages-site">custom domain documentation</a> and your registrar’s DNS panel — in my experience the problem is almost always a record that is subtly wrong rather than anything to do with Jekyll.</p>]]></content><author><name>Mustafa Turan Sağlam</name><email>mustafaturansaglam@gmail.com</email></author><category term="jekyll" /><category term="github-pages" /><category term="academic-website" /><category term="dns" /><summary type="html"><![CDATA[This site runs on AcademicPages, a Jekyll template built for researchers, hosted for free on GitHub Pages and served from my own domain. Setting it up took an afternoon of work and one long wait for DNS to propagate. Since a lot of colleagues in astronomy ask me how to put together a personal academic page without paying for hosting or learning a CMS, I am writing down exactly what I did, including the parts that went wrong.]]></summary></entry></feed>