It begins - blog hosting and design decisions
Everyone has their traditions.
As a developer, I start all my projects with a “Hello world”, that’s why the first post is so small. As a person, as jdgomez, all my projects continue with “It begins (don’t cry)”, so here is the second entry of the blog.
Context
As many people I bought a Raspberry Pi long ago, and I discovered how good it was at storing dust. Recently I remembered why I bought it (yes, to host my own blog), why I became a developer and I decided to push that project as a way to learn what AI can do for me.
- Goal: Personal Blog self-hosted on a Raspberry Pi
- Stack: Hugo (static site generator in Go) + Nginx (web server)
- Agentic Coding tool: Claude Code
Why the stack
“No. I mean, I’m not a shop boy. I was just working in a shop.” - Tristan Thorn 1
I started learning how to code with C++ and you can be sure I miss it so much. Right now I am focused on learning Go and Python. So my first decision was to code my own web server. It would be created in Go, and it would serve as a great exercise.
Luckily for me, one of my current goals is to learn more about AI, and I checked my plan with Claude Code and… that wheel was already invented.
Disclaimer: I really love to reinvent wheels (maybe a topic for another entry).
Hugo is a really fast and small framework for building websites. It’s written in Go, and can generate HTML from Markdown files. I like Markdown as a standard for documentation and clean files, I don’t want to bother with HTML or CSS. I usually don’t like to use software in alpha versions and Hugo is in v0.161.1 right now. But this project is also about learning, and checking the Hugo GitHub page I discovered an active community with solid pipelines, so I am going to give it a try.
Nginx was a hard choice for me, because I have always been an ‘Apache boy’, but again, I am open to learn, so I asked Claude Code to do a deep research on performance. I usually over-engineer performance in my own code when the project constraints allow it, and I am a curious person, so why not check some data before choosing.
Here is the result:
Nginx vs Apache — Performance Benchmarks
RAM Usage
| Scenario | Nginx | Apache (Event MPM) |
|---|---|---|
| Idle | ~50–100 MB | ~60 MB |
| 100 concurrent connections | ~15–20 MB | ~40–60 MB |
| 1,000 concurrent connections | ~25–35 MB | ~150–250 MB |
| 10,000 concurrent connections | ~50–100 MB | ~2–5 GB |
At idle, both servers are roughly equivalent. The gap grows dramatically under load: at 10,000 concurrent connections, Nginx uses 20–100x less RAM than Apache.
Why: Nginx stores ~2–5 KB per connection (just a file descriptor and minimal state). Apache allocates ~14–20 MB per process or thread.
CPU Usage
- Nginx: ~120,000 req/s serving static files (modern x86 server)
- Apache: ~70,000 req/s — 1.7x lower throughput
- At 512 concurrent connections: Nginx 28,400 req/s vs Apache 15,200 req/s
Why: Apache generates thousands of context switches (one process or thread per request). Nginx uses a non-blocking event loop — a single worker handles 10,000+ simultaneous connections with no context switch overhead.
Disk Space
| Nginx | Apache | |
|---|---|---|
| Binary | ~1–6 MB (ARM: ~1.3 MB) | ~10 MB |
| Full installation | ~10–20 MB | ~50–100 MB |
Apache ships with a dynamic module directory (separate .so files), multiple configuration files, and per-directory .htaccess support. Nginx is more monolithic — modules compile into the binary, keeping the footprint small.
Raspberry Pi (ARM) — Real Hardware Numbers
Benchmark run directly on a Raspberry Pi:
- Nginx: 1,067 req/s
- Apache: 9 req/s
When Apache is configured with Event MPM and PHP-FPM (replacing mod_php), the gap narrows significantly (~108–109 req/s each). However, Nginx still wins on resource consumption across the board.
Conclusion: For serving static content (Hugo-generated sites), Nginx is the right choice on resource-constrained hardware like my Raspberry Pi.
For the domain I chose to drop all my current domains and trademarks, as they were intended for other purposes.
This is a personal blog, and I am a developer. It’s time to buy jdgomez.dev
I purchased it on Cloudflare because it’s cheap and can easily provide me with HTTPS and has an out-of-the-box tunnel to handle my dynamic address. My ISP offers a static IP option — that’s what I considered first — but at ~€144/year it makes no sense for a personal blog.
Steps taken
Usually I will post also the commands to achieve the result I am claiming, cause this is a blog about processes (mental and technical), not about goals.
Re-reading the article before publishing it, I realiced that the steps broke the flow and them don’t provide useful information (there are quite simple), but at the same time I don’t want to remove it, I am developer after all.
The solution is to hide them, check on it if you are interested.
Steps & commands
- Installed Hugo and Nginx via apt:
- Hugo v0.131.0 extended (arm64)
- Nginx 1.26.3
- Created Hugo site in
/home/pi/blog/withhugo new site blog - Configured
hugo.toml(baseURL, language, title) - Created minimal layout in
layouts/index.html(no external theme) with Hello World - Built the site with
hugo→ output in/home/pi/blog/public/ - Configured Nginx to serve
/home/pi/blog/public/on port 80 - Disabled the default Nginx site
- Granted execute permissions on
/home/pisowww-datacan read the directory - Verified access from local network → “Hello World”
Relevant file structure
/home/pi/blog/
├── hugo.toml ← site configuration
├── layouts/
│ └── index.html ← home layout (no external theme)
└── public/ ← Hugo build output (served by Nginx)
└── index.html
/etc/nginx/sites-available/blog ← Nginx config
/etc/nginx/sites-enabled/blog ← active symlink
Final considerations
Although I am Spanish, the master language for the blog should be English, “the developer’s language”, and include my native language as a secondary option. I am currently learning German, but it’s too early for that. I will want to add it when the time comes to put it into practice, but I don’t want to do automatic translations. I am who I am, and this includes my language.
Finally, I always liked Uncle Bob’s blog, clear and simple.
So I chose to have a minimal custom theme, created from scratch by Claude Code, with clear instructions:
“I am a developer that hates cookies, my eyes prefer dark themes.”
This was its solution:
- Background black (#0d0d0d), text green (#00ff88) — terminal aesthetic, easy on the eyes
- Monospace font (Courier New, system fallback)
- Blinking cursor in the header — pure CSS animation, no JavaScript
- Terminal-style header:
~/jdgomez blog $+ cursor - Zero cookies, zero JavaScript, zero external resources — no Google Fonts, no analytics, no third-party anything
I couldn’t love it more.
The end
That’s all. That’s how all this begins. In the future I plan to add better time metrics on how much time it cost me to complete these little projects, including the article writing, but I didn’t properly measure it this time, so let’s consider it an improvement for next articles.
Hope you enjoyed this.
Thanks for reading.