A WA manufacturing group ran its core line-of-business application on a single ageing server in the factory, with no test environment, manual deployments and backups whose restores had never been attempted. We rehosted the application and its database to AWS in four stages, proved a full restore against an agreed recovery target, and left behind infrastructure defined in code rather than in one machine.
The application was fifteen years old and had never been moved. It ran on one tower server standing in a factory office, alongside a domain controller and a network-attached drive holding every drawing, job card and scanned document the business had produced since 2010. There was no second environment of any kind: development, testing and production were the same machine, so a change was either applied live or not applied. Deployments consisted of connecting by remote desktop outside production hours and copying compiled files over the running application.
We delivered a like-for-like rehost first and changed little else. The application and database now run on AWS in the Sydney region, built and rebuilt from Terraform so that staging and production are genuinely identical. Backups are managed, monitored and restored on a schedule rather than assumed. Once the platform was stable we re-platformed two parts that were causing recurring pain — the shared file store and the reporting workload — and left the application code itself substantially as we found it, which was the agreed constraint from the outset.
Risk had accumulated quietly rather than arrived as a crisis. The server was out of vendor support, and a power supply failure three years earlier had already taken the system down for the better part of two days while a replacement part was sourced. Backups ran nightly to an external drive that a supervisor carried home once a week; nobody had ever restored from one, so nobody knew whether the backups contained a usable database or how long a restore would take. Recovery objectives were not written down anywhere.
Everything else followed from having one machine. Without a test environment, every change was a live change, so changes were deferred, and deferral meant that framework and security updates had not been applied for several years. Remote access for the few staff who worked from home used an unmanaged virtual private network terminated on a consumer-grade router. Reporting queries ran against the same database the factory floor was writing to, and month-end reporting regularly slowed order entry to a crawl.
There was no budget and no appetite for a rewrite, and that was the right call. The application encoded fifteen years of accumulated process knowledge, and replacing it would have been a multi-year programme with a far worse risk profile than moving it. Our scope was therefore the platform, not the code: the application had to keep behaving exactly as it did, including its quirks.
A perpetual licence pinned the database to a specific SQL Server version, which ruled out a managed engine on a newer major version and narrowed the target to an edition and compatibility level that would accept the existing database without modification. The factory floor needed the system available throughout production hours, which meant no change activity between 06:00 and 18:00 AWST and a hard stop on anything that could interrupt order entry. The site's only internet link was a single business-grade connection that dropped several times a month, so any design that assumed constant connectivity to the cloud was unacceptable. Customer and production data had to remain in Australia, and the operational technology network had to stay segmented from the corporate one.
We started with assessment rather than with infrastructure. Two weeks of dependency mapping produced an inventory of what the application actually touched: SQL Server, three file shares, two printer queues, a domain controller, an on-premise reporting service, and a scheduled job that wrote to a local disk path. Only after that inventory existed did we build anything, because the unknown dependencies were the reason previous attempts at documenting the system had stalled.
The rehost then ran in four stages. Stage one built the landing zone, network and identity in AWS from Terraform with nothing user-facing in it. Stage two stood up the database as a managed instance and rehearsed restores until the recovery time was measured rather than estimated. Stage three moved the application tier and ran it in parallel with the factory server for six weeks, reconciling order counts nightly. Stage four retired the old server after a final reconciliation and a signed-off cutover, then re-platformed the file store and reporting workload away from the application host so that neither could slow order entry again.
Licensing was the first obstacle. Moving to a managed database engine meant matching an edition that supported the features the application used and holding the compatibility level steady, because raising it would have changed query plans on a system with fifteen years of accumulated data and no test baseline to compare against. We verified feature usage by profiling a month of production queries before choosing the target, and we kept the compatibility level at its original value, which is a deliberate trade-off we documented for the client rather than a limitation we discovered later.
The application carried two dependencies that assumed a single machine. A hard-coded UNC path pointed at a share on the same server, so we fronted the file store with an SMB-compatible file service in AWS that answered on the same name and path, letting the application keep its assumption while the storage behind it became managed and replicated. A nightly batch job wrote intermediate files to a local disk and then read them back; we gave it a dedicated attached volume with the same drive letter rather than rewriting the job, and flagged the rewrite as follow-on work with a cost estimate.
Proving the recovery objective was its own exercise. Restoring a 214 GB database is not the slow part; making the application usable afterwards is. We scripted the full sequence — restore, log shipping catch-up, connection string switch, service start, smoke test of ten representative screens — and ran it quarterly, which turned an untested assumption into 4 hours and 10 minutes of measured time against an 8-hour target. For factory connectivity we placed a small read-through cache and a queued write path at the site, so a WAN dropout delays synchronisation instead of stopping order entry.
Stage three ran old and new side by side for six weeks. Both environments accepted production traffic in the sense that every order written to the factory server was replicated and compared, while a small group of volunteer users worked in the new environment for real. Each night a reconciliation job compared order counts, inventory movements and financial totals between the two, and any drift was investigated the next morning rather than at cutover.
The final cutover happened on a Saturday with a rollback point: the factory server stayed powered and untouched for a full week afterwards, so reversal was a DNS change rather than a restore. We published the sequence in advance — what would be checked, by whom, and at what time in AWST — and staffed the following Monday on site. The first fortnight used a short daily call; after that it moved to the normal support cadence. Operator training was deliberately small, because the screens were unchanged: the visible difference for most users was a new address and faster month-end.
The measurable change is in delivery and recovery rather than in headline cost. In the six months after cutover the client shipped 22 releases to the application, against a previous pattern of roughly one change every five to six weeks, because there is now a staging environment that matches production. The first test restore of the production database completed and passed a functional smoke test in 4 hours and 10 minutes. Unplanned outages attributable to the platform fell from nine in the preceding twelve months to one in the twelve months following.
On cost we prefer to be straight: monthly infrastructure spend is about 11 per cent lower than the fully loaded cost of running the old server, and the honest benefit is governance rather than savings. The client retired ageing hardware, stopped relying on a drive carried home each week, gained an environment where a change can be tested before it is applied, and now receives a monthly statement of what the platform costs and why. That is a defensible outcome. A migration sold purely as a cost reduction would not have been.
One thing went wrong, and it was a good thing it happened in rehearsal. The application authenticated against the on-premise domain controller, and in the first cutover rehearsal the application tier in AWS could not reach it — logins timed out and nothing else worked. We had mapped the file, database and print dependencies and assumed directory services would survive over the existing link; that assumption was wrong under load. We placed a read-only domain controller in AWS, made DNS site-aware, and added directory reachability to the dependency map as a first-class item. The rehearsal cost a weekend; the same omission on cutover Saturday would have cost a production week.
The screens did not change, which is exactly what we asked for. What changed is that we can test a change before we make it, and we know how long a restore takes because we have timed it.
Infrastructure is defined in Terraform with separate staging and production accounts, and the application is deployed from a pipeline rather than by copying files over a running system. Restore rehearsals run quarterly and the result is recorded against the agreed recovery target.
Migration work usually exposes what the old platform was hiding. These engagements started the same way — with a process that depended on one machine or one person — and are documented in the same detail. Request a quote if you would rather discuss your own environment first.
Scheduling, job capture and asset history built to replace paper dockets across a mobile workforce.
Fourteen fragile connectors replaced with one governed integration layer and reconciliation reporting.
Contract pricing, ordering and approvals moved out of a shared mailbox for a national industrial supplier.
Evidence collection and regulator-ready reporting for a WA resources services contractor.
A 45-minute scoping call, no obligation. We will tell you honestly whether a migration is the right next step.