Having a space of my own away from social media, away from algorithms was something I’d wanted for a long time. A little corner to write about what I love, in my own way, without rushing. And that’s how my blog was born. π
In this post, I’m sharing how I went from idea to live site from choosing the stack all the way to deploying it.
The stack I chose
I went with Pelican, a static site generator written in Python. It won me over for a few reasons:
- It’s built with Python π
- It generates pure HTML (lightweight, fast, and easy to host)
- Meaning: nothing is processed dynamically on the server. That makes the site faster, more secure, and cheaper/easier to host (like on GitHub Pages, which only serves static files).
- The structure is simple to customize
- Posts are written in Markdown π
- The documentation… is a bit confusing, but I pushed through anyway π
I also used uv as my package and virtual environment manager it’s fast, practical, and has replaced my old manual venv + pip workflow.
π οΈ Step by step
1. Setting up the environment and installing Pelican
I used uv to create my virtual environment:
uv venv
Then I activated it manually:
source .venv/bin/activate
uv venv creates the environment with isolation, but doesn’t activate it automatically. I did it out of habit it’s the traditional way most of us learned with venv.
That said, uv also offers a more modern (and practical!) way to handle virtual environments. You can skip uv venv and source entirely and just let uv manage everything:
uv add pelican[markdown] # declares `pelican` as a project dependency
uv run pelican-quickstart # runs `pelican-quickstart` inside the automatically managed virtual environment
This way, uv creates the environment and runs commands inside it automatically no manual activation needed.
One note: if you prefer using uv add ... and uv run ..., you’d need to update the Makefile, replacing PELICAN=pelican with PELICAN=uv run pelican or all make <rule> calls would need to become PELICAN="uv run pelican" make <rule>.
2. Project structure
I followed the setup prompts and had a basic structure ready in no time. From there, I organized the repo with a clear focus:
content/β where the Markdown posts liveoutput/β the generated HTML sitetheme/β theme files and customizations
The repository is available here: github.com/aninhasalesp/meublog
I created the pelican-themes/ folder manually to clone the theme and make my own modifications.
3. Choosing and customizing the theme π¨
I used the notmyidea-cms theme that comes with Pelican and customized it little by little.
In pelicanconf.py:
THEME = "pelican-themes/notmyidea-cms"
The changes I made:
- Footer with my name and a link to my GitHub β€οΈ
- Comments with Utterances
- Share buttons (LinkedIn, WhatsApp and Telegram)
- CSS tweaks for spacing, layout, and colors
4. Comments with Utterances π¬
I used Utterances to enable comments on posts. It’s lightweight, uses GitHub issues, and it’s simple and efficient:
<div id="comments">
<script src="https://utteranc.es/client.js"
repo="aninhasalesp/meublog"
issue-term="pathname"
theme="github-light"
crossorigin="anonymous"
async>
</script>
</div>
5. Writing posts βοΈ
Posts live in content/ and are written like this:
Title: First post
Date: 2025-07-20
Category: personal
Summary: A short welcome text for the blog.
---
This is the first post! π
6. Theme customizations
I edited files inside pelican-themes/notmyidea-cms/ to give the blog more of its own identity.
In CSS:
- Adjusted padding and margins
- Better alignment of elements
- Added icons and visual links
In HTML (like base.html):
- Added the footer
- Positioned the share buttons
π‘ Editing the theme directly worked well for me, even if it’s not the ideal long-term approach.
7. Generating the static files
To compile the blog and generate the HTML:
make html
During development, I used the local server to preview changes:
pelican --listen
8. Deploy to GitHub Pages π
I used GitHub Pages to host the blog. The process was:
- Generated the files with
pelican contentormake html - Pushed the
output/folder to thegh-pagesbranch - Set up the custom domain on GitHub and pointed the DNS to GitHub’s servers
The Makefile made things easier, I published with:
make github
This command handles the whole thing. Here’s roughly what it does:
cd output
git checkout -b gh-pages
git add .
git commit -m "Deploy"
git push -f origin gh-pages
On GitHub, I went to Settings > Pages and:
- Configured it to serve the site from the
gh-pagesbranch, root folder (/) - Added a CNAME file with my custom domain (
anapaula.org) - Pointed the DNS from my registrar to GitHub Pages
- Enabled HTTPS
You can automate this with GitHub Actions too. But since this is a personal blog I don’t update every day, I preferred the manual approach.
9. Custom domain π
I registered the anapaula.org domain and configured it for the blog hosted on GitHub Pages.
What I did: In the registrar’s panel, I added the following DNS records:
A records (IPv4): pointing to GitHub Pages’ IPs:
185.199.108.153
185.199.109.153
185.199.110.153
185.199.111.153
- CNAME (if you want a subdomain): pointing to
youraccount.github.io
Inside the output/ folder (which goes to the gh-pages branch), I created a CNAME file with just:
anapaula.org
This tells GitHub which domain to link to your site. This file is included automatically in every deploy when I run make github.
On GitHub, under Settings > Pages:
- I checked “Use a custom domain” and entered
anapaula.org - Enabled HTTPS for secure browsing
I followed the official GitHub Pages documentation for all of this: π GitHub Pages docs
Wrapping up
The process had its bumps (Pelican’s docs could really use some love π ), but it was totally worth it. Having a space of my own with my name, my style was a long-time wish that finally became real.
If you’re also thinking about starting a blog, whether technical or personal, I really recommend it! And if I can help in any way, just reach out. π
The blog’s source code is on GitHub: aninhasalesp/meublog π±