Shipping Software Updates to Servers You Don't Control
2026-09-21
Key takeaway
Shipping software updates to servers you don't control — self-hosted installs on cheap shared hosting — needs a different discipline than a normal deploy. Bicitra Commerce's update pipeline preflights every planned file write (permissions, ownership, disk space) before touching anything, verifies each release package against a checksum, skips vendor/ entirely when dependencies haven't changed, and rolls back completely — including new files — on any failure.
Bicitra Commerce is distributed differently than most SaaS products: instead of one application you deploy and control, each merchant runs their own isolated Laravel/MySQL installation, usually on the cheapest shared hosting they can find. That distribution model buys merchants real independence and low hosting costs. It also means every update ships to a production server you don't have SSH access to, running under hosting conditions you don't control and can't fully predict in advance.
The failure that shaped the design
The preflight check that now guards every update exists because of a real incident, not a hypothetical one: a host where vendor/ had been left owned by the SSH user after a manual composer install. The update process discovered this the hard way — mid-update, with the site already down, because the failure only surfaced once the process tried to write files it didn't have permission to touch.
That's the worst possible time to find a permissions problem. The site is down, the update is half-applied, and there's no ops team on the other end of that shared hosting account to intervene.
Preflight before anything goes down
The fix is to check everything the update will need before touching a single file. The pipeline now preflights every planned file write — permissions, ownership, disk space — and reports a problem with zero files touched, instead of discovering it three steps into an update with the site already offline. A cPanel host that disables symlink() outright, or leaves inconsistent file ownership after a manual install, gets caught before it becomes an outage.
Defense in depth, not just one check
A few other decisions came out of the same constraint — that nobody can intervene if something goes wrong mid-update:
- Checksum verification. Every release package is verified against a checksum before it's applied, so a corrupted or incomplete download can't get partially installed.
- Skip what hasn't changed.
vendor/is left untouched entirely when dependencies haven't changed, which shrinks both the update's blast radius and the number of things that can go wrong on hosts with slow or unreliable disk I/O. - Rollback on failure, completely. If an update fails partway through, it rolls back — including removing new top-level files a failed update had already added, not just reverting modified ones. A failed update should leave the site exactly as it was, not in a new, undocumented state.
The general lesson
Most update tooling is designed assuming a human is watching and can react if something breaks. Once you're shipping to infrastructure you don't operate — shared hosting, a customer's VPS, an air-gapped environment — that assumption disappears, and the cost of getting it wrong goes up: a broken update isn't a Slack alert, it's a merchant's storefront offline with no one who can SSH in and fix it. The mitigation isn't a single clever check; it's preflighting before you commit, verifying before you apply, changing as little as necessary, and making failure completely reversible. Build for the update that fails on a host you'll never see, because eventually one will.
This is the writeup behind Bicitra Commerce.
FAQ
- How do you safely ship software updates to servers you don't have SSH access to?
- Preflight every planned file write — permissions, ownership, disk space — before touching a single file, so a problem is caught and reported with zero files changed instead of discovered mid-update with the site down.
- What causes update failures on shared hosting specifically?
- Things like symlink() being disabled outright on cPanel hosts, or file ownership left inconsistent after a manual composer install — exactly the kind of environment-specific issue a preflight check catches before it becomes an outage.
- What happens if an update fails partway through?
- It rolls back completely, including removing new top-level files the failed update had already added, not just reverting modified ones — the site is left exactly as it was.
Related articles
Row-Level Security Hid Rows From the Job That Deletes Them
Getting a multi-tenant hospital system ready for a real server almost turned the audit log's retention job into a silent delete.
EngineeringPreventing Double-Booking in a Real-Time Appointment System
How DocBee guarantees two patients can never book the same doctor's slot, using a database constraint instead of application logic.