
September 12, 2026
14 min read
By Kokil Thapa | Last reviewed: September 2026
Immutable vs mutable infrastructure is the choice between replacing whole servers or containers from a known build, and logging into live boxes to patch packages by hand. That split sounds academic until a production Laravel app behaves differently on staging and live because someone ran apt upgrade on one server three months ago. On real client projects I have maintained since 2010, the teams that win treat servers as cattle in immutable patterns, or they document every mutable change and accept drift as a cost. This guide compares both models with commands, trade-offs, and patterns you can apply on Ubuntu, EC2, and typical PHP-FPM stacks today.
The practical starting point for many PHP shops is not Kubernetes. It is a single EC2 instance, Apache or Nginx, PHP-FPM 8.3 or 8.4, and a Git-based deploy. Whether that deploy is immutable infrastructure built from golden images or a mutable symlink swap depends on team size, release frequency, and how much drift you can tolerate. Read on for a side-by-side comparison, then a decision path you can act on this week.
What is the difference between immutable and mutable infrastructure?
Mutable infrastructure treats each server as a long-lived pet. You SSH in, install packages, edit config files, and restart services. The machine accumulates history. Immutable infrastructure treats each deploy unit as disposable. You build once, promote the artifact, and replace the running instance rather than patching it.
Both models can coexist. A mutable base OS image might boot from cloud-init, then an immutable application layer ships as a container or tarball. The label applies to the layer you are changing, not the entire stack.
Infrastructure as Code (IaC) helps both sides. Terraform or Bicep can declare desired cloud resources. Chef, Ansible, or shell scripts can enforce mutable state. Packer and container builds produce immutable artifacts. The mistake is assuming IaC alone makes you immutable. Running ansible-playbook against the same server for three years is still mutable unless you rebuild the host from scratch on every change.
Core terms you will hear in production
- Golden image — a tested AMI, VM template, or container base built by Packer or a CI pipeline.
- Configuration drift — when live servers diverge from documented intent.
- Phoenix server — destroy and recreate instead of repair.
- Blue/green or rolling replace — traffic moves to new instances while old ones retire.
How does mutable infrastructure cause drift in production?
Drift is the silent tax on mutable infrastructure. Server A and Server B both run Laravel 12 on PHP 8.3. One had OpenSSL patched manually after a CVE alert. The other did not. A queue worker on the second box now fails TLS to a payment API. You spend an afternoon diffing packages instead of shipping features.
I have seen this on shared EC2 hosts that run multiple legal-tech portals under one Apache vhost layout. A quick pecl install on one site’s troubleshooting session changed the global PHP module load order. Another site broke until we traced the shared php.ini chain.
Mutable workflows still dominate small teams because they feel fast. SSH plus apt install redis-server takes minutes. Standing up Packer, an AMI pipeline, and autoscaling groups takes days or weeks. For a single-server Laravel shop billing Rs 15,000/month (~USD 112) on hosting, full immutability at the VM layer is often overkill. Application-level immutability through release directories is enough.
Signs your mutable servers need a reset
dpkg -loutput differs between staging and production for the same role.- Nobody can list every manual change from the last year.
- Disaster recovery means “find the backup” rather than “run Terraform apply.”
- Security patches land on some nodes but not others during busy weeks.
When drift crosses that threshold, Linux system administration work shifts from firefighting to reprovisioning. That is the inflection point where immutable patterns pay back the upfront cost.
How does immutable infrastructure work in practice?
Immutable infrastructure follows a build-release-run loop described in the Twelve-Factor App build-release-run model. You separate the build stage (compile assets, run tests, bake an image) from the release stage (tag artifact v2026.09.11) from the run stage (launch instances from that tag only).
On AWS, a common pattern is: Packer builds an AMI with PHP 8.5, Nginx, and hardening applied. Terraform launches an Auto Scaling Group from that AMI. User data or cloud-init pulls the latest application release artifact from S3 or a container registry. When PHP minor versions change, you bump the Packer template, build ami-NEW, update the launch template, and roll instances. You do not apt-upgrade running boxes.
The HashiCorp Packer documentation describes image builders for AWS, Azure, GCP, and Docker. A minimal Packer template for Ubuntu 24.04 might install PHP-FPM and harden SSH. That image becomes the only approved way to spawn app servers.
Containers push immutability further. A Docker image digest is immutable by design. Kubernetes replaces pods rather than exec-ing package installs inside them. For Laravel 13 on PHP 8.3+, a Dockerfile that runs composer install --no-dev and bakes config cache into the image gives you predictable runtime. Stateful data belongs in MySQL 9.7 or PostgreSQL 18, Redis 8.10, or object storage — never inside the container filesystem you treat as ephemeral.
Laravel on a single VM: immutable releases without replacing the OS
Not every project needs new AMIs per deploy. Deployer 7 on a persistent EC2 box is a hybrid that works well for sites like Adventure Third Pole Trek and sister legal-tech portals I maintain on shared infrastructure. The OS layer stays mutable. The application layer is immutable per release.
# deploy.php (Deployer 7)
set('repository', 'git@gitlab.com:org/booking-app.git');
set('shared_dirs', ['storage']);
set('shared_files', ['.env']);
set('writable_dirs', ['storage', 'bootstrap/cache']);
task('deploy', [
'deploy:prepare',
'deploy:vendors',
'artisan:storage:link',
'artisan:config:cache',
'artisan:route:cache',
'artisan:view:cache',
'deploy:publish',
'php-fpm:reload',
]);
Each deploy creates releases/202609111430 with a fresh vendor/ tree. The current symlink swaps atomically. Rollback is dep rollback — point the symlink at the previous release folder. That is immutable application deployment on a mutable host. It satisfies idempotent infrastructure principles at the code layer even when the kernel packages were upgraded manually last month.
GitLab CI builds frontend assets with Node.js 26 LTS locally or in CI, commits or uploads artifacts, then triggers Deployer. The server never runs npm in production. That separation mirrors immutable build discipline without container orchestration overhead.
Immutable vs mutable infrastructure: which should you choose?
There is no universal winner. The right model depends on scale, compliance needs, team skills, and how painful your last drift incident was. Use the table below as a scoring sheet, not a verdict from a vendor slide deck.
| Criteria | Mutable infrastructure | Immutable infrastructure |
|---|---|---|
| Initial setup time | Hours — SSH and scripts | Days to weeks — Packer, IaC, CI pipelines |
| Drift risk | High without strict discipline | Low at the replaced layer |
| Rollback speed | Depends on backups and config snapshots | Fast — redeploy previous artifact or AMI |
| Cost at small scale | Lower — one VPS, manual ops | Higher — build pipelines, registries, more moving parts |
| Security patching | In-place apt/dnf on each server | Rebuild image, roll fleet; no partial patch state |
| Best fit | Legacy PHP, shared hosting, solo maintainer | Multi-node fleets, regulated workloads, frequent releases |
| Laravel example | SSH + manual Composer on live docroot | Deployer releases, Docker, or AMI + ASG |
For Nepal-based SMB sites — law firm portals, WooCommerce 11.1 shops, booking engines — mutable OS with immutable app releases is the sweet spot I use most often. Full VM immutability makes sense when you run multiple identical nodes behind a load balancer or need SOC-style audit trails of every system state.
Declarative vs imperative infrastructure cuts across both columns. Terraform is declarative; Ansible can be imperative playbooks against mutable hosts. GitOps pushes immutability by making Git the source of truth for desired cluster state. Chef and Puppet historically targeted mutable convergence. Know which layer each tool manages before you label the stack “immutable.”
What are common mistakes when mixing immutable and mutable patterns?
The worst outcome is pretending you are immutable while still SSH-ing hotfixes onto live AMIs. Teams bake golden images, then log in to “just tweak this one nginx rule.” Six months later the launch template says one thing and production behaves another. If you allow mutable exceptions, log them in IaC within 24 hours or rebuild the image.
Another mistake is storing uploaded files on the local disk of disposable instances. Laravel storage/app on a phoenix server disappears when the VM dies. Use S3-compatible object storage or a shared NFS/EFS mount. Spatie Media Library works well when the disk driver points at cloud storage, not local on a cattle node.
Stateful sessions on local filesystems break rolling replaces too. Move sessions to Redis 8.10 or database-backed drivers before you adopt autoscaling. I standardize on Redis for Laravel queue and session on any site heading toward multiple nodes.
Mutable patterns that still make sense in 2026
- Managed databases — RDS, Cloud SQL, or a dedicated MySQL 8.4 LTS box you patch on a schedule.
- Developer laptops and local Docker Compose stacks.
- Short-lived staging VMs rebuilt weekly from the same Packer template as production.
- Legacy WordPress 7.1 on shared cPanel where you cannot replace the host.
Chef and similar config management remain valid for mutable convergence when immutability is not yet funded. The goal is documented, repeatable change — not ideology.
How do you migrate from mutable servers to immutable releases?
Migration should be incremental. Big-bang “containerize everything this sprint” fails on active client portals with payment webhooks and uploaded legal documents. Start where risk is lowest and value is highest.
- Inventory drift. Run the same package list and PHP module check on staging and production. Save output to a repo. Use a JSON formatter to diff CI artifacts if you export config as JSON.
- Externalize state. Move sessions, caches, queues, and uploads off the VM disk before you automate replacement.
- Immutable app deploys. Adopt Deployer or GitLab CI symlink releases even on one server. Stop editing
/var/www/htmldirectly. - Document the OS baseline. Capture a Packer template or Ansible role that reproduces today’s working server. Rebuild staging from it and run your test suite.
- Roll production. Schedule a maintenance window or use zero-downtime infrastructure updates with a second node and load balancer if traffic demands it.
Sister sites on my shared Deployer pipeline — including Notary Kathmandu and related legal-tech properties — share CI patterns but separate release folders per domain. That limits blast radius when one deploy misconfigures .env caching.
For larger rewrites, enterprise application development engagements often include an infrastructure phase: Terraform modules, Packer pipelines, and runbooks before feature sprints resume. Terraform for IaC declares the replaceable compute layer while RDS handles mutable database patching on AWS’s schedule.
AWS publishes a clear framing of replace-over-repair in their immutable infrastructure whitepaper. It aligns with how Auto Scaling Groups and CodeDeploy hook into new launch templates rather than patching instances individually.
Monitoring and proof both models work
Immutable stacks still need mutable-adjacent observability. Log shipping, APM, and disk alerts do not care which philosophy you chose. After each roll, verify health endpoints, queue depth, and payment callback success rates. On mutable boxes, add a weekly cron that diffs installed packages against a golden manifest and alerts on mismatch.
Testing and optimization should include infrastructure tests: Terratest for Terraform modules, smoke tests after Deployer publish, and canary traffic if you run two ASG versions. Support and maintenance retainers then cover image rebuilds for CVE response instead of emergency SSH marathons.
If you are building greenfield APIs on Laravel 13 with horizontal scale in mind, pair immutable containers with API development practices: versioned endpoints, idempotent webhooks, and stateless workers. The application design and the infrastructure model should agree that nothing important lives on local disk.
Key Takeaways
- Immutable vs mutable infrastructure is a per-layer choice: OS, platform, and application can use different models on the same project.
- Mutable servers drift; immutable artifacts roll back cleanly because version tags and AMIs are the source of truth.
- Single-server Laravel shops get 80% of the benefit from immutable Deployer releases without rebuilding AMIs every week.
- Externalize sessions, uploads, and queues before you treat compute as disposable cattle.
- Document every manual SSH change or rebuild from Packer — half-immutable stacks fail audits and incident response.
- Scale and compliance drive full immutability; budget and team size drive sensible hybrid patterns.
People Also Ask
Is Docker immutable infrastructure?
Docker images are immutable at the digest level: once built and pushed, that layer stack does not change. Running containers are still mutable if you exec in and install packages. Production best practice is to rebuild the image and redeploy pods or containers rather than patching running instances.
Can you use Ansible with immutable infrastructure?
Yes, but the role shifts. Ansible provisions the initial Packer build or bootstraps cloud-init on first launch. It should not repeatedly converge live production servers unless you accept mutable drift. Some teams use Ansible once inside Packer, then never against running app nodes.
What is the opposite of immutable infrastructure?
Mutable infrastructure is the direct opposite: long-lived servers modified in place through SSH, package managers, and manual config edits. Configuration management tools can reduce chaos but still target changing servers rather than replacing them.
Does immutable infrastructure cost more?
Upfront tooling and CI time cost more. At scale, immutability often saves money by cutting incident hours, shortening rollbacks, and enabling smaller ops teams. On one cheap VPS, mutable management stays cheaper until drift or downtime exceeds roughly one day of engineer time per quarter.
Pick the model your team will actually maintain
Immutable vs mutable infrastructure is not a purity test. It is a bet on how much drift and downtime your business can absorb. I default to immutable application releases with Deployer and GitLab CI on PHP stacks, then add golden AMIs or containers when node count or compliance pressure demands it. If your production servers have untracked manual history, start by inventorying drift and externalizing state — not by buying a Kubernetes cluster.
Need help designing deploy pipelines, Packer templates, or a migration path for an existing Laravel or WordPress estate? Review the Court Marriage In Nepal and other portfolio projects for patterns in production, browse related posts on the blog, or contact us to discuss web development and infrastructure for your next release cycle. For background on who maintains these stacks, see about me or return to the homepage.
Frequently Asked Questions
0 Comments
Leave a comment
Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

