blog.iankulin.com

Posts

Updating SSL Certificates

A short walkthrough of manually renewing SSL certificates before expiry: downloading the new certificates from PorkBun, concatenating the cert and intermediate files into a fullchain with a newline between them (avoiding an issue from the previous renewal), and restarting the nginx Docker container to pick them up. Uptime Kuma and ntfy notifications confirmed the swap, leaving 84 days until the next renewal — which I still intend to automate...

Unlearning Relational DB

Coming from a relational database background, I look at schema design for document-oriented NoSQL databases such as MongoDB, alongside how implementations handle updates to variable-size documents on disk, covering techniques like memory caching, journaling, delta writes, and periodic compaction. My practical conclusion is to design schemas around how the app accesses data and leave the low-level storage details to the database...

How to deploy a Node.js app

I deploy a small Node.js and Express service from my MacBook to an Ubuntu VPS, covering the choice between a native install and a Docker container, installing Node and npm via apt (including why the Ubuntu repository version is quite old), and copying project files to the server with scp rather than setting up git-based CI/CD for such a tiny project. I test with Insomnia instead of Postman, which I avoid because of its data collection...

Using Node.js to return a static file

In this beginner-level walkthrough, I move a static temperature text file from NGINX to a Node.js server. I introduce NGINX and reverse proxying, explain what Node and Express are, and show a short Express setup that serves the file on localhost port 3000, with deploying it left for later...

Complicating the Temperature API

A short YouTube video on building REST APIs with Node and Express prompts a plan to replace my existing weather data setup—a Python cron job on a VPS that writes API results to a text file served by NGINX—with a Node.js endpoint that fetches and caches fresh weather data on request. This would cut the up-to-ten-minute staleness of temperature data polled by homelab servers, and I break the work into small steps, starting with replicating the current text-file behaviour in Node behind NGINX...

HDD Swap on A1278 MacBook Pro

A short walkthrough of replacing my dead hard drive with a 2.5-inch SSD in my 2012 Intel MacBook Pro that had sat in a drawer for three years. I cover removing the bottom cover, disconnecting the SATA plug, transferring the mounting lugs with a torx driver, and reassembling, along with a few practical notes like the angled case screws and a packing-tape fix for the pull tab...

Containers

Reflections on three ways software development has improved since I was commercially developing 20 years ago: internet-based access to information, open source becoming mainstream, and containers eliminating dependency and environment setup hassles. Includes an embedded video explaining how containers work...

Beginning Python

After adopting Beancount for plain text accounting, I write a Python command-line utility that converts bank CSV statements into Beancount transaction files, including automatic GST calculation for Australian bank data. Notes from the process cover VS Code environment setup, command line arguments, CSV parsing, date string manipulation, and formatted output, aimed at programmers new to Python...

Outside Temperature From an API in a Shell Script

I describe adding outdoor temperature readings to my homelab server temperature logs to account for ambient temperature changes, using OpenWeather’s free API. A bash script on a VPS polls the weather endpoint every five minutes, extracts the temperature and timestamp with awk and cut, and serves the result as a text file that each server fetches during its logging cycle; the server-side script also loads the drivetemp kernel module to read SSD temperatures. Graphs of 24 hours of data show how ambient temperature, workload, and a CPU stress test affected the three servers...

Running a Browser Remotely - n.eko

After leaving a remote site unsure whether DHCP reservation changes on the router were actually saved, I look at ways to reach the router’s web UI from home. Options considered include a Tailscale subnet router and terminal browsers like browsh, before settling on N.eko, a self-hosted virtual browser run in Docker on a VPS. My writeup includes a compose file and the NEKO_NAT1TO1 setting needed to fix a “peer disconnected” error behind NAT...

ISO wrangling - Etcher and Ventoy

ISO files can’t just be copied onto a USB drive; they need to be written with a tool that makes the drive bootable. I describe switching from Balena Etcher, which requires re-flashing the drive for every new ISO, to Ventoy, which installs to a USB stick once and lets you copy multiple ISOs onto it, then choose between them from a boot menu at startup...

Git/GutHub - macOS - marking file as executable

While setting up a small cron-driven script to cache a weather API’s JSON output for serving over Nginx, I run into trouble getting git to preserve the script’s executable bit between macOS and an Ubuntu VPS. After git update-index –chmod=+x fails and toggling the filemode config setting only seems to work by accident, the root cause turns out to be a forgotten fact: macOS does support Unix file permissions, so a plain chmod before committing solves it...

Installing SSL Certificates with Nginx on Docker

I set up SSL for a domain served by Nginx in Docker, using Let’s Encrypt certificates generated through Porkbun. I cover concatenating the certificate files, fixing a malformed PEM that broke Nginx startup, and migrating from a plain docker run command to a docker-compose setup with volume mounts and SSL config. I note that certificates expire after 90 days, with certbot suggested as a future automation fix...

Adding a Domain Name to a VPS

I point a Porkbun-registered domain at a BinaryLane VPS by keeping Porkbun as the name server and updating the A record to the VPS’s IP address. Along the way, I include a short primer on DNS resolution and authoritative name servers, plus a mention of my longer-term plan to use the VPS as a Wireguard tunnel to a home cluster. The end result is the domain serving a test page from Nginx running in a container on the VPS...

Linux Shell Script for Temperature Logging

Worried about internal temperatures in a stack of HP Elitedesk nodes running Proxmox, and wanting a before-and-after comparison for a planned NVMe upgrade, I set up logging of PCH, CPU, and SSD temperatures. The readings come from the /sys/class/hwmon/ tree, with a drivetemp kernel module needed for the SSD; a shell script appends them to a CSV every five minutes via cron. The collected data is graphed, including during a CPU stress test...

SDD Wearout numbers

After reading up on Proxmox’s storage setup, I check the Wearout percentages of the SSDs in my second-hand HP Elitedesk nodes and find one no-name drive reporting 100% wearout despite passing its SMART health check. I examine the drive’s SMART attributes, attempt a short SMART test that gets aborted, and consider buying new SSDs ahead of a planned move to a high-availability cluster with NAS, Ceph, or ZFS storage...

Why use './' in front of filenames?

An exploration of why filenames in Linux are sometimes prefixed with ./. I ask ChatGPT for an explanation, verify its claims with hands-on tests, and find the prefix is useful for executing scripts in the current directory, preventing filenames from being mistaken for command arguments, and clarifying relative paths in HTML—though in many cases it’s optional...

Mounting NFS shares into LXC containers

I run Syncthing in a Proxmox LXC container as a possible Dropbox replacement and hit a snag when an NFS share from the NAS fails to mount with an access denied error. The cause is the container’s security restrictions, and the fix is to run it as privileged, either by editing its config file or changing the option in the Proxmox web GUI...

Running Multiple Linux Commands in One Line

A quick Linux shell tip on chaining commands on a single line. Using apt update && apt upgrade -y as the example, I explain how the double ampersand runs the second command only if the first succeeds, and briefly mention semicolons and double pipes for unconditional or failure-only execution...

Linux on HP Mini 110

I experiment with lightweight Linux distros on an old HP Mini 110 netbook, motivated by wanting a low-cost machine for accessing Proxmox VMs outside the web GUI. I try three distros, antiX, Lubuntu, and Mint Xfce, with the main stumbling block being Broadcom wifi drivers: antiX runs the fastest but I never get wireless working on it, while Lubuntu and Mint both work once I install proprietary drivers over Ethernet. Mint Xfce ends up as the working option, despite its 32-bit version nearing end of life...