DevOps
Docker & Portainer, Traefik, Cloudflare tunnels, 162 production containers across 3 hosts, backups and monitoring — my most hands-on, differentiated material.
34 posts in this category
-
When Lowering CRF Does Nothing: The -maxrate Ceiling and the SSIM Quality Deadlock
Why dropping CRF by five steps improved SSIM by only 0.00003: discovering the mathematical conflict between -maxrate bitrate ceilings and quality gates in high-throughput video re-encoding.
-
PHP2Shell: I Measured Every PHP Runtime I Manage. All of Them Were Vulnerable.
CVE-2026-109618 and CVE-2026-109619 are unauthenticated RCE in PHP itself, exploited before disclosure. What I measured across the infrastructure I manage — and the exact fix that closed it.
-
Docker Reported Exit 0. The Kernel Had Already OOM-Killed It.
A container on my NAS kept stopping unexpectedly while Docker reported exit 0 and OOMKilled=false. The honest evidence was in dmesg: six cgroup OOM kills.
-
Space Reclamation Wasn't Stuck. It Was Waiting for Tomorrow at 09:29.
The Storage Manager card said 'running' all day and free space hadn't moved. 121 GiB had come back across three separate reclaims — and the afternoon ate 47 GiB of it.
-
Every Player Stuttered on the Same Video. The File Was Blameless.
Same HEVC file, same stutter in VLC, Chrome and an iPad — offline. The container timing was perfect. The pictures were not: NVDEC's legacy AV1 wrapper was returning frames from the wrong timestamps.
-
It Reported Success. Nothing Had Changed.
Three ways a network-mounted drive lied to my conversion pipeline: a write that silently stopped at 12.5 MB of 403 MB, a rename that never landed while the metadata said otherwise, and a size check that agreed with a corrupted copy.
-
The Upstream Was Deleted, Then Came Back as a Rewrite
My production reading service runs a build whose official Docker Hub repo returns 404. Then upstream came back — 233 commits, a new language, no releases. How to tell dead from rewriting.
-
One Hostname for a Public Tracker and an SSO-Gated Dashboard
A web-analytics tracker has to be public and its dashboard must not be. How I put both on one hostname with an authentik proxy provider and path-based skip rules.
-
A Read-Only NocoDB Dashboard for a Database on Another Machine
Point NocoDB at a MySQL/MariaDB database on another machine without copying a single row — and avoid the Docker SNAT source-IP trap and two API traps I hit.
-
How I Vet an Open-Source Dependency Before Betting On It
Six checks that catch a repo which doesn't do what its docs claim — grep for the feature, read the doc's target branch, check the tier gate and the payment rail.
-
Why Chrome Forgets Its Tabs in a Container — And How I Fixed It
Chrome's "continue where you left off" never fires inside a Docker container. The three fixes that failed, the real root cause, and the 70-line keeper that works.
-
The Character That Silently Broke My authentik CSS
My authentik custom CSS looked correct, matched the right elements, and did nothing. The cause was a single > character that authentik escapes into invalid text.
-
When Your Database Client Lies to You: Patching Workbench 26 for MariaDB
MySQL Workbench 26.7.0 connects to MySQL 8.4 but fails on MariaDB with a useless TypeError. Three patches, and why version numbers stopped meaning what you think.
-
Replacing RDPGuard With IPBan: The Traps Nobody Documents
I migrated from paid RDPGuard 7.8.7 to open-source IPBan 4.1.0 — and hit three undocumented traps, including an uninstaller that would have silently unbanned 12 attackers.
-
Upgrading n8n v1 to v2: Seven Deprecations in One Log File
My self-hosted n8n 1.x to 2.40.1 upgrade surfaced seven silent breakages at once — a telemetry schema rejection, deprecated webhook vars, and a DB override that quietly disabled the AI sandbox.
-
The Corruption Came Back on Different Drives — the Cause Was TRIM, Not the SSDs
Two weeks after a btrfs RAID1 pool corrupted on healthy-looking NVMe drives, the same all-zero checksum reappeared on a different drive stack. The culprit was queued TRIM (NCQ) on Seagate IronWolf 110 SSDs — a firmware bug FreeBSD blacklisted but Linux never did. How I caught it and the fix.
-
When SMART Says Healthy and Your RAID Is Silently Corrupting Data
A btrfs RAID1 pool on two healthy-looking NVMe drives quietly corrupted a Windows VM. How I caught it with a checksum forensic — a zero-block CRC32C on the found side of every failure — and how the root cause finally resolved two weeks later: asynchronous TRIM, not the drives or the riser.
-
I Was About to RMA This SSD — the Fault Was a SATA Cable
A Seagate IronWolf 110 SSD threw WRITE FPDMA timeouts, failed mkfs with 'superblock magic doesn't match', and went silent — a textbook dying drive. I swapped one SATA cable and it formatted clean with zero errors. How to test before condemning a drive.
-
Why Unraid Hangs When You Stop the Array With a Swapfile — and the Fix
My Unraid array stop hung forever at unmounting disks because an 8 GB btrfs swapfile pinned /mnt/cache. Root cause, the /boot/config/stop trap, and two User Scripts that fix it.
-
Automating CyberPanel Without the UI: Reverse-Engineering an Undocumented v2 API
CyberPanel v2 killed the documented JSON API and left only the Angular UI's own session+CSRF endpoints. Here's the exact auth flow and how I found the real functions behind the pages.
-
Authentik 2025.8 to 2026.8: The Breakable Parts Nobody Warns You About
A year's worth of authentik major-version upgrade pain: storage mount changes, RBAC session cleanup, trusted proxies, and the authorization_flow vs authentication_flow mix-up that broke SSO.
-
The Forward-Auth Gate That Verified Perfectly — and Wasn't Live
My authentik forward-auth gate returned a clean 302 to the login page from the host itself, while the public URL still served the app. The hostname had two ingress layers, and I had only changed one.
-
Home Assistant Container: Upgrading Thirteen Releases Across a Four-Hop Ladder
Upgrading a containerized Home Assistant installation from 2025.9 to 2026.10 in a single leap risks irreversible SQLite database corruption and broken reverse-proxy gates. Here is how a verified 4-hop ladder preserved 259 entities.
-
Your Disk-Full Alert Is Lying: Stop Alerting on Percentages
3% free sounds like an emergency until you notice it is 500 GB. On multi-terabyte volumes, percentage thresholds fire when nothing is wrong — and miss when something is.
-
Why Your Grafana Dashboard Shows No Data (When Prometheus Is Fine)
Every target up, data in Prometheus, panel expressions correct — and all 41 panels reading No data. The culprit was a Grafana variable filtering on itself, plus the verification habit that hid it.
-
Why Telegram Bot Notifications Die: IPv6, DNS, and a 400 That Took a Day
A debugging story: a Dockerized telegram monitor whose sendPhoto calls returned 400 from nginx/1.30.1 while getMe worked fine — an IPv6-only DNS answer, a wrong extra_hosts IP, and a multipart join that corrupted JPEG bytes.
-
Passbolt UI Kept Hanging — Three Failure Modes From One Missing Config File
My self-hosted Passbolt returned 504s for weeks: a null GPG fingerprint stalled email delivery, a container recreate wiped the fix, and ssl.force behind a proxy caused a redirect loop.
-
Hardening a Tor Onion Service: What Actually Matters
Out of curiosity I mirrored my portfolio and git server onto the darknet. Here's the hardening that held, the parts that silently broke, and whether it's worth offering to clients.
-
Uploading 100MB+ Videos to YouTube via CDP: The Docker Archive Pattern
Learn how to stage large video files inside a Dockerized Chrome container using the Docker Archive API, then attach them through CDP without sending the entire file over the browser WebSocket.
-
The Synology Spreadsheet API Is a Container, Not an API Endpoint
How to automate Synology Office spreadsheets: the official spreadsheet-api container, and the four traps — a fake 'not installed', a 401 with correct credentials, 2FA that can never authenticate, and a permission wall.
-
Putting a Front Door on an App You Can't Modify
A self-hosted app whose front page was a Chinese login box — and a client-rendered SPA I couldn't edit. So I added a second container: nginx, a bilingual page, and three injected lines.
-
Cascading Docker Failures: When a Node.js Heap Limit in NocoDB Starved an n8n Automation Stack
A 768 MB container limit caused NocoDB to crash with JavaScript heap out of memory, triggering hundreds of ECONNREFUSED failures across dependent n8n workflows. Resolving it required max-old-space-size tuning and pruning zombie executions.
-
Why Six Desktop Chrome Containers Locked a Production NAS: CPU WebGL Emulation, Btrfs D-State, and Offloading to iGPU
Running multiple containerized Chrome instances on an embedded 4-core NAS drove load average past 27, freezing Btrfs transactions in uninterruptible sleep. Migrating them to an Intel iGPU host freed 7.5 GB of committed memory and dropped host load to 6.8.
-
Why Your CDP Clicks Silently Fail: Smooth Scroll, Minimised Windows, and JS-Dispatched Events
Three reasons a Chrome DevTools Protocol click reports success and does nothing: a stale rect from smooth scrolling, a minimised window that drops coordinate input, and a page that received the click but rejected it.