• React 19 + Vite — what changed from the webpack days

    I’ve been building React apps since the create-react-app days. Webpack configs, Babel plugins, 45-second cold starts. It was fine — it was all we had. Then Vite happened, and then React 19, and now frontend development feels like a different job. A better one.

  • Upgrading EKS across four environments — the rolling strategy

    Upgrading Kubernetes on EKS sounds simple — change a version number, apply, done. In practice, with four environments (devnet, testnet, preprod, prod) and services that can’t afford downtime, it’s a multi-week process with a lot of “apply and watch” in between. I just finished rolling from 1.29 to 1.33 across the board, and here’s what that actually looked like.

  • Migrating from ethers.js to viem — what broke and what got better

    I spent a good chunk of last year migrating from ethers.js v5 to viem. Not because I had to — ethers was working fine. But I kept seeing viem pop up in every modern web3 project, and after reading the docs I understood why. It’s a fundamentally better approach to the same problem.

  • Fail2ban and firewall hardening on a public-facing VPS

    The first time I ran grep "Failed password" /var/log/auth.log | wc -l on a new VPS, the number was embarrassing. Thousands of failed SSH attempts within 48 hours of provisioning. Bots scan the entire IPv4 space continuously — your server is being probed within minutes of getting a public IP. Let’s do something about it.

  • Loki + Promtail for log aggregation on a budget

    I’ve been running Prometheus + Grafana for over a year now and it’s great for metrics. But metrics tell you what happened — not why. For that you need logs. And my logging strategy was ssh into the server and tail -f whatever PM2 was writing to disk. Not scalable, not searchable, and definitely not “check this from my phone at 2am” friendly.

  • First smart contract on Base — what surprised me

    I’ve been writing Solidity for a while, but always on mainnet or testnets. Base launched in August 2023 and I figured it was time to try an L2 for real — deploy something, see how the tooling and gas economics actually differ. What follows is everything that surprised me — good and bad — about deploying on Base using the Foundry toolchain.

  • Ansible for a single server — overkill or exactly right?

    When I first set up my VPS, I configured everything by hand. SSH’d in, ran commands, tweaked config files, forgot what I did three weeks later. The second time I set up a server I wrote bash scripts. Big bash scripts. Scripts that grew organically until they were unreadable, non-idempotent, and broke in subtle ways if they’d already been partially run. The third time I used Ansible. I haven’t looked back.

  • Deploying with PM2 — why I stopped using Docker for Node.js apps

    Hot take: Docker is overkill for deploying Node.js apps on a single server. I know, I know. Containers are great. Isolation, reproducibility, all that. But when you’re running 4 Express apps on one VPS and your “deployment” is rsync + restart, Docker adds a layer of complexity that earns you almost nothing.

  • Running Prometheus + Grafana on a single VPS

    I run a bunch of services on a single Hetzner VPS. Nothing fancy — a few Node.js apps behind nginx, some cron jobs, the usual. For a long time my “monitoring” was htop over SSH and hoping nothing breaks while I sleep. That’s embarrassing to admit, but I think a lot of solo devs are in the same boat.

  • SSH config tricks I wish I knew years ago

    For years I SSH’d into servers by typing the full command every time. ssh -i ~/.ssh/id_rsa -p 2222 user@192.168.1.100. Sometimes with a jump host in the middle. It worked, but it was tedious and error-prone. Then I actually read the ssh_config man page and felt mildly embarrassed about all the time I’d wasted.