Laravel upgrades · deploy pipelines · maintenance
Upgrade your old Laravel app without breaking production
Still on Laravel 8, or 5, on a server nobody wants to touch, deployed by uploading files? I bring it to a supported Laravel and PHP version in small, tested steps, replace manual uploads with a deploy pipeline, and keep it patched afterwards if you want.
"require": { "php": "^8.3", "laravel/framework": "^13.0" }
Upgrade path
- 7 → 8PHP 7.3 · tests · staging
- 8 → 9PHP 8.0 · tests · staging
- 9 → 10PHP 8.1 · tests · staging
- 10 → 11PHP 8.2 · tests · staging
- 11 → 12PHP 8.2 · tests · staging
- 12 → 13PHP 8.3 · tests · staging
- 2 years
- of security fixes for each Laravel release. After that, none.
- 7 → 10
- Odigix's original admin panel, upgraded across three majors
- 10 → 13
- Odigix's main Laravel app, now on the current release
Sound familiar?
Most teams don't skip upgrades on purpose. The app works, every release adds another reason to wait, and after a few years the gap feels too big to cross.
- composer.json still asks for Laravel 8, or 5.x.
- The server runs PHP 7.4 or 8.0, because nobody wants to find out what breaks on a newer one.
- Deploying means uploading files over FTP, or logging in over SSH to run git pull.
- There are no tests, or none that run before a release.
- composer update has been off-limits for years: one outdated package blocks the next.
- Only one person knows how to set the project up, and they're busy or gone.
- A customer's security questionnaire asks which versions you run, and the honest answer is awkward.
- The server's operating system is past its own support date.
Where your version stands
Laravel gives each major release 18 months of bug fixes and two years of security fixes. PHP gives each branch two years of active support and two more of security fixes. After that, a vulnerability found tomorrow stays open in your version, and the packages you depend on drop it too.
Laravel
- 5.5 LTSEnd of lifeNo fixes since Aug 2020
- 5.8End of lifeNo fixes since Feb 2020
- 6 LTSEnd of lifeNo fixes since Sep 2022
- 7End of lifeNo fixes since Mar 2021
- 8End of lifeNo fixes since Jan 2023
- 9End of lifeNo fixes since Feb 2024
- 10End of lifeNo fixes since Feb 2025
- 11End of lifeNo fixes since Mar 2026
- 12Security onlySecurity fixes until Feb 2027
- 13SupportedSecurity fixes until Mar 2028
PHP
- 7.2End of lifeNo fixes since Nov 2020
- 7.3End of lifeNo fixes since Dec 2021
- 7.4End of lifeNo fixes since Nov 2022
- 8.0End of lifeNo fixes since Nov 2023
- 8.1End of lifeNo fixes since Dec 2025
- 8.2Security onlySecurity fixes until Dec 2026
- 8.3Security onlySecurity fixes until Dec 2027
- 8.4SupportedSecurity fixes until Dec 2028
- 8.5SupportedSecurity fixes until Dec 2029
What running an unsupported version risks
These aren't hypotheticals. Each one hit apps on old or misconfigured Laravel and PHP, and three of the four are in CISA's catalogue of vulnerabilities exploited in the wild.
- CVE-2018-15133Exploited in the wild
A leaked APP_KEY turns a cookie into code execution
Old Laravel versions decrypted and unserialized the X-XSRF-TOKEN cookie, so anyone holding the app's key could run code on the server. In January 2024, CISA and the FBI named it in their advisory on Androxgh0st, a botnet that scans for exposed Laravel .env files to steal credentials.
Affects Laravel up to 5.5.40 and 5.6.x up to 5.6.29.
cisa.gov - CVE-2021-3129Exploited in the wild
Debug mode left on in production
Ignition, the error page that shipped with Laravel 6 to 8, let an unauthenticated visitor write and run code on the server when APP_DEBUG was on. It's in CISA's catalogue of vulnerabilities known to be exploited.
Affects Ignition before 2.5.2 with debug mode enabled.
nvd.nist.gov - CVE-2024-4577Used by ransomware
A PHP flaw that old branches never got a fix for
A critical (CVSS 9.8) argument-injection bug in PHP-CGI on Windows. Patches shipped for PHP 8.1, 8.2 and 8.3 in June 2024. PHP 8.0, 7 and 5 were already end of life, so they never got one: the only real fix was to upgrade.
Affects PHP-CGI on Windows: 8.1 before 8.1.29, 8.2 before 8.2.20, 8.3 before 8.3.8, and every end-of-life branch.
devco.re - CVE-2024-52301
The fix exists, if you can install it
With PHP's register_argc_argv setting on, a crafted query string could change which environment Laravel boots in. Laravel patched every branch back to 6, but a patch only helps if composer update runs cleanly on your project, and that's exactly what stalls on old codebases.
Affects Laravel below 6.20.45, 7.30.7, 8.83.28, 9.52.17, 10.48.23 and 11.31.0.
github.com
How the upgrade works
Upgrades go wrong when they're done in one jump, without tests, straight on production. This process avoids all three.
- 01
A free call
You tell me what the app does, where it runs, how it gets deployed and what worries you about it. If I'm not the right fit, I'll say so on the call.
You getAn honest first read, and a short list of what I need to quote.
- 02
A read-only look at the code
I go through composer.json and the lock file, the PHP and server versions, abandoned packages, custom code that reaches into framework internals, the tests, and how deploys happen today.
You getA written upgrade plan (target versions, the path there, packages to replace, risks) and a fixed quote.
- 03
A safety net before any change
The project runs from a clean checkout on a staging server. I add tests around the flows that make you money (sign-up, login, checkout, billing, the jobs that run at night) so we agree on what "still works" means.
You getA staging environment and tests you keep, whatever happens next.
- 04
One major version at a time
Laravel 7 → 8 → 9 → 10, not one big jump. Each step is its own pull request: framework, PHP version, packages and deprecated APIs, tests passing, deployed to staging for you to click through. Coding agents do much of the mechanical rewriting; I review every change before it merges.
You getSmall, reviewable pull requests and a working app at every step.
- 05
A deploy pipeline instead of FTP
GitHub Actions runs the tests on every push and deploys to your server: a new release folder, dependencies, migrations and caches, then a symlink switch, so visitors never see a half-uploaded app. Rolling back means pointing the symlink at the previous release. If the server is too old to run a supported PHP, I set up a new one and move the app rather than patch it in place.
You getDeploys that take minutes, can be undone, and don't depend on one person's laptop.
- 06
Go-live with a way back
Production switches over at a low-traffic time you choose, after a verified database backup and a rehearsed rollback. I watch errors and queues closely in the days after.
You getYour app on a supported Laravel and PHP version, in production.
- 07
Handover, or I keep it patched
You get a README that covers setup, deploys and rollbacks, so any developer can pick the project up. Or I stay on: monthly dependency and security updates, watching advisories for your versions, and the next major upgrade when it ships.
You getA project anyone can maintain, or someone already maintaining it.
What I need from you, and when
Access grows with the work: read-only to quote, more only when a step needs it.
- Code repository
- Read access to quote. Then a collaborator account: I work on branches and open pull requests, and never push straight to your main branch.
- From the code review
- Environment config
- The list of variable names in .env, not the values. Real secrets live only on the servers, never in chat or in the repository.
- From the code review
- A copy of the data
- An anonymized database dump, or a read-only database user, to test migrations against real data shapes.
- Before upgrading
- Staging server
- A small server for staging: one you already have, or one I set up on your hosting account.
- Safety net step
- Production server
- A dedicated SSH user with my key for the pipeline and the go-live, not your root password. Removed at handover unless I'm maintaining the app.
- Pipeline and go-live
- Third-party services
- Only the ones the upgrade touches (payments, mail, storage), with test-mode keys or a read-only seat where possible.
- If needed
- Someone who knows the app
- An hour or two to list what must never break, then a click-through on staging before each release.
- Throughout
How access is handled
- Accounts in my own name, so every action is traceable and you can revoke it.
- SSH keys, not shared passwords. Secrets go through a password manager share, never chat.
- Nothing irreversible in production without your go-ahead: no data deletion, no deploy outside the agreed window.
- An NDA before I see the code, if you need one.
Upgrades I've done
The same process, on real codebases.
- 7→10Odigix admin panelThe platform's original Laravel admin panel, upgraded across three major versions.
- 10→13Odigix main appThe Laravel backend behind odigix.com and its 30,000+ registered users, brought to the current release.
- 6–7→SupportedClient codebasesClient apps from the Laravel 6 and 7 era, brought to supported versions. Client names stay private.
Questions clients ask
How long does an upgrade take?
It depends on how far behind the app is, how many packages need replacing and whether there are tests to lean on. The written plan after the code review gives you the steps and a timeline before you commit to anything.
Can we keep shipping features during the upgrade?
Yes. The upgrade lives on its own branches and merges one major version at a time, so your team keeps working as usual. I keep the upgrade branch in sync with your changes as I go.
What does it cost?
A fixed price, quoted after the free call and a read-only look at the code, not an hourly meter. It depends on the size of the gap, so prices aren't listed here.
Do you need access to our production server?
Not to quote. Production access is only needed to set up the deploy pipeline and for the go-live, through a dedicated SSH user that you create and can remove.
What if a package we depend on is abandoned?
I find a maintained replacement, or move the small part you actually use into the app, and you decide before anything changes. It's listed in the plan up front, not discovered halfway through.
Do you maintain the app afterwards?
If you want. Monthly dependency and security updates, watching advisories for the versions you run, and the next major upgrade when it ships, while the gap is still small. Maintenance is quoted per project.
Building something similar?
Tell me where you are and what's blocking you. I'll give you an honest read on how I'd approach it.