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...
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...
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...
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...
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...
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...
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...
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...
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 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...
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...
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...
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...
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...
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...
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...
Proxmox saves VM backups to local storage by default, which is no help if the host dies and makes restoring to a different node awkward. My walkthrough covers creating a shared folder with NFS permissions on a Synology NAS, then adding that share as storage at the datacenter level in Proxmox so backups and restores can happen from any node, making it easy to move VMs between hosts...
After finding that memory, rather than CPU, is the bottleneck on my Proxmox server, I order physical RAM for the host. I also walk through increasing the RAM allocated to a Jellyfin VM from 6GB to 8GB via the Proxmox Hardware settings, noting the change takes effect only after a reboot...
I set up a secondhand Synology DS216j NAS as homelab storage with RAID 1 and a Samba share, intended for VM backups and eventually a media library. I then mount the share on a privileged Debian LXC container in Proxmox via a cifs entry in /etc/fstab, with a breakdown of the mount options and a note that the setup persists across reboots...
I wrote a short how-to for fixing the 401 Unauthorized error that apt update throws on a freshly installed Proxmox server because the enterprise repository requires a paid license. The fix involves commenting out the pve-enterprise.list entry and switching sources.list over to the no-subscription Proxmox repository alongside standard Debian Bullseye repos...