Can a managed PaaS cost less than a VPS while cutting nights and weekends on-call? For legacy PHP monoliths under 100k requests per month, the true expense is engineering time and patch work. The single deciding factor is the tradeoff between ops hours and platform limits.
Whether to migrate a legacy PHP app to PaaS or keep it on a VPS depends on control, costs, and traffic. PaaS cuts ops work and auto-scales for variable loads. VPS often gives lower baseline costs and full server control.
Choose migration when engineering hours and on-call frequency outweigh platform limits. Use buildpacks, Dockerfiles, CI scripts, and tested rollback recipes to make the move safe.
Factors that decide PaaS vs VPS for legacy PHP
This tradeoff determines the choice between ops hours and platform limits. If engineering time and on-call frequency cost more than replatforming, PaaS tends to pay back over 12 to 24 months.
Choose PaaS when ops tasks dominate and traffic varies. Choose VPS when strict control, very low latency needs, or unsupported extensions demand a full OS.
The most frequent error at this point is comparing only sticker prices and ignoring engineering hours and scaling events. That underestimates total cost for a VPS across 12 to 24 months.
What costs should be included?
Include hourly instance cost, managed database fees, bandwidth, backups, and storage. Add estimated engineering hours for patching, incident response, and scaling events.
Model three traffic patterns: steady low, variable, and spiky. Compute 12 and 24 month totals and then compare.
Which application traits block a painless PaaS
Check for writable local filesystem use, sticky sessions, local cron jobs, and custom PHP extensions. These traits usually need code changes or platform workarounds.
Many legacy apps assume local state. Plan two to twelve weeks of refactoring when the app writes files locally or uses file sessions.
PaaS is a strong choice for teams that value time over raw monthly cost. It cuts routine work and speeds recovery from incidents, but it forces architectural changes for local file access and background jobs. PaaS helps except when an app needs kernel tweaks, hardware features, or strict network rules that only VPS or IaaS can give.
Cost comparison by traffic pattern
Use a simple TCO model to compare PaaS and VPS under real traffic patterns. Assume an engineering hourly rate of $120 and include infra, managed DB, and ops hours in the model.
Example 12-month totals: Small steady load (10k requests per month): VPS infra $20 per month. Ops two hours per month gives 24 hours and $2,880. The VPS total equals $3,120. PaaS infra $40 per month. Ops one hour per month gives 12 hours and $1,440. The PaaS total equals $1,920.
Variable load (60k per month with daily swings): VPS infra $40 per month. Ops six hours per month gives 72 hours and $8,640. The VPS total equals $9,120. PaaS with autoscaling averages $90 per month. Ops two hours per month gives 24 hours and $2,880. The PaaS total equals $3,960.
Spiky pattern (baseline 20k per month, peaks to 200k per day): VPS often needs reserved capacity $80 per month. Ops twelve hours per month gives 144 hours and $17,280. The VPS total equals $18,240. PaaS handles spikes elastically and averages $220 per month. Ops three hours per month gives 36 hours and $4,320. The PaaS total equals $6,960.
These numbers show engineering time and scaling events often drive the decision. Plug real ops rates and infra quotes into the model to find break-even months.
A short example helps compare costs precisely.
When PaaS wins: variable or spiky traffic profiles
PaaS wins when traffic spikes are frequent and ops staff must scale manually on VPS. Autoscaling shortens time to capacity and cuts missed requests during peaks.
PaaS providers autoscale web processes and often include managed databases and load balancers. That removes manual provisioning and lowers incident toil.
Measured tests show cold starts can add a latency tail that affects p95 and p99 more than p50. Exact values vary by provider, instance type, warm pool size, and app init work.
Record the provider, region, instance class, and test harness when benchmarking. Present results as a range with methodology so readers can reproduce or compare numbers.
How does autoscaling affect costs and uptime?
Autoscaling raises short-term compute costs during peaks but avoids overprovisioning year-round. For variable traffic, PaaS can be cheaper across 12 months when ops time is counted.
PaaS SLAs include managed patching and health checks that improve uptime. Expect provider SLAs near 99.95 percent for web services, but verify each plan.
How do cold starts affect latency and user experience?
Cold starts create a latency tail that hits p95 and p99 metrics more than p50. Use warm pools, minimum instances, or provisioned concurrency when available.
For API endpoints with strict p99 SLAs, measure cold-start penalties on the chosen provider before scaling to zero.
When VPS wins: steady loads or strict control needs
VPS wins when load is predictable and full OS or network control is required. A reserved VPS often gives lower monthly cost for constant traffic.
If the app depends on custom PHP extensions, low-level networking, or hardware-bound tasks, VPS keeps those capabilities. VPS also avoids PaaS cold starts and opinionated runtime limits.
An anonymized example: a small ecommerce site with steady five requests per second and custom C extensions kept VPS. The site saved forty percent yearly versus PaaS after measuring engineering hours.
When do latency and consistency matter more than cost?
When p95 and p99 latency directly affect revenue, avoid platforms that add cold starts. Use a provisioned VPS or dedicated instances instead.
Reserved VPS plus tuned PHP-FPM and nginx often deliver stable p99 latency under 120 milliseconds for simple pages.
When are custom extensions or network rules required?
If the app requires uncommon PHP extensions, kernel modules, or specific iptables rules, a VPS is usually necessary. PaaS may not expose those capabilities.
Map required modules with php -m and verify provider support before choosing PaaS.
Common migration errors and runtime warnings for legacy PHP
The top runtime failure is assuming the filesystem is writable and persistent. Deploying unchanged code to PaaS often breaks uploads, caches, and temp files.
Another frequent mistake is redeploying without externalizing sessions or background jobs. That causes session loss and missing cron processing after the move.
Planning for these issues prevents most early migration failures.
What breaks most often during a PaaS move?
File uploads fail when code writes to local disk without using object storage. Session state resets when sessions stay file-based.
CRON jobs stop working when the platform does not run persistent background processes. Replace them with worker services or managed scheduled jobs.
How to avoid data loss during cutover?
Always create point-in-time backups and test restores before switching traffic. For databases, use logical dumps and rehearse replica promotion.
Perform schema changes as backward-compatible steps: add columns first, deploy, migrate data, then remove old code paths.
Technical compatibility checklist
Before replatforming, run a methodical compatibility checklist with scriptable commands. Confirm PHP version and SAPI using php -v and php -i.
List extensions with php -m and save the output to php_modules.txt. Search code for filesystem writes using grep to find file_put_contents, move_uploaded_file, or fopen.
Detect session storage with php -i or by inspecting ini files. Locate cron jobs and background calls with crontab -l and code grep searches.
Identify shell or exec usage by grepping for exec, shell_exec, or proc_open. Verify dependency handling: if no Composer build exists, ensure vendor is included or add a multi-stage Docker build.
Check for custom PHP extensions and plan container builds to compile them during image build if needed. For stateful paths, mark them for S3 or Cloud Storage migration.
For jobs, plan worker processes or provider scheduled jobs. Capture findings in a machine-readable migration checklist so CI can gate compatibility.
Provider migration recipes: heroku
Each provider has a preferred build and runtime model. Use provider buildpacks, Dockerfiles, or source-to-image based on app needs.
The table below compares a single VPS against four representative PaaS options. Add DigitalOcean App Platform or AWS Elastic Beanstalk rows if needed for your shortlist.
| Option |
Typical monthly cost |
Scaling model |
Control |
Ops hours estimate |
| VPS (small) |
$10–$40 |
Manual or custom autoscale |
Full OS and network |
4–6 hrs/week |
| Heroku (hobby/pro) |
$7–$100+ |
Dyno autoscale / manual |
Limited OS access |
1–3 hrs/week |
| Render |
$7–$80 |
Autoscale or manual |
Container access |
1–3 hrs/week |
| Fly.io |
$5–$200 |
VMs per region |
High control, fast network |
2–4 hrs/week |
| Platform.sh |
$50–$500 |
Branch-based deploys |
High control |
1–3 hrs/week |
Heroku recipe and commands.
Procfile
web: vendor/bin/heroku-php-apache2 public/
$ git push heroku main
$ heroku run php bin/console doctrine:migrations:migrate --app my-app
Dockerfile example for legacy PHP without Composer
FROM php:8.1-apache
RUN apt-get update && apt-get install -y libpng-dev libonig-dev zip unzip
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl
COPY . /var/www/html
RUN chown -R www-data:www-data /var/www/html
ENV APACHE_DOCUMENT_ROOT /var/www/html/public
Migration steps at a glance
Audit
Inventory PHP version, extensions, file usage, cron, sessions.
Refactor
Move uploads to S3, sessions to Redis, cron to worker.
Test
Deploy to staging, run synthetic and load tests, compare latency.
Cutover
Blue/green with short TTL and DB safe migrations.
Heroku buildpacks, Render builds, Fly.io Docker images, and Platform.sh environments handle runtime differently. The infographic above shows the common path: audit, refactor, test, cutover. Use it as a checklist for a small pilot before full migration.
Additional provider notes: verify extension lists on each platform and confirm persistent storage options for session or cache.
For PHP usage statistics and version adoption details, refer to the PHP Group and W3Techs market survey for context. W3Techs: PHP usage
Practical migration recipe
For a practical legacy PHP migration, walk the pipeline with concrete commands. First inventory the runtime and dependencies using php -v and php -m.
Export a copy of composer vendor if present and rsync to staging. Convert uploads and public assets by syncing to object storage using the AWS CLI example shown.
Replace file-based sessions with Redis and set session.save_handler to redis and session.save_path accordingly. Build a Docker image and push it to your registry.
Deploy to a PaaS via the provider CLI. For a canary cutover use staged DNS TTL and an incremental traffic shift with smoke tests. These commands form an end-to-end migration path suitable for a one-pilot cycle.
A small staged pilot reduces surface area for issues.
Migration plan, blue/green, and rollback scripts
A safe migration follows audit, staging deploy, canary traffic, and blue/green cutover. Use Infrastructure as Code and a short TTL DNS during the cutover.
Always have automated backups and a tested restore plan before switching user traffic. Also test a rollback from staging to confirm procedures.
The step list below gives concrete commands and scripts for a standard PHP and MySQL app.
What are the exact cutover steps?
- Audit and inventory extensions: run php -v and php -m
- Add Redis and S3 support
- Build Docker image and push to registry
- Deploy green, run smoke tests, shift traffic incrementally
- Promote green to primary and retire old instances
How to handle DB migrations and rollback?
Use backward-compatible migrations. Deploy schema additive changes first, then deploy the app code that uses new fields.
Use point-in-time snapshots and a promoted read replica for rollback tests. Restore the latest logical backup if rollback is needed.
Example rollback script (logical undo) in bash:
bash
set -e
mysql -u$DB_USER -p$DB_PASS -h $DB_HOST $DB_NAME < /backups/latest.sql
heroku ps:restart -a my-app
Example GitHub Actions CI snippet to build, test, and push Docker image:
yaml
name: CI
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build and push
uses: docker/build-push-action@v4
with:
push: true
tags: user/app:latest
- name: Run smoke tests
run: curl -fsS ${{ secrets.STAGING_URL }}/health || exit 1
Next step before FAQ
If the team is ready to evaluate, run the compatibility checklist and deploy a small staging build on one PaaS provider. Measure cost and latency for a two-week pilot.
Do not prioritize PaaS if the app is tiny, static, extremely predictable, or if it needs hardware-specific networking or strict compliance features the PaaS cannot give. In those cases VPS or dedicated IaaS is the safer choice.
Frequently asked: hosting, VPS, and cloud comparisons
What is the difference between VPS and PaaS?
VPS is a virtual server that the team manages. PaaS is a managed runtime with build and deploy tools.
VPS gives full OS access and custom network control. PaaS removes much infrastructure maintenance by handling builds, scaling, and many ops tasks.
The team should list required OS-level features and compare them to provider limits before choosing.
Is VPS faster than PaaS for PHP pages?
Not always. It depends on tuning and traffic.
A tuned VPS can deliver steady low-latency p99 under 120 milliseconds for simple pages. PaaS may add cold-start latency but scales better under bursts.
Test representative requests and measure p50, p95, and p99 to decide which platform fits service needs.
How long does a typical migration take?
Expect two to twelve weeks for most legacy PHP apps. The range depends on writable FS, sessions, and cron replacements.
Simple apps without local state often migrate in two to four weeks. Allocate time for testing, a pilot, and a safe cutover window.
What hidden costs should be modelled?
Include engineering hours, on-call overhead, backup retention fees, managed DB costs, data egress, and third-party license fees. Over a 12 to 24 month model, these items often outweigh pure VM cost.
A clear 24 month TCO helps compare a $20 per month VPS with a $60 per month PaaS when ops hours are valued at $80 to $150 per hour.