Automating Drupal Deployments to Shared Hosting with GitHub Actions
A practical, Drupal-aware pipeline for promoting one tested commit through development, staging, and production on shared hosting.
Deploying a Drupal site to shared hosting does not require a bespoke platform, but it does require a disciplined release sequence. I built a GitHub Actions workflow for this portfolio that validates every promoted commit, connects to the host over SSH, updates the correct environment, and verifies the resulting site.
What the pipeline needs to guarantee
A useful deployment pipeline does more than copy files. It should prove that the selected commit meets project standards before it reaches a server, deploy the same commit through every environment, and fail loudly when the resulting Drupal site is unhealthy.
- Validate Composer metadata and install locked dependencies.
- Run Drupal coding-standard and PHP syntax checks.
- Map
develop,staging, andmainto isolated environments. - Use a dedicated SSH key stored as an encrypted Actions secret.
- Import configuration, rebuild and warm caches, and run deploy hooks.
- Request important public routes after deployment.
Promote one tested commit
The key design choice is promoting an exact commit rather than rebuilding a slightly different release for each environment. Development validates the change first. Staging exercises the same revision under production-like conditions. Production receives that identical revision only after both earlier deployments pass.
This makes the branch names useful release gates: develop deploys to dev, staging deploys to stage, and main deploys to production. GitHub Actions environments also make the destination visible in each run.
Keep secrets outside the repository
The workflow uses a dedicated Hostinger SSH key and a pinned known_hosts value. Password protection credentials for dev and staging are stored as repository secrets, never committed. Production needs no Basic Authentication secret because its public routes should be directly testable.
Use Drupal-aware release steps
After the server checkout is updated, the deployment creates a database backup, enables maintenance mode, checks for pending database updates, imports the repository-owned configuration, runs deploy hooks, rebuilds caches, and restores the site. A trap takes the site out of maintenance mode if a later command fails.
On this shared host, PHP disables proc_open, so Drush cannot safely orchestrate database updates. The pipeline therefore detects pending updates and stops before importing configuration. Database changes can then be handled deliberately instead of failing halfway through a release.
Verify the application, not just SSH
A successful SSH session only proves that a command ran. The health check confirms Drupal bootstraps, the database connects, no database updates remain, custom PHP files parse, and important routes return HTTP 200. It also checks for page-specific markers so an unrelated error page cannot pass by returning a successful status.