Setting up a personal website

published on 2025-06-28

I've wanted to set up a blog/personal website for a while, but kept putting it off. I finally took a couple hours on a weekend to figure it out, so let's kick my blog off with an overview of the setup and my thought process while making it.

Goals

I had a couple requirements in mind that shaped my decisions.

I knew about the existence of Static Website Generators, so I at least had a search term to start my research, which quickly led me to awesome-static-generators on GitHub, and from there - to 11ty. The setup looked simple enough so I went ahead and tried it out.

Setting up 11ty

Most of the documentation sounded relevant to me so I began by simply reading it front-to-back, only skipping the Using Data in Templates section as it seemed too advanced for my use-case.

Then I set up an npm project and a git repo for it and installed @11ty/eleventy.

After playing around with it, I settled on the following directory structure in my repo:

Let's explore it.

eleventy.config.mjs

This file tells 11ty about the structure of our project, imports a server-side syntax highlighting plugin, and defines a helper function - all fairly self-explanatory.

import syntaxHighlight from "@11ty/eleventy-plugin-syntaxhighlight";

export default function(eleventyConfig) {
    eleventyConfig.setInputDirectory("src");
    eleventyConfig.addPassthroughCopy("src/style.css");

    eleventyConfig.addPlugin(syntaxHighlight);

    eleventyConfig.addFilter("date", (dateObj) => dateObj.toISOString().split('T')[0]);
};

Makefile

Also fairly simple, my main reason for even having a Makefile over package.json scripts is that my upload script has more than one command.

.PHONY: all clean build upload

clean:
	rm -rf _site/

dev: clean
	npx @11ty/eleventy --serve

build: clean
	npx @11ty/eleventy

upload: build
	ssh my_vps "rm -rf personal-website/"
	scp -r _site/* my_vps:personal-website/

My VPS that hosts this website also hosts several other projects, and I added a configuration for nginx pointed at ~/personal-website/

index.md

---
layout: main_layout
title: Home
---
Hey, I'm Amit. WIP, check out my [blog](/blog)!

Here's where this gets interesting. Firstly, this is a markdown document that gets rendered as html and served as the root of the website - 11ty will also happily accept index.html or any other supported extension and render it. This is an example of a page with a front matter - metadata that 11ty or my code can use to modify how the page is rendered.

The layout property instructs 11ty to look at _includes/main_layout.html, find a liquid.js template there, and wrap its contents around the current document. The navigation bar is defined there.

style.css

I blended together some "CSS Reset" snippets, then wrote some styles for the navigation bar and some other components. It's pretty short, feel free to explore it.

main_layout.html

This file defines the skeleton of the website that wraps every other page.

<html lang="en">
  <head>
    <title>{{ title }}</title>
    <link rel="stylesheet" href="/style.css">
    {%- if code -%}
    <link href="https://unpkg.com/prismjs@1.20.0/themes/prism-tomorrow.css" rel="stylesheet" />
    {%- endif -%}
  </head>
  <body>
    <header>
      <!-- ... -->
    </header>
    <main>
      {{ content }}
    </main>
  </body>
</html>
{% comment %} vim: set ft=liquid {% endcomment %}

A couple things to note here:

post.html

This file is the template that is used for every blog post.

---
layout: main_layout
tags: post
permalink: "/blog/{{ date | date }}/{{ title | slugify }}/"
---
<h1>{{ title }}</h1>
{{ content }}

The template itself is merely appending a <h1> above the content with the title of the post, but I'm sure I'll evolve it over time.

blog/index.html

---
layout: main_layout
title: Blog
---
<h1>Blog</h1>
<ul class="posts-list">
    {%- for post in collections.post -%}
    <li class="post-link">
        <a href="{{ post.url }}">
          <span class="post-date">{{ post.data.date | date }}</span>
          <span class="post-title">{{ post.data.title }}</span>
        </a>
    </li>
    {%- endfor -%}
</ul>

Here we use the post collection to render a sitemap for the blog. By default, collections are sorted by date which is very convenient.

blog/setting-up-a-personal-website.md

And now, the culmination - I can conveniently open a new markdown file:

---
layout: post
title: Setting up a personal website
date: 2025-06-28
code: true
---

Content goes *here* :)

All I need is to select the post layout, give it a title and date, and optionally add the code variable that includes the CSS for highlighting code blocks, and the system will:

If I ever need to include raw HTML or javascript, I just use a .html file and it simply transparently works with the same front matter.

To publish my cool new blog, all I need is to commit, push, and make upload it away!