Skip to content

feat(posts): migrate four posts from the old blog - #6

Merged
minhtt159 merged 8 commits into
mainfrom
claude/blog-migration-homelab-8a34df
Sep 16, 2026
Merged

minhtt159 merged 8 commits into
mainfrom
claude/blog-migration-homelab-8a34df

Conversation

@minhtt159

Copy link
Copy Markdown
Owner

Adopts the surviving material from teamkhunglong.github.io, a Jekyll blog dormant since 2022, translated from Vietnamese and rewritten to this repo's conventions.

Four posts, in reading order:

Post From Note
Five dollars a month instead of an open port 2021-03-16 The homelab origin argument
Mining ETH in a homelab 2021-04-26 + 2021-09-06 Two halves of one arc, merged
The economics that make cryptojacking work 2021-07-25 The abuse case
Merklision 2020-10-24 SVATTT CTF writeup

Each opens with an archive note giving its original date and saying plainly that the subject matter is history. Five inline SVGs replace the originals' raster diagrams, built from the svg.dg classes with no hex values.

Dropped, not ported

Four generic DevOps and Kubernetes tutorials that were largely renderings of upstream documentation, the 2020 post about building the old blog, the 2020 V8 build note and the 2022 CPU war story. The whoami bio is left for the about-page rewrite, which is its own branch.

What changed against the sources

Cold reads returned FIX FIRST on every post, and several findings were errors introduced in translation rather than inherited. Corrected against the Vietnamese sources and, for the CTF post, against the challenge source itself:

  • The RTX 3060 needed the Windows driver unlock to reach 48 MH/s; the draft said it "only reached" that.
  • "The mining paid for itself" was never claimed in the source, which states the goal and never reports the outcome. No revenue figure exists anywhere in the old blog.
  • Chia plotting was offered as evidence that people rent GPUs to mine. It is a storage and CPU workload.
  • The Merkle second-preimage rewrite submits the concatenation of child digests, not the internal nodes, because the implementation hashes every element before pairing.
  • Where 2047 comes from is now derived: one answer per list length from 2 to 2048. It is not 2^11 - 1. Re-running the solver reproduces it.

The origin post was rebuilt around the objection that a VPN hub is itself an internet-facing listener. The claim is now that the exposure relocates rather than disappears, with WireGuard's silence to unauthenticated packets as the reason that trade is worth making.

Verification

  • hugo --minify builds with no ERROR and emits all four posts
  • content/ is ASCII throughout
  • no post carries a hex value, fill= or stroke=
  • all five SVGs render as markup, nothing escaped by Goldmark
  • both theme states checked on every diagram
  • no employer name in the output

Swept facts and per-post decisions are recorded in homelab-platform under docs/blog/old-blog-archive.md.

🤖 Generated with Claude Code

minhtt159 and others added 8 commits September 16, 2026 02:20
Ports the surviving material from teamkhunglong.github.io, a Jekyll blog
dormant since 2022, translated from Vietnamese and rewritten to this
repo's conventions. Each post opens with an archive note giving its
original date and saying plainly that the subject matter is history.

- Merklision: the SVATTT 2020 CTF writeup, a Merkle second-preimage
  attack composed with an odd-length padding bug to reach 2047
  collisions against a requirement of 2020.
- Mining ETH in a homelab: the 2021-04 GPU passthrough narrative with
  the 2021-09 Kubernetes how-to folded in, since the how-to was the
  second half of the same arc.
- The arithmetic that makes cryptojacking worth it: the 2021-07 post on
  rented-GPU economics, reframed around what the missing cost line
  means defensively.

Each carries one inline SVG built from the svg.dg classes, verified in
both theme states. All numbers trace to the source posts; the swept
facts and their verification live in homelab-platform under
docs/blog/old-blog-archive.md.

Dropped rather than ported: four generic DevOps and Kubernetes
tutorials that were largely renderings of upstream documentation, and
the 2020 post about building the old blog itself. The whoami bio is
left for the about-page rewrite.

Posts stay draft: true pending Minh's read.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A fresh subagent read the three posts with no context and returned
FIX FIRST on all three. Most of what it caught was real, and three of
them were errors introduced in translation rather than inherited.

Corrected against the Vietnamese sources:

- The RTX 3060 needed the Windows driver unlock to *reach* 48 MH/s.
  The migrated text said it "only reached" that, inverting the sense.
- "The mining paid for itself" was never claimed in the source, which
  states the goal and never reports the outcome. Removed; the posts now
  say plainly that no revenue figure was ever recorded.
- The Chia example was offered as evidence that people rent GPUs to
  mine. Chia plotting is a storage and CPU workload on plain compute
  instances, so it evidences the instinct, not the hardware.

Also fixed: the 2047 collision count is now stated as measured rather
than derived, since the original author explicitly wrote that he did
not know the closed form; the cap on n is stated where the challenge is
described; M and H are defined before use; the Windows-guest
instability and the 4U case's three stable months are separated, being
claims about different things; the April/July/September timeline is
made explicit, since the container insight belongs to the July post and
the build instructions to September.

Diagram fixes: post one's colour now encodes role consistently and says
so, rather than drawing identical values in two colours; post two stops
claiming the passthrough path "scales by building another machine",
which contradicts its own prose, and marks IOMMU as a mapping rather
than a pipeline stage; post three's first column no longer renders a
verdict the prose never reaches, and no longer pairs a shared container
input with "walk to the machine" recovery.

The hostAliases bullet is kept and named as evasion, with a pointer to
the companion post that argues the defender's side.

Post three is retitled to match its slug and its content: it contains
no arithmetic, and said so in its title.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ports the 2021-03-16 post from the old blog, which the first pass had
misfiled with the generic DevOps tutorials. It is not a tutorial: it
argues that port forwarding on the ISP modem fails by accumulation, one
defensible hole per service, on hardware the owner does not administer,
and that a 5 USD VPS running a VPN hub holds the count at zero however
long the service list gets.

This is the earliest post in the sequence and the decision the rest of
the homelab grew out of, so it now sits in front of the mining post.

The original carried three raster topology diagrams. They are replaced
by one inline SVG contrasting the two shapes, per the repo's rule that
topologies get redrawn rather than copied. The home ISP named in the
third original diagram is genericised.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A cold read of the origin post returned FIX FIRST, and its central
objection was correct: the post spent its length arguing against
internet-facing listeners while proposing a design that has one. A VPN
server on a public address is exactly the thing being condemned.

The claim is now the honest one. The hub does not remove the exposure,
it relocates it: four listeners on ISP firmware nobody can patch become
one listener on a machine the owner administers, and that count does
not move when the service list grows. The diagram says this too - red
marks an internet-facing listener in both panels, so the single red
arrow on the right is the admission rather than an omission.

Other corrections from the same read:

- The cost comparison had no billing period on the 24.90 USD figure, so
  it could not support "cheaper". The source never recorded the period;
  the post now says so and drops the claim.
- Chrome Remote Desktop was described as free two bullets before the
  summary asserted the products cost more than a VPS. The post now
  admits the remote desktop was the excuse and a general-purpose
  machine was the reason.
- "No third party in the path" was false. The rented box is in the path
  for every packet, and unlike a direct-routing product it always is.
- The modem cannot be both unconfigurable and a viable place to run a
  VPN. Where the ISP locks the firmware the alternative is unavailable,
  which is a different objection than insecurity.
- A camera appliance cannot run a VPN client, and it was the first
  example in the escalation. Appliances stay on the LAN; clients join
  the tunnel and reach them.
- One reverse proxy collapses three HTTP services onto one port, so the
  port count grows only if you let it. That makes the two designs
  closer relatives than the post first implied, and it now says so.
- Added what the design costs: a server that must be patched forever, a
  single point of failure that takes the recovery path with it, and all
  traffic transiting the cheapest instance available.

One real drawing bug: the home-side flow line carried no marker-end
while every other line did, so the direction the whole argument rests
on was not drawn. All nine lines now have arrowheads.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Read the gist rather than relying on the 2020 writeup's summary of
itself, and re-ran the solver. Several things the post asserted were
wrong.

The second-preimage rewrite does not submit the internal nodes. The
implementation hashes every element before pairing any of them, so the
element that reproduces a node is the concatenation of that node's two
child digests - twelve bytes, not the six-byte node. The post and the
first diagram both said the wrong thing; both now say

  M(L1, L2, L3, L4) == M(h(L1)||h(L2), h(L3)||h(L4))

which is what the solver's `hashes[i] + hashes[i+1]` actually computes,
`+` on bytes being concatenation.

Where 2047 comes from is now derived rather than shrugged at. The
answers come out one per list length, from 2 up to the padding ceiling
of 2048, so the count is 2048 - 2 + 1. It is not 2^11 - 1; the
resemblance is the ceiling being a power of two. Re-running the solver
reproduces 2047 with every length present exactly once. The set also
includes the original tuple, so there are 2046 genuine collisions, and
the post says so rather than leaving two defensible numbers implicit.

Other corrections from the source:

- The bound is `assert 0 <= n <= 2020`, stated exactly.
- A duplicate submission trips an assertion and ends the session. The
  draft said repeats were silently discarded.
- There is no check that a submission differs from the original, only
  that the 2020 are pairwise distinct, so the original is a legal
  answer. The draft claimed otherwise.
- Submissions are base64-decoded to arbitrary bytes, so there is no
  alphabet restriction. The draft had invented one and built a
  paragraph on it about why the composition's last step mattered.
- The hash is SHA-256 truncated to six bytes, which the draft never
  mentioned.

SVATTT expands to the ASEAN Student Contest in Information Security.
The draft called it a Vietnamese inter-university competition.

Adds a second diagram, for the length ladder that produces 2047.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Minh supplied what the original post never recorded: the VPN was
WireGuard, deployed with Algo, the Trail of Bits Ansible scripts, on a
virtual machine from Viettel IDC.

Both facts carry real weight in the argument, so neither is a footnote.

Algo's opinions are half of why exposing this server is defensible: it
refuses to install OpenVPN or Tor, drops L2TP, IKEv1 and RSA, does not
rest on TLS, and builds on an Ubuntu LTS with unattended security
upgrades. That last one partly answers the post's own objection about
having to patch the replacement forever, so the cost section now says
what it covers and what it does not - distribution packages, yes; the
day the LTS goes end of life, no.

WireGuard closes the harder gap. It does not reply to packets that fail
authentication, so the one remaining listener does not announce itself
to a port scan, which is a different exposure profile from a forwarded
port where whatever sits behind it answers anyone who knocks. That is
the strongest available answer to the objection the previous commit
conceded, and it is now in the prose, the diagram label and the
description.

Viettel IDC was the hosting arm of the same carrier terminating the
line at home, so tunnel traffic stayed inside one national network
instead of transiting Singapore or Frankfurt. For a tunnel every
interactive session crosses, that is the difference between a remote
desktop feeling local and feeling remote - and it is the piece that
stopped making sense when he moved to the Netherlands within the year.

The disclosure rule in blog-inspirations.md is scoped to current
employer material, so a personal 2021 hosting provider is nameable. The
home ISP stays generic; the argument never needed it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The provider was named without context, which assumes a reader who
already knows it. Both mentions now place it: a Vietnamese cloud
provider whose small instances sit where an equivalent DigitalOcean
droplet sits.

That also repairs the cost reasoning. The post argued for buying
domestically on latency grounds while leaving the impression that the
price was a concession, when it was competitive on its own terms.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Flips draft to false on the material ported from the retired
teamkhunglong.github.io blog, after Minh's read.

Verified before flipping: hugo --minify builds with no ERROR and emits
all four; content/ is ASCII throughout; no post carries a hex value,
fill= or stroke=; all five inline SVGs render as markup with nothing
escaped by Goldmark; and no employer name appears in the output.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@minhtt159
minhtt159 merged commit 839742d into main Sep 16, 2026
2 checks passed
@minhtt159
minhtt159 deleted the claude/blog-migration-homelab-8a34df branch September 16, 2026 01:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant