After choosing the tiny BusyBox httpd server for containerised websites, I encountered third-party benchmarks suggesting NGINX was dramatically faster. Running my own A/B tests with Apache’s ab tool initially gave misleading results, which turned out to be NGINX Proxy Manager serving cached responses. With cache-busting requests, BusyBox and NGINX performed similarly over the network, so I am sticking with the 1.35MB BusyBox containers over the roughly 49MB NGINX-alpine images...
A step-by-step guide to moving my domain registration from WordPress.com to Porkbun, motivated by my unease over recent WordPress drama. I cover the transfer process—including a required 60-day wait, disabling the transfer lock, and a gotcha where private registration had to be turned off before the authorization code would work—plus copying DNS records and switching nameservers. In a closing update, I note that WordPress later blocked external domain pointing, pushing me toward self-hosting...
Hosting UptimeKuma on Fly.io’s free tier, I find that updating an out-of-date container image requires nothing more than running fly deploy with an existing fly.toml file. After the update the app starts crashing from memory exhaustion, and switching to a lighter Alpine-based image appears to keep usage within the free instance’s 256MB limit...
Using NGINX basic auth as a lightweight alternative to building authentication for my side projects. For a standard NGINX setup, the authenticated username is passed to a Node app in an X-Username header and checked against a user list for access rights. I then cover replicating this in NGINX Proxy Manager, using access lists and the locations tab to set the header...
How I make one Docker Compose service wait for another to be ready, using a healthcheck on the depended-on service and a depends_on condition with service_healthy on the dependent one. The worked example adds InfluxDB to my homelab monitoring stack so a Go metrics collector starts only after the database is up, with sample compose YAML included...
A BusyBox container serving a static site can’t fetch content over HTTPS because BusyBox ships without root CA certificates and has no package manager to install them. Rather than switch to a larger Alpine image, I settle on bind-mounting the host’s certificate directory into the container read-only, with example configurations for both docker-compose and docker run...
A follow-up on bundling static sites into BusyBox Docker containers, covering how to handle minor dynamic tasks such as periodically downloading an image into the directory of hosted static files. Rather than using cron, which behaves unexpectedly on BusyBox, my solution is a shell script with a download-and-sleep loop that runs in the background alongside the httpd server. I also note that BusyBox’s wget has TLS problems, a topic I defer to a later post...
Serving static websites from small Docker containers built on BusyBox httpd, coming in at around 4MB each. I walk through the Dockerfile setup, cross-platform builds from an M1 Mac to linux/amd64, pushing to the GitHub Container Registry, and deploying via docker-compose behind Nginx Proxy Manager, including DNS and SSL configuration...
I explain my move from Docker Hub to GitHub’s Container Registry for container images running on my VPSs, motivated by Docker Hub’s single-private-image free tier and the eventual possibility of CI/CD rebuilds. It walks through generating a Personal Access Token, logging in to ghcr.io, and pushing and pulling images with the registry included in the container name...
I recommend Ishan Anand’s YouTube series Spreadsheets are all you need, which teaches how generative AI works using an Excel spreadsheet implementing most of GPT-2. I highlight Anand’s teaching ability, note that the featured lessons are the first three of a paid course, and link to a downloadable version of the spreadsheet...
My routine npm update, triggered by a GitHub security advisory, runs into the cryptic “Exit handler never called!” error. Alongside a refresher on what package-lock.json and npm update do, my fix is to confirm the lock file is at fault using npm install –no-package-lock, then delete it and regenerate it with a fresh npm install, followed by retesting and rebuilding any artifacts...
I walk through publishing my own JavaScript utility to npm so it can be installed and updated like any other package, rather than copying source files between Node projects. I cover creating an npm account, scoping the package name to my username, writing and publishing the code with npm publish, and installing it in another project, using a simple is-even example...
After abandoning an overly complicated LXD-based file transfer setup, I walk through using command-line rsync to sync files directly between two Synology NASes, including over Tailscale. I cover setting up passwordless SSH without ssh-copy-id, working around DSM 7’s restriction on Tailscale outbound connections and its lack of Magic DNS, enabling rsync in the Synology interface, excluding metadata and recycle bin directories, fixing permissions, throttling bandwidth, deleting remote files in one-way syncs, and running the job in the background with nohup...
Running NGINX Proxy Manager in a Docker container breaks the usual habit of pointing proxies at 127.0.0.1, since localhost now refers to inside the container rather than the host. I explain why, cover the confusing exception of NPM’s own admin interface, and show how joining service containers to NPM’s Docker network lets the proxy reach them by container name via DNS, with no ports exposed to the host...
A beginner-friendly walkthrough of enabling file uploads in a Node/Express web app using the multer middleware. I cover setting up a basic Express server, configuring multer’s disk storage, and submitting files via an HTML form with multipart/form-data encoding, before briefly noting production concerns like sanitizing filenames and restricting file size and type...
I walk through building user authentication in an Express.js app from the ground up, starting with how HTTP requests, cookies, and sessions work before moving to session IDs and the express-session library. I then cover a login flow with bcrypt-hashed passwords and file-based session persistence, laying groundwork for a future post that will use Passport.js...
I explain why I use Docker bind mounts instead of named Docker volumes in my homelab, keeping each container’s compose file and data together in a single directory for easier backups and migration. I weigh the tradeoffs of this approach and walk through migrating an Uptime Kuma container from a named volume to a bind mount by locating the volume’s files with docker inspect and copying them directly while the container is stopped, contrary to more complicated methods suggested elsewhere online...
Having downloaded a pile of large language models to run locally with Ollama on my M1 MacBook, I compare how several of them (codeqwen, deepseek-coder, phi3, dolphin-mistral, and llama3 at different quantisation levels) answer a Docker question about CMD versus ENTRYPOINT. I time each response and judge it subjectively, with caveats that the test is unscientific and benchmark charts usually reflect full-size models on expensive hardware. My writeup includes a layman’s explanation of quantisation, brief notes on each model’s character, and I conclude that llama3 and most others gave usable answers while phi3 fell short...
I offer a short explainer on the difference between ENTRYPOINT and CMD at the end of a Dockerfile, with examples showing that command-line arguments replace CMD entirely but are appended to ENTRYPOINT. I also cover combining the two, and note that both execute at container launch, unlike RUN, which happens during the image build...
Docker environment variables set for a container aren’t available to scripts run by cron inside it, even when cron runs as the same user. After confirming the cause and finding no clean fix, I settle on a workaround: saving the needed variable to a file in the entry point script and reading it back from the cron job...