Skip to content
Now building for 2026 — tell us what your team needs. Start a project
Sembosi Digital Sembosi Digital

Deploying a PHP Application to cPanel Without Downtime

Hosting 2 min read
Deploying a PHP Application to cPanel Without Downtime

Shared hosting is still where a lot of business software lives. Here is the deployment routine that keeps sites online during releases.

Plenty of small and medium businesses run on shared hosting with cPanel, and that is not going to change overnight. The challenge is deploying updates without taking the site offline or, worse, leaving a half-updated application behind.

The problem with uploading over live files

Copying files directly into public_html means visitors can load a page that mixes new templates with old code. If your release includes a database migration, the window where old code meets a new schema is exactly when things break.

The release-directory approach

Keep releases outside the document root and swap a symlink:

/home/user/
├── apps/
│   ├── releases/
│   │   ├── 2026-09-14-1015/
│   │   └── 2026-10-02-0940/
│   └── current -> releases/2026-10-02-0940
└── public_html -> apps/current/public

Upload the new version to a fresh release directory, then flip the symlink. The switch is atomic, so no request ever sees a mixed state.

ln -sfn /home/user/apps/releases/2026-10-02-0940 /home/user/apps/current-new
mv -T /home/user/apps/current-new /home/user/apps/current

Make the application environment-aware

Never commit .env files or credentials into a release. Keep one configuration file outside the web root and symlink it in during release:

ln -sfn /home/user/apps/shared/.env /home/user/apps/current/.env

Run migrations before flipping the link

Order matters: migrate the database first, then switch traffic. For zero-downtime schema changes, add columns as nullable with defaults, deploy the code that uses them, backfill in batches, and only then enforce constraints.

ALTER TABLE invoices ADD COLUMN reference VARCHAR(40) NULL;

Put the site into maintenance mode for the migration window

Most releases do not need it, but migrations do. Serve a static maintenance page from the web server level, allow your own IP, and keep it short.

# .htaccess
RewriteEngine On
RewriteCond %{REMOTE_ADDR} !^203\.0\.113\.10$
RewriteCond %{REQUEST_URI} !maintenance\.html$
RewriteRule .* /maintenance.html [R=503,L]

Keep the last three releases

If a release misbehaves, flipping the symlink back is a ten-second rollback — provided the previous release directory is still there.

Automate it

All of this can run from a Git post-receive hook or a small deploy script over SSH. The routine is: fetch, install dependencies, run migrations, warm caches, flip the symlink, restart queues, health-check, and roll back automatically if the health check fails.

Deployment should be the least exciting part of your week. When it is boring, it is working.