blog.iankulin.com

Posts

Cookies, Sessions & Tokens

While getting a web app ready for alpha testing with real user data, I needed to add login authentication. My post is mostly a recommendation for a video by Valentin Despa that explains the big picture of implementing authentication in an Express app with Passport, a gap left by more detailed tutorials...

Basic VPS disk speed

My disk benchmark results for a few VPS providers, run with fio. Binary Lane performs well despite only advertising SSD storage, while I find the difference between Digital Ocean’s SSD and NVMe offerings disappointing, though contention on shared drives may explain some of that...

Sorting out Node package dependencies when cloning old repos

I add authentication to an old Node.js app by cloning a four-year-old tutorial repo, which produces a flood of npm install errors. I explain how package.json and package-lock.json pin dependency versions (carets, tildes, exact pins, transitive dependencies), then work through escalating fixes in order of risk: deleting the lockfile, loosening version ranges, wildcard updates, and npm audit fix –force, followed by testing...

Testing Storage Speed

After adding NVMe drives and an external USB NVMe mirror to my Proxmox homelab, I benchmark four storage options — internal NVMe, SATA SSD with ZFS, Synology NAS, and external ZFS pool — using fio write tests to decide where live VM disks should live. Results upend expectations: the NAS is fastest for parallel writes, the external enclosure disappoints, and ZFS compression carries a real cost on small random writes. The upshot is ZFS without compression on the SATA SSDs, trading some speed for data integrity and easy snapshot transfers...

Error wiping old drive in Proxmox

When reusing my old Proxmox boot SSD as a ZFS pool, a “has a holder (500)” error blocks wiping the drive in the web GUI. The workaround is to delete the old partitions with fdisk, reboot to release the kernel’s hold, and then wipe the drive normally. I also note the installer’s existing-volume-group prompt and recommend the graphical installer when adding a boot drive to an existing node...

How to install M.2 SSD in HP G2 800 Mini

A step-by-step walkthrough of installing 256GB NVMe drives in the M.2 slot of HP EliteDesk 800 G2 Mini machines. My Proxmox nodes will boot from the new drives, letting the existing SSDs — whose SMART reporting is unreliable — run ZFS with scrubbing for data integrity. I cover opening the case, removing the drive cage to reach the M.2 slots, seating the drive, and reassembly, along with a note that M.2 mounting screws typically need to be ordered separately...

Hide 'Problems' for a file in VS Code

How I silence linter warnings that VS Code raises for the minified pico.min.css file from the Pico CSS library: I exclude the file with a files.exclude entry in .vscode/settings.json, which stops it appearing in the file view and being processed by extensions. I also cover committing workspace settings to the repository and leaving a note in .gitignore so the hidden file isn’t confusing later...

Installing a Node app on a server

A walkthrough of deploying a Node.js app to a server so it runs as a systemd service rather than an attached terminal session. Using a minimal Express app as the example, I cover copying the files over, installing dependencies, writing a systemd unit file with restart behaviour, and confirming the app still responds after logging out. It’s my manual groundwork for a later Ansible playbook that will automate the setup...

Digital Ocean first impressions

Frustrated with slow VM provisioning in Proxmox compared to BinaryLane, I used a $200 Digital Ocean credit from a podcast promotion to test how quickly a cloud VM can be spun up. A Debian droplet booted in about 42 seconds, but initial SSH access proved awkward, requiring me to dig through docs and the web console to set up a user since Debian blocks root login. Once I cleared that hurdle, the rest of the experience was fine...

Nginx config on Debian/Ubuntu

I give an overview of how nginx configuration files are arranged on apt-based distros like Debian and Ubuntu. I cover the main nginx.conf file including configs from the conf.d directory, a pattern that separates distro-maintained settings from local changes, and the sites-available/sites-enabled symlink setup for enabling and disabling individual site configs...

Ansible with Secrets

This is a follow-up to my earlier Ansible playbook post, covering how to handle different sudo passwords across servers. I show how per-host inventory variables work, explain why storing ssh passwords in plaintext is risky, and walk through moving credentials into an external vars file before encrypting it with Ansible Vault, including the create, edit, and ask-vault-pass commands...

Bloody VIM

A short survival guide to vi/vim for sysadmins who unexpectedly find themselves in it, such as when editing an Ansible vault or adding a message to a git commit. I cover the essentials of Vim’s modes: navigating with the cursor keys, pressing i to enter insert mode, using escape and :wq to save and quit, with a brief note on why Vim’s unusual movement-focused design exists...

Finding the host IP from inside a Docker container

Migrating my node.js API from a homelab VM to a VPS hits a snag: nginx, running in a Docker container, serves static files fine but returns Bad Gateway when proxying API requests. I walk through working out that localhost inside the container doesn’t reach the host, trying host.docker.internal without success, and finding the fix by checking the docker0 bridge interface, which gave 172.17.0.1 as the address to put in the nginx config...

nginx in Front of a node.js app

I configure NGINX on a VPS to serve static files while forwarding /api routes to a Node.js app running on localhost. I cover a server block example with proxy_pass and the Host header, the conf.d include convention, and restarting or validating the config. This post is part of a series on my weather API, but it is self-contained...

Where to go after Reddit

After Reddit’s treatment of its communities ahead of its IPO, I decide to leave the site and evaluate alternatives, settling on Lemmy as a federated, Reddit-like replacement. I also cover communities that moved to Discourse instead, the fragmentation of online discussion into smaller islands, and ChatGPT’s possible role in Stack Overflow’s decline, and close with a list of the Lemmy and Discourse communities where I now post...

ZFS Basics on Proxmox

Persuaded by the 2.5 Admins podcast’s enthusiasm for ZFS, I set up a mirrored ZFS pool in Proxmox using two 256GB NVME drives in a USB dual-bay enclosure. My walkthrough covers creating the pool via the Proxmox web GUI, a primer on ZFS terminology (pools, vdevs, datasets), and basic tasks like moving VM disks onto the pool and running a scrub. I also note enclosure temperatures under load and possible sustained write slowdowns on the Samsung PM981 SSDs...

First Ansible Playbook

This is a follow-up to my getting-started-with-Ansible post, in which I walk through writing my first playbook that installs NGINX and keeps the service running on a pair of web servers. I cover the basics of YAML, the shift to declarative thinking, the apt and service modules, and how to read the color-coded output from a playbook run. I close by setting up a problem for a future post: automating updates across servers that each have unique credentials...

Proxmox 8.0 Install

Ahead of upgrading my Proxmox homelab node from 7.4 to 8.0, I migrate its guest VMs (Jellyfin and a Docker host) to another cluster node, which doubles as a test of the disaster-recovery plan, fixing a couple of hardware incompatibilities along the way. The node then gets a fresh Proxmox 8 install rather than the in-place upgrade, which I document as a runbook covering non-subscription repositories, SSL certificates, Tailscale, and NFS storage...

Getting Started with Ansible

My beginner’s guide to taking the first steps with Ansible, aimed at people comfortable managing a few Linux servers on homelab VMs or a VPS rather than following tutorials built around Vagrant and VirtualBox. I cover installation prerequisites, ad-hoc commands run against a small set of Debian VMs, core concepts like modules and idempotence, and simplifying commands with inventory files and ansible.cfg. I defer playbooks to a follow-up...

How to recover a docker run command

How I reconstruct a forgotten docker run command when I need to update a container: there’s no Docker command that retrieves it, but shell history and docker inspect can reveal the ports, mounts, and volumes I used. I suggest switching to Docker Compose as the way to avoid the problem in future...