## Why HestiaCP + DeployHQ is a strong fit for agencies

If you run a web agency or freelance shop juggling a dozen WordPress, Laravel, or static PHP sites on a single VPS, [HestiaCP](https://hestiacp.com/) is one of the cleanest open-source alternatives to cPanel — free, scriptable, and resource-light enough to run on a 2-4 GB Linode. The catch most teams hit is deployment: HestiaCP gives you tidy per-site SFTP accounts, but no built-in pipeline to push commits from Git to the right `web/<domain>/public_html` directory automatically.

That is where [DeployHQ](https://www.deployhq.com) closes the loop. Connect a [GitHub](https://www.deployhq.com/deploy-from-github) or [GitLab](https://www.deployhq.com/deploy-from-gitlab) repository, point it at the HestiaCP-issued SFTP credentials, and every push to `main` ships only the changed files — no full re-uploads, no manual zip-and-drag, no shared logins floating around in 1Password. This guide walks through the exact configuration we use for agency clients running multi-tenant HestiaCP boxes on Linode, with the security hardening, build steps, and rollback strategy spelled out.

If you are weighing control panels, the companion post on [installing cPanel on AlmaLinux or Ubuntu](https://www.deployhq.com/blog/installing-cpanel-on-ubuntu-22-04-and-deployhq) covers the commercial alternative side-by-side. This guide assumes you have already chosen HestiaCP.

## Architecture at a glance

```
flowchart LR
    Dev[Developer] -->|git push| GH[GitHub / GitLab / Bitbucket]
    GH -->|webhook| DHQ[DeployHQ]
    DHQ -->|build pipeline:\ncomposer / npm / artisan| DHQ
    DHQ -->|SFTP changed files| Hestia[HestiaCP user web/site/public_html]
    Hestia --> Linode[Linode VPS Ubuntu 22.04 LTS]
```

Three things to internalise before you start:

1. **One SFTP user per site, never one per server.** HestiaCP makes this trivial; we will use it as the security boundary.
2. **DeployHQ uploads diffs, not full trees.** A 1,200-file Laravel app redeploys in seconds because only changed files cross the wire — only the changed paths are transferred over SFTP.
3. **Builds run on DeployHQ's infrastructure, not the VPS.** Composer, npm, Vite, and webpack all execute in DeployHQ's [build pipeline](https://www.deployhq.com/features/build-pipelines), so your Linode never installs Node or dev dependencies.

## Step 1 - Provision the Linode VPS

For most agency workloads the [Linode 4 GB shared CPU plan](https://www.linode.com/pricing/) (Nanode is too tight once HestiaCP, MariaDB, and PHP-FPM are running) on Ubuntu 22.04 LTS is the sweet spot. If you need a refresher on sizing, we covered the trade-offs in [Shared Hosting vs VPS for junior developers](https://www.deployhq.com/blog/shared-hosting-vs-vps-a-comprehensive-guide-for-junior-developers) and [What is a VPS?](https://www.deployhq.com/blog/vps-101-understanding-virtual-private-servers).

Provision the instance, point your DNS A record at the public IP, and SSH in as root before HestiaCP install:

```
# Quick hardening before HestiaCP installer runs
adduser deploy
usermod -aG sudo deploy
apt update && apt -y upgrade
ufw allow OpenSSH && ufw allow 'Nginx Full' && ufw enable
```

[DeployHQ](https://www.deployhq.com) also publishes a dedicated [Linode deployment guide](https://www.deployhq.com/guides/linode) if you want the platform-specific walkthrough — it covers Linode-side networking and StackScript provisioning that we will not duplicate here.

## Step 2 - Install HestiaCP

Follow the [official HestiaCP installation script](https://docs.hestiacp.com/getting_started/installation.html) — do not skip the `--apache no --proxy yes` flags if you want Nginx-only (lighter and what we recommend for static + PHP-FPM):

```
wget https://raw.githubusercontent.com/hestiacp/hestiacp/release/install/hst-install.sh
bash hst-install.sh --apache no --proxy yes --hostname panel.example.com \
  --email ops@example.com --password 'set-a-strong-one'
```

Reboot, log into `https://panel.example.com:8083`, and confirm the admin dashboard loads. Lock the panel down to your office IPs via `iptables` or HestiaCP's firewall module before going further.

## Step 3 - Create per-site HestiaCP users

Per [HestiaCP user management](https://docs.hestiacp.com/administration/user_management.html), each client site gets its own Linux user. This is the security boundary that makes the multi-tenant model safe — chrooted SFTP, separate databases, separate cron, separate log files.

```
# Create the user, assign the package, attach the domain
v-add-user clientacme strong-pw ops@example.com default 'Client ACME'
v-add-domain clientacme acme.com
v-add-mail-domain clientacme acme.com
v-add-database clientacme acme acme_user db-pw mysql
```

Now generate the SFTP key pair on your [DeployHQ](https://www.deployhq.com) side first (next step), then add the public key to the HestiaCP user:

```
v-add-user-ssh-key clientacme /tmp/deployhq.pub
```

Verify the chrooted SFTP path resolves. The HestiaCP convention is `/home/<user>/web/<domain>/public_html` — that is the path you will paste into [DeployHQ](https://www.deployhq.com).

## Step 4 - Configure the DeployHQ project

In DeployHQ:

1. **Create a project** , connect it to your Git provider, pick the branch.
2. **Add a server** with these values:

| Field | Value |
| --- | --- |
| Protocol | SSH/SFTP |
| Hostname | `acme.com` (or the Linode IP) |
| Port | `22` |
| Username | `clientacme` (the HestiaCP user, not `root`) |
| Authentication | SSH key (recommended over password) |
| Deployment path | `/home/clientacme/web/acme.com/public_html` |
| Branch | `main` |

1. **Copy the [DeployHQ](https://www.deployhq.com) public key** from the server config screen, then add it to HestiaCP using `v-add-user-ssh-key` as shown above. We covered the same flow in [How to deploy to your server using SSH/SFTP and Git with DeployHQ](https://www.deployhq.com/blog/how-to-deploy-to-your-server-using-ssh-sftp-and-git-with-deployhq).
2. **Enable automatic deployments** so every push to `main` triggers a deploy — see [automatic deployments](https://www.deployhq.com/features/automatic-deployments) for the webhook mechanics.

If the SSH connection refuses, the [SSH/SFTP troubleshooting guide](https://www.deployhq.com/blog/troubleshooting-server-issues-with-deploy) covers the four issues that account for ~90% of failures (missing key, wrong port, fail2ban ban, chroot path mismatch).

## Step 5 - Build pipeline (Composer, npm, asset compilation)

Run builds on [DeployHQ](https://www.deployhq.com), not on the Linode. A typical Laravel project's build commands look like:

```
# Composer install (production-only, optimised autoloader)
composer install --no-dev --optimize-autoloader --prefer-dist

# Front-end assets
npm ci
npm run build

# Strip the heavy stuff before upload
rm -rf node_modules tests .git docs
```

For WordPress sites the equivalent is `composer install --no-dev` plus `npm run build` for any custom block bundles. We documented the broader Git-driven WordPress workflow in [Automate WordPress Deployments with Git (no more FTP)](https://www.deployhq.com/blog/automate-wordpress-deployments-with-git).

## Step 6 - Post-deploy SSH commands

[DeployHQ](https://www.deployhq.com) supports SSH commands that run on the target server after files are uploaded. Use them to swap symlinks, run migrations, and warm caches — all over the same SFTP user, no `root`:

```
# Laravel example
cd /home/clientacme/web/acme.com/public_html
php artisan migrate --force
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan queue:restart
```

Pin a `release` directory pattern if you want true atomic swaps — DeployHQ's [zero downtime deployments](https://www.deployhq.com/features/zero-downtime-deployments) feature handles symlink atomicity for you.

## Step 7 - Security hardening

Per [HestiaCP security best practices](https://docs.hestiacp.com/administration/security.html), the non-negotiables are:

- **Disable password SSH** in `/etc/ssh/sshd_config` (`PasswordAuthentication no`) once keys are in place.
- **fail2ban** is enabled by default in HestiaCP — leave it on, and add the `recidive` jail for repeat offenders.
- **Restrict the panel port (8083)** to your office/VPN IPs only. Public exposure of the panel is the most common HestiaCP compromise vector.
- **Per-user FTP/SFTP credentials** — never give [DeployHQ](https://www.deployhq.com) the `admin` user. Each site = its own user.
- **TLS everywhere** — HestiaCP's built-in Let's Encrypt issuer covers both the panel and the hosted domains.

## Backup and rollback strategy: the 3-2-1 rule

This is where most agencies cut corners and pay for it later. Follow the [3-2-1 backup rule](https://en.wikipedia.org/wiki/Backup#3-2-1_rule): **3** copies of your data, on **2** different media, with **1** off-site. Concretely:

| Layer | What it covers | Where it lives |
| --- | --- | --- |
| HestiaCP daily backup | DB + files + mail per user | Local disk on the Linode (`/backup/`) |
| Linode Backup Service (~25% of plan cost) | Full instance snapshot, 1d/7d/scheduled | Linode infrastructure |
| Off-site (Backblaze B2 / S3) | HestiaCP `.tar` + DB dumps | Independent provider |

Define your [RPO and RTO](https://en.wikipedia.org/wiki/Disaster_recovery#Recovery_objectives) up front: for most agency client sites, **RPO 24 h** (lose at most a day of changes) and **RTO 1 h** (back up and running within an hour) is realistic. Set rollback expectations in your client contract, not after the first incident.

[DeployHQ](https://www.deployhq.com) also retains the previous 10 deploys so you can revert any commit-triggered breakage in one click — distinct from disaster recovery, but the first line of defence for the new release broke checkout.

## Realistic outcomes

For the agencies we work with, the typical move from manual SFTP to HestiaCP + [DeployHQ](https://www.deployhq.com) delivers:

- **Deploy time** : down from ~10 minutes (drag-and-drop from a local build) to ~30-90 seconds (diff upload of changed files only).
- **Failed deploys** : down sharply because Composer/npm runs on [DeployHQ](https://www.deployhq.com) — no works on my machine PHP version drift between developer laptops.
- **Credential sprawl** : zero shared SFTP logins; per-site keys, revocable per-client.
- **Auditability** : every deploy has a commit SHA, an author, and a server-side log — [DeployHQ pricing](https://www.deployhq.com/pricing) starts at the level where this is included.

Your numbers will vary based on app size and pipeline complexity, but the shape of the win is consistent.

## When HestiaCP is the wrong choice

To save you a refactor: do not use HestiaCP if you need (a) Windows hosting, (b) commercial vendor support with an SLA, or (c) deeply custom Apache modules. In those cases a commercial cPanel install or a [pure Git-based VPS deployment without a control panel](https://www.deployhq.com/blog/setting-up-git-based-deployment-on-a-virtual-private-server-vps) will fit better. If you are still evaluating the file-transfer protocol itself, [SFTP vs SCP vs rsync](https://www.deployhq.com/blog/sftp-vs-scp-vs-rsync-choosing-the-right-file-transfer-method) covers the trade-offs.

For agencies running 10+ client sites, the [DeployHQ for agencies](https://www.deployhq.com/for-agencies) plan adds team-level project management on top of the same workflow.

* * *

## Recommended resources

- [HestiaCP official documentation](https://docs.hestiacp.com/)
- [DeployHQ documentation](https://deployhq.com/docs)
- [Sign up for DeployHQ](https://www.deployhq.com/signup)

Questions or stuck on a specific HestiaCP / [DeployHQ](https://www.deployhq.com) wiring problem? Email **[support@deployhq.com](mailto:support@deployhq.com)** or ping us on [@deployhq](https://x.com/deployhq) — we read every message.

