docker
Technical notes on web development, DevOps, and AI integration.
35 articles
- 03:16devops
Flip the DB Sync Direction, Flip Every Safety Assumption
Flipping db-push into db-pull is more than reversing arrows: local backs up first, the dump gets inspected before trusted, backtick rules change over SSH.
TL;DR: Reversing the sync direction puts your local database at risk, so the guard sequence has to flip. The script first backs up local data for rollback, then takes a consistent staging dump and checks size, tables and completion before wiping anything. It avoids SSH backtick issues and strictly compares row counts afterward, preferring a hard failure over a half-finished import.
#mysql#bash#docker - 21:53devops
A 502 from Cloudflare Tunnel, caused by a compose service name
The tunnel said 502 while every container was green. Compose DNS only knows service names, and a six-line alias solved it in one step.
TL;DR: Public URL returned 502 while everything looked healthy and curl to the proxy worked fine. Ingress pointed to proxy on port 8199 but the service is actually plane-proxy, so Docker DNS had no record and cloudflared couldn't reach the origin. Adding a network alias proxy to plane-proxy fixed it, keeping the name stable for anything outside the repo.
#docker#compose#cloudflared - 21:07devops
Self-hosting Plane without a single public port
A 13-service Plane stack on a single-admin VPS: a cloudflared sidecar as the only public door, bind-mounted state, and no public host ports.
TL;DR: Running Plane on a packed VPS clashed with its default host ports 80 and 443. I kept the 13-service stack fully internal and exposed it only via a Cloudflare Tunnel sidecar aimed at the proxy, not port 8000 which is just the API. This keeps the firewall to SSH only, handles TLS at the edge, and removes public port exposure.
#self-hosting#plane#docker - 06:26devops
KTM Joins Inventory: From Custom 0.5.81 to Vendor 0.5.86
KTM was invisible to Ansible until I added it to two inventory groups. One playbook run later, it swapped from custom 0.5.81 to vendor 0.5.86 with data intact.
TL;DR: Ansible skipped KTM because the host wasn't in inventory, so --limit couldn't target it until two group edits added it. The playbook then upgraded the container from a custom 0-5-81 build to vendor latest 0-5-86, now back in sync. Dashboard password persisted via bind-mounted datadir, while the old custom image remains on disk for later cleanup.
#docker#ansible#automation - 08:10devops
Reviving an Old WordPress Site in Docker: The 301 Trap
Containers healthy, browser dragged to production. Three first-run Docker mechanisms skip old volumes silently, and wp_options holds one more surprise.
TL;DR: Reviving an old WordPress site in Docker, I got redirected to production because stale URLs were baked into wp_options. Docker's first-run scripts silently skip work when old volumes are attached, so restore the database explicitly and fix URLs directly. Scary-looking MariaDB warnings are often harmless; watch the logs patiently before assuming anything is broken.
#docker#wordpress#mariadb - 05:51devops
When a version monitor wakes you for an intentional state
A five a.m. PROBLEM for a healthy fleet that was intentionally newer than Docker Hub. My version comparison had no sense of direction.
TL;DR: A 5 a.m. alert flagged my fleet as out of sync with Docker Hub, but all six hosts were healthy—running an approved custom build newer than the registry. The real bug was the monitor's assumption that Hub is always the source of truth.
#monitoring#docker#sre - 18:21devops
When Custom Docker Images Break Your Upgrade Playbook
Fleet-wide custom Docker images make digest-based upgrade playbooks obsolete; verification shifts to app endpoints, upgrade path becomes clone→build→transfer.
TL;DR: Locally built Docker images broke my Ansible upgrade playbook, since digest comparison needs a remote registry image that custom builds never have. Automation has permanently forked for these hosts. Upgrades are now manual: build locally, transfer via scp, docker load, then swap containers with about 15 seconds downtime while data mounts stay untouched.
#docker#ansible#automation - 17:47devops
Build Docker Images Off-VPS When the Official Registry Lags
The Docker Hub image lags behind the npm release. Build on a big machine, ship it with save, gzip, and scp, then load it on a small VPS.
TL;DR: The Docker Hub image trailed the npm release, and a 964MB VPS can't build a Next.js app without the OOM killer intervening. The fix: build locally, save and gzip the image, scp it over, and docker load it, keeping the old container renamed for instant rollback. Custom images carry different digests, so digest-checking playbooks must skip this server.
#docker#deployment#ssh - 11:17devops
Restart Is Not Deploy: A Pre-Flight Gate for the API Container
A restart gate that refuses while the tree is dirty.
TL;DR: Restarting a bind-mounted container deploys whatever sits in the working tree, so a half-finished refactor went live uncommitted. The fix is a restart script that refuses to run when the served path is dirty, using git status porcelain. The guard narrows but doesn't close the race window between check and start.
#docker#compose#bash