After ChatGPT flagged that mdserver might allow path traversal attacks, I used Bruno, an under-development Postman/Insomnia alternative, to check whether Express was sanitizing URLs properly. ChatGPT generated pass and fail URL examples, I wrote asserts for each in Bruno, and the whole collection can be run at once. A side benefit is that requests are stored as version-controllable text committed alongside the rest of the code...
This is a write-up of a small weekend project of mine: a Node.js/Express server that serves markdown files from a directory as HTML, using middleware to intercept requests for .md files and convert them with the Showdown library. I added a simple string-replacement template so the output is well-formed HTML with a proper page title. The code is on GitHub, with hardening and a possible Docker containerization left as future work...
A follow-up to my previous post on tagging Proxmox guests, showing how to use Ansible to automatically start VMs and LXC containers before running apt updates. I cover installing the proxmoxer Python library, my inventory and vault setup, and the differences between starting VMs by name with the proxmox_kvm module and containers by VMID with the proxmox module. I include a complete example playbook...
I use Proxmox’s tagging system to mark which VMs and containers need to be powered on before running my weekend Ansible update script on a dev server. My walkthrough covers applying tags in the web GUI, customizing colors via Tag Style Override, the three display styles available, and sorting machines by tag in the Datacenter search view...
My weekend Ansible apt upgrade run failed on one Ubuntu host with a BADSIG GPG signature error on the Ubuntu jammy-updates repository. I trace the problem to my Apt Cacher NG cache and fix it by deleting the cached Ubuntu repository data, forcing fresh index files to be downloaded. I leave the underlying cause unresolved, though it appears to affect only that one host...
After Insomnia forced account creation and my saved API requests disappeared, I switched to Bruno, a free and open-source API client available for Mac, Windows, and Linux, plus a CLI and VS Code plugins. Bruno stores request collections as human-readable text files, making them easy to commit to source control alongside code. The writeup includes my first impressions after an afternoon of use...
My weekend Ansible update run flagged three machines as unreachable, and the culprit turned out to be expired Tailscale keys, which expire by default every 180 days. Re-authenticating remote machines is awkward because force-reauth drops any SSH session running over Tailscale, while reauthorization from the admin page only grants temporary access. Ways around the problem include disabling key expiry per machine in the admin console, and I also note that expiry dates aren’t easily visible in the CLI or admin page...
A step-by-step walkthrough of my routine for starting new Node/Express SSR web projects with HTMX, covering directory setup, npm and git initialization, GitHub repo creation, and my ongoing dilemma about committing htmx.min.js versus using a CDN. In the second half, I describe an Express starter skeleton with EJS views and partials, basic routing with 404 handling, and some starter CSS...
When I ran Tailscale inside an unprivileged LXC container on Proxmox, it failed at tailscale up with a “no backend” error, because the container lacked access to the TUN/TAP device Tailscale needs. My fix was to stop the container, add a device allow rule and a bind mount entry for /dev/net/tun to its LXC config file, then start it and run tailscale up again...
A walkthrough of how I add a new domain as a virtual host to an NGINX server already managed by Certbot, showing that rerunning certbot –nginx lets me expand the existing combined certificate to cover the new domain. I also cover migrating domains with existing Porkbun-issued certificates to the same server and folding them into the combined certificate, ending with a note on revoking the now-redundant ones...
I explain why I switched from manually downloading SSL certificates from PorkBun every 90 days to using Let’s Encrypt and Certbot, prompted in part by limitations with managing Australian .au domains. It covers installing Certbot on Ubuntu with NGINX, how it reads site configs to obtain and install certificates, and the systemd timer that renews them automatically...
My homelab post about BOINC, the successor to SETI@home, running in an LXC container. After an earlier setup attempt ended with limited success and doubt about the configuration, a pulsing CPU during a weekend maintenance routine showed the client was actually processing World Community Grid work. I also float the idea of using BOINC as a workload to experiment with Kubernetes...
While setting up an Ubuntu 20.04 LXC on Proxmox to run a TP-Link Omada controller, I found DNS resolution failing because Proxmox copies the host’s Tailscale-based resolv.conf into containers, and the container has no route to the Tailscale DNS address. In this post, I cover the diagnosis of why Debian templates behaved differently, plus two fixes: specifying DNS explicitly in the Proxmox GUI, or creating a .pve-ignore.resolv.conf file so Proxmox stops overwriting the container’s settings...
I set up APT Cacher NG in an unprivileged LXC container to cache Debian package downloads for machines on my homelab LAN, avoiding repeated fetching of the same updates. My walkthrough covers installing and configuring the server (including enabling HTTPS passthrough), pointing client machines at the cache via a proxy config file pushed out with Ansible, and checking the built-in report page for cache statistics...
I deploy a small Go monitoring endpoint to my homelab servers as a systemd service, using Ansible. I cover the basics of a systemd .service file, including target dependencies like After=network.target, and an Ansible playbook that copies the executable and service file into place, restarting the service via handlers only when files change. I pull my sudo credentials from an encrypted Ansible vault...
A small Go utility exposes a lightweight JSON endpoint on each node or VM indicating whether RAM and disk usage are okay. Uptime Kuma watches the endpoint with its HTTP keyword check and sends an ntfy push notification when a machine gets into trouble. I include brief impressions of writing in Go and link to the GitHub repo...
I found that backing up an unprivileged LXC container on Proxmox to an NFS share can fail with a permission denied error when the backup process tries to create a temporary file on the remote share. The fix is to edit /etc/vzdump.conf on my Proxmox node and set tmpdir to /tmp, so the temporary file is built locally before being copied to the share...
I walk through using VS Code’s Remote-SSH extension to edit files on a remote server with a full editor instead of terminal tools like nano or vim. I explain that the plugin works by installing VS Code Server on the remote machine and connecting over SSH, then I cover setup: installing the extension, adding a host via the Remote Explorer, saving the SSH config, and connecting in a new window...
My freshly spun-up Ubuntu VPS starts receiving SSH brute-force login attempts against root within minutes, at roughly one attempt every 10 seconds. I cover disabling root SSH login by creating a sudo user, setting PermitRootLogin no in sshd_config, restarting sshd, and watching out for included config files in sshd_config.d that can override settings. I end with the idea of logging what passwords the bots actually try...
After a couple of homelab incidents that Uptime Kuma didn’t catch, including a vanished USB mount and an NVMe drive filling up, I consider adding custom checks for things like disk space, memory use, and mount status via a small metrics endpoint. Weighing Node/Express against Python, C, and Golang, I conclude that C’s benchmark edge isn’t worth the hassle for endpoints polled only every few minutes...