This blog had been silent since 2017.
Not just the content. The entire infrastructure underneath was dead. Ruby 2.3, end-of-life since March 2019. Jekyll 2.x, unsupported. Compass for CSS compilation, a project that stopped in 2016. The GitLab CI pipeline was failing silently on every push.
Nobody noticed because nobody was pushing.
The Autopsy
The CI used ruby:2.3 from Docker Hub. That image still exists, frozen in time, based on Debian Stretch.
Debian Stretch’s package repositories have been archived. Every apt-get update returns 404. The image cannot install anything. Not even locales.
1 2 3 | |
That was the end of Ruby 2.3.
The Fix: Minimum Viable Migration
The goal was not to modernize everything. The goal was to make it build again.
ruby:2.7 on Debian Bullseye. Repositories work. The image is stable.
Three things broke when moving from 2.3 to 2.7.
Bundler. The default bundler now requires Ruby 3.2+. Pinning to 2.4.22 solves it:
1
| |
FFI. The ffi gem versions above 1.17 require Ruby 3.0+. Pinning to ~> 1.16.3 in the Gemfile prevents bundler from pulling an incompatible version.
Pygments. The pygments.rb gem (version 0.6.3) uses a Python IPC protocol to communicate with the Pygments syntax highlighter. That protocol is broken with Python 3.
The fix: replace it entirely with Rouge, a syntax highlighter written in pure Ruby. No Python dependency. No IPC. The plugin pygments_code.rb was rewritten to call Rouge’s API:
1 2 3 4 5 | |
No posts needed changes. The same codeblock Liquid tag works exactly as before.
Local Development: Easier Than Expected
The assumption was that Ruby 2.7 would only work inside Docker due to native extension compilation (ffi, rdiscount, RedCloth).
Wrong.
With mise on Arch Linux:
1 2 3 4 | |
Every native gem compiled without issues. bundle exec rake preview serves the site at localhost:4000. No Docker required for local development.
Cleaning Up the Dead Weight
With the build working, the next step was removing everything that had died while the blog was sleeping.
Dead integrations removed: - Google+ sidebar widget and +1 button — service shut down April 2019 - Google Analytics (Universal Analytics) — retired July 2024, collecting zero data - Facebook Like button — privacy-invasive, removed - Twitter sidebar widget — removed from default sidebar
Dead code identified but left alone:
- Flash/SWFObject in octopress.js — inert, no browsers use Flash
- Modernizr 2.0 — feature detection for browsers that no longer exist
- jQuery 1.9.1 — still used by the nav, not worth removing without a rewrite
Posts hidden: five low-value posts (test posts, reposts, dated content) set to published: false. Not deleted — just invisible.
Frontend: Small Changes, Visible Impact
The Octopress 2 default theme is from 2012. A full redesign was out of scope. But a few CSS-only changes made a noticeable difference.
Typography. The font stack was broken — Sass was treating the entire heading font declaration as a single quoted string. Browsers never matched it. Fixed to use proper PT Sans / PT Serif stacks with correct Google Fonts loading over HTTPS.
Text width. The content column had no max-width constraint. On wide screens, text lines stretched far beyond comfortable reading length. A single max-width: 38em on .entry-content fixed it.
Background. The original tiling PNG texture was replaced with a solid color. The nav bar now sits on a clean dark background instead of a noisy image.
Blockquotes. Added subtle background color and proper padding for a more modern feel.
Open Graph and Social Sharing
The site had no Open Graph or Twitter Card meta tags. Every shared link appeared as a plain URL with no preview.
Added to the <head> template:
- og:title, og:description, og:image, og:type, og:url
- twitter:card, twitter:title, twitter:description, twitter:image
These are now populated automatically from each post’s front matter. Posts with an image field get summary_large_image cards. Posts without get a basic summary card.
What Remains
The stack is still far from modern. Jekyll 2 and Octopress are dead projects. Compass generates vendor prefixes that no browser has needed in years. The JavaScript loads jQuery 1.9.1 and Modernizr 2.0 on every page.
The Compass dependency is the main blocker for a Jekyll 4 migration. Every Sass file uses Compass-specific mixins and asset helpers that do not exist in standard Sass. Replacing them is a multi-day effort.
But the site builds. The CI passes. Posts render. The content is readable.
Sometimes resurrecting something old is faster than rewriting from scratch.
The next step is deciding whether to invest in a full Jekyll 4 migration or accept that this Octopress shell, despite its age, still works well enough to publish what matters.
For now, it publishes. That is enough.