Saturday, 5 September 2026
Will node/npm be able to server our personal blogs/sites in 2046?
As usual, folks were discussing options for personal blogs, and many were recommending plain ole HTML/CSS. I put in my bid for Static Site Generators.
Then someone said that they would stay away from anything node/npm/JS, because the ecosystem seems chaotic and they weren't sure where it would be in 20 years. Upon further probing, this person generalized their thoughts behind a "all code is ephmeral"/bitrot type assertion
I wondered if we could test this hypothesis somehow. What did people use forblogging in 2006? Apparently something called blojsom (spoiler: you might notice that's what we're running on here) which was even included in Mac OS X "Tiger" Server at some point. The choice of framework/platform might leave us a little bit biased, because Java is well known for its backward compatability gymnastics. Yes, I used vibe coding/Claude for this. Sue me, just sue me already. I figured it was perfect because it could simulate being someone with Java knowledge. And also, why would I want to actually spend a weekend trying to get a 20 year old blogging software to work? Anyways, spoiler alert again, it worked. Claude solved it in 25 minutes, built a Docker container with outdated versions of JDK and Tomcat, and deployed to Railway. This is the prompt:
Clone blojsom - czarneckid/blojsom-sourceforge - and try to deploy it on a modern web host, with as few changes as possible. Document how "possible" this is, each step involved, and whether a human would be able to reasonably do it themselves as a weekend project. Prompt me for any saas hosting accounts you may need.
The document it produced is the blog post below.
Posted by at 1:25 AM in /
Deploying blojsom 2.28 (2006) on a modern host, 2026
Live instance: https://blojsom-production.up.railway.app/blojsom/blog/
Verdict up front: very possible, comfortably a weekend project, realistically an afternoon. Zero Java source changes. Zero build-file changes. Zero changes to any file the project shipped. Everything added is three new files in deploy/ plus a Dockerfile, and every "change" is either container plumbing or a value the original INSTALL instructions told you to edit by hand anyway.
Wall-clock for this run: roughly 25 minutes from git clone to a post written through the live admin UI surviving a container restart, including two dead ends noted below.
What blojsom 2.28 is, technically
- Servlet 2.3 webapp, Java source/target 1.4, built with Ant (
build.xml, no Maven, no downloads: every dependency is a jar checked intowar/WEB-INF/lib). - No database. Entries are files on disk under
blog-home; comments, trackbacks, and metadata are sibling dot-directories. Config is.propertiesfiles underWEB-INF/. - Velocity 1.4 templates, log4j 1.2.8, commons-*, xmlrpc 1.2. All pre-2006.
That profile is why this is easy: a self-contained, dependency-vendored, file-backed WAR is close to the best case for resurrecting old Java.
The steps
- Find the right tree. The GitHub repo is an SVN dump. 2.28 lives at
branches/blojsom-2_28-final/blojsom-2.0/(thetags/directory stops at 2.19; later releases are underbranches/). Trunk is 3.x, a different animal (Spring + Hibernate + SQL).
- Pick a JDK that still compiles
-source 1.4. JDK 9+ removed it (javac9 minimum is 6, current is 8). JDK 8 accepts it with warnings. So:eclipse-temurin:8-jdk.apt-get install ant,ant war. Build succeeds first try, 2 seconds, four "obsolete option" warnings. Output:distro/blojsom.war.
- Pick a servlet container that still speaks
javax.servlet. Tomcat 10+ isjakarta.*and will not load this WAR (Tomcat 10's auto-migration converter would probably work, but that is a change). Tomcat 9.0.x is still maintained and runs on JDK 8:tomcat:9.0-jdk8-temurin. Drop the WAR inwebapps/, done. Theweb.xmlis DTD-era 2.3 and Tomcat 9 accepts it without complaint.
- Give it somewhere to write.
blog.propertiesships withblog-home=/change/me/please/. On a PaaS the container filesystem is ephemeral, so this has to be a mounted volume. Railway: one volume mounted at/data,blog-home=/data/blog/.
- Tell it its own URL. blojsom builds absolute links (including the admin login form's
action) fromblog-base-url/blog-urlinblog.properties. Wrong value = admin login posts tolocalhost:8080and fails silently.deploy/entrypoint.shrewrites these at boot fromBLOJSOM_BASE_URL(falls back to Railway'sRAILWAY_PUBLIC_DOMAIN).
- Create an admin user. Two files, not one: Both are done by the entrypoint from
BLOJSOM_ADMIN_PASSWORD.authorization.properties:admin=<md5 hex>withuse-encrypted-passwords=trueanddigest-algorithm=MD5added toblog.properties(plaintext also works; the file format supports either).permissions.properties:admin=*. Without this you can log in but every admin page says "You do not have permission". The shipped file only grantsdefault=*, anddefaultis not a user in the shippedauthorization.properties.
- Listen on
$PORT. Tomcat'sserver.xmlhardcodes 8080; entrypointseds it. Railway also lets you pin the target port to 8080 on the domain, which is what I did, so this is belt-and-braces.
- Railway plumbing: project, empty service, volume at
/data, two env vars, generate a domain,railway upfrom this directory (25 MB upload; the Dockerfile is autodetected). First build+deploy about 60 seconds.
Dead ends hit
unzipis not in the Tomcat image. Usedjar xf(present, since the image has a JDK) to explode the WAR. Exploding rather than dropping the.warin was a choice: blojsom's admin plugins write back intoWEB-INF/default/*.propertiesat runtime, which only works on an exploded layout.ant wardeleteswar/WEB-INF/default/templatesafter jarring, so you cannot justCOPYthewar/directory out of the build stage; you must takedistro/blojsom.war.- Shipped
authorization.propertieshas no trailing newline. A naiveecho >> filegluesadmin=...onto the last comment line. Fixed insetprop. - The permissions file (step 6). Not mentioned anywhere obvious; found by grepping for the error string.
What does not work, or is degraded, and was left alone
- Weather plugin logs a 403 at boot: it fetches
http://www.nws.noaa.gov/data/current_obs/null.xml. Harmless, unconfigured plugin phoning a dead URL. - Ping URLs (
rpc.weblogs.com,rpc.pingomatic.com) on publish: pingomatic still exists, weblogs.com does not. Unchecked the "ping" box when posting; leaving it checked just adds a slow timeout to publishing. - Outbound email (comment notifications) points at
smtp-server=localhostinweb.xml. No SMTP in the container;blog-email-enabled=falseby default so nothing breaks. - Admin-UI edits to blog settings (name, description, plugins) land in
WEB-INF/default/*.propertiesinside the container image, not on the volume. They survive restarts but not redeploys. Posts, comments, and trackbacks are on the volume and survive both (verified by restart). Fixing this properly means pointingblojsom-configuration-base-directoryoff-WAR, which blojsom 2.x resolves relative to the servlet context, so it would be an actual change; skipped. - Security. This is 2006 code: MD5 passwords, no CSRF tokens, a comment form open to the internet, an XML-RPC endpoint (
/blojsom/xmlrpc/) and Atom API on by default, log4j 1.2.8 (not the log4shell branch, but unmaintained). Do not put anything you care about behind that admin password. Fine for a demo, not fine for a real blog without at least fronting it with something. - HTTPS. Railway terminates TLS at the edge; Tomcat sees plain HTTP. blojsom does not care because it builds URLs from
blog-base-url, which we set tohttps://.... If you ever set that tohttp://, browsers will block the mixed-content form posts.
Could a normal person do this in a weekend?
Yes, with these caveats about who "a normal person" is:
- Someone who has run Docker before and knows what a WAR is: an afternoon. The whole thing is one Dockerfile and a shell script; the only genuine research is "which JDK / which Tomcat", and both answers are one search away.
- Someone who has never touched Java: still a weekend, but a frustrating one. The failure modes (silent redirect to
localhost:8080on login, the permissions file, the templates directory being deleted after the WAR is built) produce no useful error messages. Expect to readweb.xml,blog.properties, and one Java file. - **Someone who wants to do it without Docker,** on a classic VPS: also fine, arguably closer to what the 2006 INSTALL doc assumed.
apt install openjdk-8-jdk tomcat9on Debian/Ubuntu,ant war, copy the WAR. Same config edits, done by hand.
What would push it past a weekend: wanting Tomcat 10/11 (jakarta migration), wanting a supported JDK (17/21 will run the compiled classes fine; it is only the compile step that needs 8, so you could build on 8 and run on 21 with Tomcat 9), or wanting blojsom 3.x (needs a real database and Hibernate 3.1 against a modern driver; that is where "as few changes as possible" stops being small).
Files
Dockerfile(repo dir, two-stage: JDK 8 + Ant build, Tomcat 9 + JDK 8 runtime)deploy/entrypoint.sh(env var to properties file shim; seeds an empty volume)deploy/seed-blog/general/hello-world.html(one entry so the first page is not blank)deploy/README.md(this file)
Nothing else in the tree was modified.
Run locally:
docker build -t blojsom228 . docker run -p 8080:8080 -e BLOJSOM_ADMIN_PASSWORD=changeme blojsom228 # http://localhost:8080/blojsom/blog/ admin: ?flavor=admin
Deploy (Railway, account already linked):
railway up --detach
Env vars the image understands: PORT, BLOJSOM_BASE_URL, BLOJSOM_BLOG_HOME, BLOJSOM_ADMIN_PASSWORD.
Posted by admin at 12:59 AM in general/
Friday, 4 September 2026
Posted from the 2026 admin UI
Written through blojsom 2.28's own admin console, running on Railway. If you can read this after a redeploy, the volume works.
Posted by admin at 11:57 PM in general/
Hello from 2006
This is blojsom 2.28, built from the SourceForge SVN tree with its original Ant build and running on Tomcat 9 / JDK 8 in a container. Entries are plain files in blog-home; this one is general/hello-world.html.