Last updated on 28th May 2026

Deploy PHP Applications with Deployer

This guide walks you through running Deployer deploys with DeployHQ's Custom Action protocol. Custom Actions execute commands inside a Docker container during your deployment pipeline, so you can run vendor/bin/dep deploy from DeployHQ instead of from a developer laptop.

Prerequisites

Before you begin, ensure you have:

  • A Deployer-managed PHP application: Your repository contains a deploy.php (or deploy.yaml) recipe and lists deployer/deployer in composer.json.
  • An SSH key authorised on the target hosts: Deployer connects from the container to your production servers over SSH. The container's ssh-agent is populated with your Project SSH key, so that key's public half must appear in the authorized_keys file of the deploy user on every target server.
  • Known Hosts for each target server: Configured under Project -> Build Configurations -> Known Hosts. Without these, strict host key checking is disabled, which is fine for an initial dry run but should be enabled before going to production.

How SSH Works Inside a Custom Action

When a Custom Action runs, DeployHQ loads two private keys into an ssh-agent on the build server and mounts the agent socket into the container at /tmp/ssh_agent_socket:

  • Your Project SSH key (the same one used to clone the repository from your SCM provider).
  • The DeployHQ default key (used internally).

The private keys are never written to the container's filesystem. The container only receives the agent socket, so your commands can call ssh, git, or dep and have authentication work transparently, but cannot read the key material directly.

Any Known Hosts configured on the project are written to a known_hosts file inside the container. If at least one Known Host exists, strict host key checking is enabled automatically.

Setting Up the Server

  1. Open your project in DeployHQ and navigate to Servers.
  2. Click New Server and select Custom Action as the protocol.
  3. Under Image Source, select Curated Template.
  4. Choose PHP + Deployer from the template dropdown. This sets the Docker image to php:8.3-cli.
  5. If your application targets a different PHP version, override the image with a matching tag, for example php:8.2-cli or php:7.4-cli.
  6. Enter your Deployer commands in the Commands field. A typical configuration looks like this:
   cd /data && composer install --no-dev --optimize-autoloader
   cd /data && vendor/bin/dep deploy production --revision=%endrev%
  1. Leave Halt on error enabled so the deployment is marked failed if Deployer returns a non-zero exit code.
  2. Click Create Server.

Adding Known Hosts

For every host Deployer will connect to, capture its SSH host key and add it to the project's Known Hosts:

ssh-keyscan -H app-01.example.com >> known_hosts.txt

Open the contents of known_hosts.txt, paste the line into Project -> Build Configurations -> Known Hosts, and save. Repeat for each target server. DeployHQ enables strict host key checking automatically once any Known Hosts are configured.

Authorising the Deploy Key

Deployer needs the deploy user on each target host to accept connections from the Project SSH key:

  1. In DeployHQ, open Project -> Repository and copy the Public Key shown on that page.
  2. On each target server, append it to ~deploy/.ssh/authorized_keys (or whichever user Deployer uses).
  3. Verify by running ssh deploy@app-01.example.com 'echo ok' from a server with access to the key. Authentication should succeed without a prompt.

The Project SSH key is shared between SCM access and Deployer deploys. Rotating it rotates both. Plan rotations accordingly.

Example Configurations

Standard Laravel Deploy

cd /data && composer install --no-dev --optimize-autoloader
cd /data && vendor/bin/dep deploy production

Targeting a Specific Branch

cd /data && composer install --no-dev --optimize-autoloader
cd /data && vendor/bin/dep deploy production --branch=%branch% --revision=%endrev%

%branch% and %endrev% are expanded by DeployHQ before the command runs. The full list of supported variables is in the text variables reference.

Multi-Stage Deploys

Create one Custom Action server per stage and set its name to match your Deployer host alias:

  • Server Staging with command vendor/bin/dep deploy staging
  • Server Production with command vendor/bin/dep deploy production

Deploy each server from its own auto-deploy branch to wire up environment-specific releases.

Installing PHP Extensions

The default php:8.3-cli image is minimal. If your composer.json requires extensions such as pdo_mysql, gd, or intl, add an install step before composer runs:

docker-php-ext-install pdo_mysql
cd /data && composer install --no-dev --optimize-autoloader
cd /data && vendor/bin/dep deploy production

For repeated deploys, save build time by baking required extensions into a custom Docker image and selecting it under Image Source -> Custom Docker Image.

Troubleshooting

"Permission denied (publickey)":

  • Confirm the Project SSH public key is present in the deploy user's authorized_keys on every target host.
  • Run ssh-add -l as the first command in your Custom Action to verify the key is loaded inside the container.

"Host key verification failed":

  • Strict host key checking is enabled because at least one Known Host is configured. Add a Known Host entry for the host Deployer is trying to reach.

"Class 'Deployer\Deployer' not found":

  • Run composer install before invoking dep. The default template does this in the first command line.

"Deploy timed out":

  • Custom Actions have a 30-minute overall timeout. Multi-host Deployer recipes with asset builds can approach this limit. Move asset compilation into a build command before the Custom Action runs, or pre-bake your dependencies into a custom Docker image to skip the composer install step.

"docker-php-ext-install: command not found":

  • You overrode the image with one that is not based on the official php image. Either revert to the official tag or install extensions using the new image's package manager.