blog.iankulin.com

Homelab

Gogs - your own tiny GitHub

I wanted a private git server for version-controlling my plain-text financial accounts (kept with beancount), rather than pushing them to GitHub. I walk through installing Gogs — chosen over Gitea for being simpler — in Docker on an LXC container, including a storage driver fix needed to get it running, and finish with the first-run setup and pushing a repo...

New Self-Hosted Service Workflow

A walkthrough of my workflow for adding a new self-hosted service to my Proxmox homelab, using audiobookshelf—set up after abandoning Audible—as the worked example. It covers running the service as a Docker container inside an unprivileged Debian LXC, mounting NAS storage via fstab, Tailscale access, Ansible automation, monitoring with Uptime Kuma, and Proxmox backups...

ViewTube

ViewTube is a self-hosted YouTube front end that strips out ads and tracking, with local accounts for subscribing to channels and keeping video progress. I got it running in a VM with Docker Compose in about five minutes, along with a workaround of using MongoDB 4.4 because newer versions require AVX CPU support my VM didn’t expose...

Docker volume backup is more complicated than it should be

I explain how to back up and migrate a Docker named volume between hosts using the official method: stopping the container, then running a temporary container that mounts the volume and tars its data to a file. I work through an example with Uptime Kuma that covers moving the data to a new VM and restoring it into a fresh install, including a gotcha where restoring to the wrong path leaves the data nested and ignored. I end by questioning why simply copying the volume’s files from the local filesystem isn’t recommended...

Ansible playbook to start Proxmox hosts

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...

Proxmox tags to solve a problem

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...

apt update - BADSIG 871920D1991BC93C

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...

Tailscale keys expire

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...

Getting Tailscale working in LXC containers

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...

Certbot - adding more virtual hosts

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...

BOINC in an LXC container

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...

Solved DNS Issues - Proxmox, LXC, Ubuntu, Tailscale

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...

Caching APT updates

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...

Installing service with Ansible

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...

Simple API endpoint in Go

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...

Problems backing up LXC to NFS in Proxmox

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...

Use VS Code to work on remote files

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...

Disable SSH root logins

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...

Lightweight Web Servers

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...

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...