Building Dropbox Before Dropbox Existed: Syncing Files Across 5 Countries
How I built a distributed file sync system using rsync, MySQL replication, and PHP across offices in 5 countries, years before cloud storage was a thing.
In 2007, Dropbox was barely a concept. Cloud storage wasn’t a thing. And I had a problem: a company with offices in 5 different countries needed their teams to share files. The best connection any office had was ADSL. Some were stuck on ISDN.
Email attachments weren’t going to cut it. FTP was manual and painful. SharePoint cost a fortune and still needed decent bandwidth. So I built something custom.
This is the story of a distributed file synchronization system that ran for years, built with PHP, MySQL, and rsync, before the cloud made it all trivially easy.
The Problem
The company spanned five countries. Each office had its own local server running an intranet. Teams needed to share documents, engineering files, and project data across all locations.
The requirements were straightforward:
- Users upload a file to their local server (fast, local network)
- That file automatically appears on every other server
- Users can see where the file is in the sync process
- It has to work over terrible international connections
- It needs to handle large files without killing the network
- Old versions of files need to be accessible
Simple enough on paper. Considerably harder when your fastest link is ADSL and some offices are running ISDN.
First Attempt: Dazuko (and Why It Failed)
My first instinct was to monitor the filesystem at the kernel level. If the OS could tell me the instant a file changed, I wouldn’t need to poll for changes. Enter Dazuko, a kernel module designed for exactly this purpose, on-access file monitoring.
On paper, it was perfect. In practice, it was a disaster.
Dazuko was still fairly new at the time, and it kept crashing the system. Not just the monitoring process, the whole server. Kernel panics, lockups, the works. When your file sync solution takes down the server it’s supposed to be running on, you’ve got a problem.
I pulled Dazuko out after a few weeks of instability. The lesson: don’t bet production infrastructure on bleeding-edge tools, no matter how elegant the approach sounds. Sometimes the boring solution is the right one.
The Boring Solution That Actually Worked
I wrote a PHP script. It ran on a cron job. It checked for file changes by comparing the current state of the upload directory against what it knew about in the database. New file? Changed timestamp or size? Log it and start syncing.
Not glamorous. Completely reliable. It ran for years without crashing a single server.
The Architecture: Hubs and Spokes
The key insight was that not all connections were equal, and trying to sync every server directly to every other server would be painfully slow. Instead, I designed a hub-and-spoke topology.
┌──────────────┐
┌────────►│ Germany │◄────────┐
│ │ (Hub) │ │
│ └──────┬───────┘ │
│ │ │
┌────┴─────┐ Inter-hub sync ┌────┴─────┐
│ Child │ │ │ Child │
│ Server A │ ┌─────┴──────┐ │ Server B │
└──────────┘ │ Australia │ └──────────┘
│ (Hub) │
└─────┬──────┘
│
┌─────┴──────┐
│ Child │
│ Server C │
└────────────┘
Two offices had the best connections: Australia and Germany. These became the hubs. Every other office was a child of whichever hub was geographically (and network-wise) closest.
The flow worked like this:
- A user uploads a file to their local server
- The PHP script detects the change and logs it to MySQL
- The file gets rsync’d to the nearest hub
- Once the hub has the complete file, the other hub copies it
- Child servers detect (via MySQL) that a new file is ready at their hub
- Children rsync the file from their hub
This meant no child server ever had to transfer directly to another child. Every file went through at most two hops: origin to hub, hub to hub, hub to child.
rsync: The Unsung Hero
The entire file transfer layer ran on rsync, and specifically its delta-sync algorithm. This was critical for making the system work over slow connections.
rsync doesn’t just copy files. It compares the source and destination, breaks files into blocks, computes checksums, and only transfers the blocks that have actually changed. If you modify a few paragraphs in a 50MB document, rsync sends kilobytes, not megabytes.
Over ISDN, this was the difference between “file synced in 2 minutes” and “file synced in 3 hours.” For offices editing the same documents repeatedly, delta-sync turned what would have been an unusable system into something that felt responsive.
MySQL Replication: The Clever Shortcut
Here’s the part I’m most proud of. The hardest problem in any distributed system is state: how does every node know what’s happening everywhere else? Which files exist? Which are mid-transfer? Which version is current?
I could have built a custom protocol for this. I could have implemented some kind of gossip protocol or consensus mechanism. Instead, I used MySQL replication.
Every server ran MySQL. When a file change was detected, the PHP script logged it to a local MySQL table: filename, hash, timestamp, size, status. MySQL’s built-in replication handled getting that information to every other server in the network.
This meant:
- Every server had a complete, up-to-date picture of every file across all locations
- Replication handled the networking, retries, and conflict resolution
- The status of every file transfer was visible everywhere
- I didn’t have to write or debug a distributed state protocol
MySQL replication was battle-tested, handled network interruptions gracefully, and “just worked.” It let me offload the entire coordination problem to software that had been solving exactly this kind of problem for years.
The PHP scripts on each server just needed to query their local MySQL to know: “Is there a new file at my hub that I don’t have yet? Is my upload finished copying to the hub?” Simple queries driving the whole sync workflow.
The Intranet Interface
Users accessed the system through the existing intranet on their local server. The interface showed:
- File browser: Upload, download, and browse synced files
- Sync status: For each file, which offices had it, which were still syncing
- Transfer progress: Visual indicator of where files were in the pipeline
- Version history: Access to previous versions of any file
- Search: Find files across the entire distributed system
The status display turned out to be more important than I initially thought. When you’re waiting for a critical document from another country, the difference between “it’s 73% synced to your hub” and just… silence, is enormous. People trusted the system because they could see it working.
The version history was a simple but valuable addition. Every time a file was updated, the previous version was archived with a timestamp. Users could browse and restore old versions directly from the intranet. No complex version control system needed, just a straightforward archive with a web interface.
How the Cascade Worked in Practice
Let’s walk through a real scenario. An engineer in one of the child offices updates a design document.
Step 1: Detection (seconds) The PHP cron script runs, notices the file’s modified timestamp has changed, and logs the change to MySQL.
Step 2: Hub sync (minutes) rsync kicks off to the nearest hub. Delta-sync means only the changed blocks transfer. Over ADSL, a typical document update takes a few minutes at most.
Step 3: MySQL replication (seconds) The hub’s MySQL database now has the updated file record. Replication pushes this to every other server in the network. Within seconds, every office knows the file has been updated and where it currently exists.
Step 4: Inter-hub sync (minutes) The second hub sees (via MySQL) that the first hub has a new file version. It initiates an rsync pull. The connection between the two hubs was the best in the network, so this was relatively fast.
Step 5: Children sync (minutes to hours) Child servers detect that their hub has the file ready. They pull it via rsync. ADSL children get it quickly. ISDN children take longer, but rsync’s delta-sync keeps it manageable.
Throughout all of this, every user at every office can see exactly where the file is in the pipeline by checking their local intranet.
The Technical Stack
- File monitoring: PHP scripts on cron
- File transfer: rsync with delta-sync
- State coordination: MySQL with replication
- User interface: PHP/HTML intranet pages
- Servers: Linux at each office
- Architecture: Hub-and-spoke with two hubs (Australia, Germany)
Nothing exotic. Nothing cutting-edge. Just proven tools assembled in a way that solved the problem.
What Made It Work
Looking back, a few decisions were critical:
1. Hub-and-spoke over mesh
A full mesh between 5 servers means 10 connections to manage, and the slowest connection bottlenecks everything. Hub-and-spoke meant only the two best-connected offices handled inter-region traffic. Children only talked to their nearby hub over relatively decent connections.
2. Letting MySQL handle distributed state
Building custom distributed coordination is one of the hardest problems in computer science. MySQL replication was already solving it. Using it saved months of development and years of debugging.
3. rsync’s delta-sync
This single feature made the whole system viable over slow connections. Without it, every file change would have meant transferring the entire file. With it, routine updates were tiny.
4. The failed Dazuko experiment
Abandoning the “elegant” kernel-level monitoring for a simple PHP polling script was the right call. The polling approach added a few seconds of latency to file detection, which nobody noticed or cared about. The tradeoff for rock-solid reliability was worth it every time.
5. Showing users what was happening
The sync status display wasn’t in my original design. But once people started using the system and asking “has my file arrived yet?”, it became obvious. Transparency builds trust.
The Broader Context
To appreciate how early this was:
-
2007: When I built this system
- Dropbox founded (not yet launched)
- Google Drive didn’t exist
- OneDrive (SkyDrive) didn’t exist
- iCloud didn’t exist
-
2008: Dropbox beta launched
-
2011: iCloud launched
-
2012: Google Drive launched
-
2014: OneDrive rebranded from SkyDrive
We were solving distributed file sync problems with PHP and MySQL years before anyone could just sign up for a cloud storage account.
What I’d Do Differently Today
Honestly? Today I’d use Dropbox or Google Drive. The problem is solved.
But if I had to build something similar again, for an air-gapped network, a highly regulated environment, or somewhere without reliable internet, the architecture would be surprisingly similar. Hub-and-spoke is still a valid topology. rsync is still excellent. And using an existing database’s replication for state coordination is still a clever shortcut.
The main things I’d change:
- Encryption in transit, we trusted the private network more than we should have
- Better logging and alerting, debugging issues on remote servers in different time zones was painful
- Automated health checks, knowing a server was struggling before users reported it
Lessons That Still Apply
Use existing tools for hard problems
MySQL replication for distributed state. rsync for efficient file transfer. Don’t build what you can borrow, especially for the hardest parts of the system.
Design for your worst connection
The ISDN offices drove the entire architecture. If I’d optimized for the fast connections, the system would have been unusable for half the company.
Fail gracefully, then recover
Connections dropped. Servers rebooted. rsync handled interrupted transfers natively. MySQL replication caught up after outages. The system expected failure and recovered from it automatically.
Boring technology wins
PHP on cron beat a kernel module. MySQL replication beat a custom protocol. rsync beat a hand-rolled transfer system. Every “boring” choice contributed to a system that ran reliably for years.
Conclusion
Before cloud storage was a commodity, we built custom solutions with whatever tools we had. This one used PHP for monitoring, rsync for transfers, and MySQL replication for coordination, not because those were the trendy choices, but because they were reliable, well-understood, and available.
It ran for years. It synced files across five countries. It survived flaky ISDN connections, server reboots, and the daily reality of international networking in 2007.
The most elegant part of the system wasn’t any single component. It was the decision to let proven tools do what they were already good at, and just wire them together in the right order.
Have a distributed systems challenge? I’ve been solving complex technical problems for over 20 years. Let’s discuss your project.