Blog
Technical notes on web development, DevOps, and AI integration.
152 articles
- 00:44security
My Playbook Said Changed, sshd Said Still Open
The hardening playbook said changed, but sshd -T still showed passwordauthentication yes: first-match-wins and lexical Include order let 50-cloud-init.conf win.
TL;DR: OpenSSH uses first-match-wins for sshd config, so a drop-in named 50-hardening.conf lost to cloud-init's 50-cloud-init.conf alphabetically. Fix: rename it 00-hardening.conf, comment out conflicting lines in the main config, and edit 50-cloud-init.conf directly. Always verify with sshd -T instead of trusting a playbook's green status.
#ssh#sshd#hardening - 00:44devops
Two Silent Killers in One Ansible Deploy
An Ansible playbook died over an apostrophe inside a block scalar, then hosts went unreachable over ssh key offer order. Two lessons from one exit code 4.
TL;DR: A comment with an apostrophe inside a shell block scalar killed the whole playbook, since YAML ignores # in block scalars and Ansible's argument splitter chokes on unbalanced quotes. Exit code 4 is ambiguous anyway. Then MaxAuthTries exhausted wrong-key attempts; IdentitiesOnly=yes with ordered IdentityFile entries fixed it.
#ansible#ssh#yaml - 22:27frontend
My Sticky Sidebar Failed in Complete Silence
A position sticky sidebar that scrolled away with the page, and the three CSS preconditions I now check before trusting sticky again.
TL;DR: A sticky sidebar in a flex layout failed silently because it broke all three preconditions. Flexbox's default stretch left the aside no scroll room, fixed with items-start, while a fixed header demanded a custom top offset. The author now avoids overflow-clipping ancestors, removed redundant height caps, and made this layout a standard pattern.
#css#tailwind#flexbox - 18:45devops
My Phone Buzzed at 2 AM and There Was Nothing To Do
A noisy alert trains you to mute the channel. Debouncing 3 samples, recovering at 75% of warn, and deduping per incident before Discord pings you again.
TL;DR: A transient backup spike fired the alerts until the channel got muted, which is worse than no monitoring. The fix: three-sample debouncing, a 0.75 hysteresis factor for recovery, and per-incident dedupe, mirroring Prometheus's for and keep_firing_for clauses. Core principle: alerts must be urgent and actionable, or they're spam.
#monitoring#alerting#discord - 18:38devops
Dashboard Numbers Go Stale Without Telling You
A last value without its age is a lie. Adding staleness badges (fresh/aging/dead), window-following aggregates, and portable systemd timestamps.
TL;DR: A dashboard showed 3% CPU while the service had been dead for seven hours, because the last sample was rendered as if fresh. The fix classifies data as fresh, aging, or dead based on age versus poll interval. Lesson: a value without its age is a lie.
#monitoring#prometheus#systemd - 17:26devops
Three Fixes That Tamed My Server Monitoring Dashboard
A server monitoring dashboard becomes noise when attention items pile up with no organization. Three complementary fixes transform a flat grid into a usable workflow.
TL;DR: Dashboard Guy Eighteen flat grid of alerts made it impossible to find critical issues across nine servers. Backend search with debounce, severity filter buttons, and collapsible server groups solved the noise problem by pushing all filtering logic server-side. Three tools together let you triage from hundreds of items in two taps or three words.
#monitoring#ux#devops - 16:18ai
Automate Browser AI: Delegating Article Drafts to Free Qwen Chat
Building a free article draft generator from chat.qwen.ai via automated browser: mechanics, pitfalls, and fallback that make it cron-worthy.
#qwen#browser-automation#content-pipeline - 12:57devops
40 Mbps in the Config, 5 Mbps on the Screen
A half-remembered Mbps-to-bytes formula left the 3proxy bandlim cap at 5 Mbps instead of 40. The manual said bits all along.
TL;DR: A 3proxy bandwidth cap configured at 40 Mbps actually limited traffic to 5 Mbps because bandlim expects bits per second, not bytes, so the fix was changing 5000000 to 40000000. The same commit trimmed a GoAccess dashboard to three panels, surfacing the URL table immediately. Lesson: verify unit conversions against the manpage.
#3proxy#bandwidth#networking - 12:39devops
I Deleted My Dashboard, Then Called It Back
I tore out my self-built GoAccess stack for 3proxy's built-in admin counters, then realized counters can't answer which URLs eat the bandwidth.
TL;DR: The author deleted a self-built GoAccess dashboard for 3proxy, replacing it with the built-in admin directive and secure-mode counters. That answered how much traffic, but not which URLs or hosts consumed it. GoAccess returned properly: stripped fractional timestamps, filtered ADMIN lines, and nginx proxying WebSocket with explicit upgrade headers and longer read timeouts.
#3proxy#goaccess#nginx