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 admin 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 into war/WEB-INF/lib).
  • No database. Entries are files on disk under blog-home; comments, trackbacks, and metadata are sibling dot-directories. Config is .properties files under WEB-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

  1. Find the right tree. The GitHub repo is an SVN dump. 2.28 lives at branches/blojsom-2_28-final/blojsom-2.0/ (the tags/ directory stops at 2.19; later releases are under branches/). Trunk is 3.x, a different animal (Spring + Hibernate + SQL).
  1. Pick a JDK that still compiles -source 1.4. JDK 9+ removed it (javac 9 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.
  1. Pick a servlet container that still speaks javax.servlet. Tomcat 10+ is jakarta.* 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 in webapps/, done. The web.xml is DTD-era 2.3 and Tomcat 9 accepts it without complaint.
  1. Give it somewhere to write. blog.properties ships with blog-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/.
  1. Tell it its own URL. blojsom builds absolute links (including the admin login form's action) from blog-base-url / blog-url in blog.properties. Wrong value = admin login posts to localhost:8080 and fails silently. deploy/entrypoint.sh rewrites these at boot from BLOJSOM_BASE_URL (falls back to Railway's RAILWAY_PUBLIC_DOMAIN).
  1. Create an admin user. Two files, not one: Both are done by the entrypoint from BLOJSOM_ADMIN_PASSWORD.
    • authorization.properties: admin=<md5 hex> with use-encrypted-passwords=true and digest-algorithm=MD5 added to blog.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 grants default=*, and default is not a user in the shipped authorization.properties.
  1. Listen on $PORT. Tomcat's server.xml hardcodes 8080; entrypoint seds 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.
  1. Railway plumbing: project, empty service, volume at /data, two env vars, generate a domain, railway up from this directory (25 MB upload; the Dockerfile is autodetected). First build+deploy about 60 seconds.

Dead ends hit

  • unzip is not in the Tomcat image. Used jar xf (present, since the image has a JDK) to explode the WAR. Exploding rather than dropping the .war in was a choice: blojsom's admin plugins write back into WEB-INF/default/*.properties at runtime, which only works on an exploded layout.
  • ant war deletes war/WEB-INF/default/templates after jarring, so you cannot just COPY the war/ directory out of the build stage; you must take distro/blojsom.war.
  • Shipped authorization.properties has no trailing newline. A naive echo >> file glues admin=... onto the last comment line. Fixed in setprop.
  • 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=localhost in web.xml. No SMTP in the container; blog-email-enabled=false by default so nothing breaks.
  • Admin-UI edits to blog settings (name, description, plugins) land in WEB-INF/default/*.properties inside 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 pointing blojsom-configuration-base-directory off-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 to https://.... If you ever set that to http://, 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:8080 on login, the permissions file, the templates directory being deleted after the WAR is built) produce no useful error messages. Expect to read web.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 tomcat9 on 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.

« September »
SunMonTueWedThuFriSat
  12345
6789101112
13141516171819
20212223242526
27282930