Cloud & DevOps
Cloud & DevOps engineering on AWS, Google Cloud and Azure
This is the operational layer underneath an application: the servers it runs on, the pipeline that puts new code there, the alarms that tell a named person when something stops, and the backups you can prove still restore. We set that layer up, document it as code, and keep it uneventful.
What this service covers
- Cloud platforms: AWS, Google Cloud, Azure
- CI/CD pipelines: build, test, deploy and roll back
- Server optimization & monitoring: web server, PHP-FPM, database and cache tuning
- Alerting: metrics, logs and alerts that reach a person
- Backups: offsite, monitored and restore-tested
What a deployment pipeline removes
Most teams do not ask for a pipeline. They ask for relief from the three things a missing pipeline costs them: a release that involves dragging files into an FTP client and hoping nothing was missed, a bug that exists only on the server because an extension or an environment variable differs from the laptop it was written on, and an unwritten rule that nobody deploys on a Friday.
Those are one problem wearing three hats. Each is a symptom of the same thing: the steps between a finished commit and a running server live in somebody's head, and get performed slightly differently every time.
What runs on every push
Clean checkout
The commit is checked out on a fresh runner, so nothing quietly depends on a file left behind by the last build.
Install from the lock file
Dependencies come from the lock file rather than from whatever a cache happens to hold, so everyone gets the same versions.
Test, then build once
The suite runs and assets are compiled a single time. A failure here stops the release before it can reach a server.
Promote one artifact
The exact build that passed is the one that reaches the server. Nothing is compiled again in production, where it could come out different.
The point of a pipeline is where the failure happens. On a runner, minutes after the push, in front of the person who wrote it — rather than in production, hours later, in front of a customer. Release stops being an event that needs a calm afternoon and becomes something that can happen on a Tuesday morning, twice.
Two things decide whether that holds up. The test suite has to be trusted enough that a red build genuinely stops people, and secrets have to be injected at run time from a secret store rather than committed to the repository to make a build work.
Environments that tell you the truth
A staging environment is only useful if it is wrong in ways you already know about. If staging runs a different PHP or Node version, a different database engine, a different queue driver or a machine a tenth of the size, then a green result on staging proves very little.
We build staging from the same definition as production and let it differ on purpose, in a short written list rather than by accident.
| Aspect | Production | Staging |
|---|---|---|
| Machine size | Sized for real traffic | Smaller — enough to run the app, not to load-test it |
| Credentials | Live keys and live accounts | Sandbox or test-mode keys only |
| Data | Real customer data | A scrubbed copy, or generated data |
| Outbound mail and SMS | Delivered to customers | Caught by a single test inbox |
| Who can reach it | The public | Behind HTTP auth or an IP allowlist, and kept out of search results |
Everything else is held identical — runtime versions and extensions, cache and queue drivers, web server and PHP-FPM configuration, cron entries, and the deploy process itself. The point is that the release going to production has already been rehearsed on something that behaves like production.
Every unlisted difference is a place where a green staging run means nothing. Where one cannot be removed — a payment provider with no sandbox for a particular flow, an integration with hardware that exists in exactly one place — we say so and test that part deliberately in production behind a feature flag, rather than pretending staging covered it.
Infrastructure as code, and why click-configured servers rot
A server assembled by hand in a web console is a server nobody can rebuild. Which firewall rule was opened for that one payment integration, which cron entry was added at two in the morning, why the swap file is that size, which package was installed from a third-party repository — all of it lives in one person's memory and leaves when they do.
Cannot reproduce it quietly becomes cannot move it. Six months later nobody is willing to touch the machine, so it does not get patched, does not get resized, and does not get handed to the next person with any confidence.
We describe infrastructure in code instead: the cloud resources declared in version-controlled definition files, and provisioning scripts or images for what runs inside them. The environment becomes a file in your repository, reviewed like any other change, with a history that explains why each rule exists. Rebuilding a machine after an incident, adding a second one, or standing up a separate region for a client with data-residency obligations turns into an ordinary task rather than an archaeological dig.
On a small project this stays deliberately modest: one definition per environment, a variables file for the handful of things that differ, and a plan output reviewed in the pull request before anything is applied. You do not need a platform team to get the benefit.
Zero-downtime deploys, and a rollback you have actually used
Copying files into a directory that is currently being served creates a window in which half the old code and half the new code are live at the same time. We use atomic releases: the new build is prepared alongside the running one, and the switch is a symlink change followed by a reload, so requests already in flight finish on the old release and the next ones land on the new. Queue workers are restarted after the switch, not before, so no job is picked up by code that is about to disappear.
Rollback matters more than the deploy. Keeping the previous releases on disk makes reverting a matter of pointing the symlink back and reloading, which takes seconds.
The database is the harder half, because a migration that has already dropped a column cannot be undone by a symlink. Where it counts we separate schema changes from code changes, so the code can move backwards even when the schema cannot.
Atomic releases
Build prepared beside the live one; the cutover is a symlink switch and a reload.
Kept releases
Previous builds stay on disk, so reverting is a routine step rather than a rebuild.
Reversible migrations
Destructive schema changes are split across releases so code can roll back alone.
Worked example: retiring a column without a maintenance window
- Release one. Add the new column. Deploy code that still reads the old one but writes to both.
- Release two. Backfill the existing rows with a background job, in batches, while the site keeps serving.
- Release three. Switch reads to the new column. The old one is still populated, so this release can be reverted on its own.
- Release four. Once reverting is no longer plausible, drop the old column.
Four deploys instead of one, and at no point does a version of the code exist that cannot be reversed by pointing the symlink back. The cost is planning; the alternative is a restore while customers wait.
Monitoring, alerting and logs are three different jobs
They get sold as one word, and the difference shows up at the worst possible moment.
- Monitoring is the current state. CPU, memory, disk, queue depth, response times, certificate expiry, and whether the site answers at all from outside your own network.
- Logging is what happened. Application errors with stack traces and request context, web server access logs, slow query logs — retained long enough to investigate a problem that gets reported a week late.
- Alerting is the narrow part that interrupts a human being. It is the only one of the three that costs you something when it is wrong in either direction.
An alert nobody acts on is not monitoring — it is noise with a delivery mechanism. A channel full of routine warnings teaches everyone to swipe them away, and the one alert that mattered gets dismissed with the rest.
So we keep the alert set deliberately small and make each one answerable: it fires on a symptom a user would actually notice, it reaches a named person or an on-call rotation rather than a shared inbox, and it carries enough context — which host, which endpoint, which error, what changed recently — for someone to start work without opening five dashboards.
Anything that fires regularly and needs no action is either fixed or deleted, because leaving it there is worse than having no alert at all.
If you only ever have one check, make it an external one: a request to a real page, from outside your own network, on a short interval. An unreachable machine is in no position to report that it is unreachable, and an expired certificate or an edited DNS record looks perfectly healthy from the inside.
Backups that have been restored at least once
A backup nobody has restored is a belief, not a safeguard. They fail in dull, common ways:
- A job that has been erroring silently since a credential rotated, with nobody watching the job itself.
- A dump that captures the database but not the uploaded files.
- A snapshot schedule covering the boot volume but not the data volume that was attached later.
- A retention window shorter than the time it takes anyone to notice the corruption.
- An archive sitting on the same machine it was meant to protect.
We back up to storage separate from the server, monitor the backup job itself so a silent failure raises an alert like any other symptom, and restore into a scratch environment so two things are known rather than assumed: that the data comes back intact, and roughly how long a real recovery would take.
Two numbers decide what a backup is worth: how much data you can afford to lose, which is the gap between copies, and how long you can afford to be down while one is restored. Agree both before choosing a schedule. The schedule is the cheap part; the restore is not.
That second number is what turns a vague promise into a recovery time you can plan a business around, and it is usually the one nobody has measured.
One design point follows from it: ransomware and a table deleted by mistake are the same problem from the backup's point of view. Both need a copy the compromised account could not have written to — a separate credential without delete rights, and versioned storage where the provider offers it, rather than a nightly job holding full permissions over its own archive.
Autoscaling, and what it does not fix
Autoscaling adds and removes instances behind a load balancer as demand moves. It is the right answer for traffic that genuinely varies — a campaign, a seasonal peak, a service that is quiet overnight — and for surviving the loss of a single machine without anyone noticing.
It is an availability answer, not a performance one. A query with no index, an N+1 loop on a product listing or a report that reads an entire table stays exactly as slow on twenty instances as on one, and now you pay twenty times over to be slow.
It also assumes the application can scale horizontally at all. Sessions and uploaded files have to live somewhere shared rather than on local disk, scheduled tasks must not run once per instance, and the database has to absorb the extra connections that arrive with each new node.
We look at the profile before the instance count, and the cheaper answer is often an index, a cache and a queue — the application-side groundwork described on our web development page.
Cloud cost control
Cloud bills grow by accretion, and the usual sources are repetitive enough to check against a list:
- Instances sized for a launch spike that never came back down.
- Volumes and snapshots left behind by machines terminated months ago.
- Load balancers, NAT gateways and static addresses attached to nothing.
- Logs kept at full verbosity forever in the most expensive storage class.
- Egress — the charge for data leaving the provider, which hides well because no line on the invoice is named after the feature causing it.
Before any of that, one sanity check: open the provider's cost report grouped by service for the last three months and find the largest line. It is often not the one people assume, and tidying the small lines first is how a cost review ends up costing more in effort than it saves.
Then we tag resources so every line has an owner, right-size against measured usage rather than the original guess, apply lifecycle rules to logs, snapshots and backups, and put static assets behind a CDN so origin egress falls. Committed-use or reserved pricing comes last, once the shape of the usage is stable, because committing to the wrong size for a year is an expensive way to save money.
When moving off a single VPS is premature
There is a version of this work that costs more than it returns. One application with modest traffic, a single database and a handful of background jobs runs perfectly well on one well-configured virtual server that has backups, monitoring and a deployment pipeline.
Splitting it across a managed database, a managed cache, container orchestration, a message broker and a service mesh adds moving parts, a monthly bill and a category of failure that needs someone on hand who understands it.
What you accept in return is worth naming out loud: patching or rebooting that one machine is visible to users unless a window is planned, and recovery from its total loss is a rebuild plus a restore rather than a failover. If both are tolerable this year, the simpler setup is cheaper in money and in attention.
Managed services earn their place at identifiable moments: when losing the database would take longer to recover than the business can tolerate, when the server can no longer be patched or rebooted without visible downtime, when several teams need to deploy without queueing behind each other, or when a contract requires isolation and audit trails you cannot produce by hand.
A single server is often still the right answer. We are content to say so — and to build it so that the eventual move is a change to a definition file rather than a rewrite.
How we engage
Three ways this work usually starts
Review
We go through the servers, deploy process, backups, alerts and bill as they stand, and hand back a prioritized list with what each item would cost to fix. Quoted per project.
Build or migrate
New environments on AWS, Google Cloud or Azure, a CI/CD pipeline, infrastructure as code, or a planned move from an existing host with a rehearsed cutover. Quoted per project.
Ongoing care
Patching, certificate renewals, backup checks, alert triage and small changes. Our maintenance plans start at $49 per month; heavier retainers are quoted on scope.
What we need from you to start
None of it is unusual, but gathering it early is the difference between a review that moves and one that stalls waiting on access.
- Access you can revoke: a named user in the cloud console and an SSH key of our own, rather than a shared root login sent over email.
- The repository, and whoever deploys today: half an hour with the person who currently pushes to production usually explains more than the server does.
- Control of the domain and DNS: cutovers need record changes and a lowered TTL ahead of time, and that happens in your registrar account.
- Someone who can approve a downtime window: even a short one, and even if we end up not needing it.
- A list of what talks to the system from outside: payment webhooks, an accounting sync, a partner's IP allowlist. These are the things that break quietly after a move.
The same list works in reverse at the end of an engagement. We write down how the environment is deployed, patched and restored, walk somebody on your side through it, and ask you to remove our access — and nothing we build depends on an account of ours continuing to exist.
All prices in US dollars (USD). We can invoice in GBP, EUR, AUD or INR on request.
Working hours: Mon–Fri, 09:00–19:00 IST (UTC+5:30) — 4+ hours of live overlap with US Eastern; full overlap with UK and EU mornings.
Cloud & DevOps FAQs
Ping us about your infrastructure
Tell us what is running, and where it hurts
Send us the shape of the setup — cloud provider or bare server, how you deploy today, what wakes people up — and we will come back with what we would change first and what it would cost. If the honest answer is that your current server is fine, we will say so.
Related services
Web Development
Fast, scalable websites and web apps to develop web application solutions with Laravel, React and modern stacks.
Mobile App Development
Native and cross-platform iOS & Android apps built by the best app developers, with React Native and Flutter.
Custom Software
Custom software development for bespoke CRM, ERP and SaaS platforms, engineered around your exact workflow.