The best deployment tool most developers ever used was git push heroku main. It disappeared behind pricing changes, but the idea did not: the repository is the deployment, and the platform does the rest. This post follows a developer recreating that on MassiveGRID PaaS, which is built on Virtuozzo Application Platform, formerly Jelastic, with the Git-Push-Deploy add-on, and being honest about what it does and does not do.

The developer runs a small product studio we will call Halcyon Apps: a Node.js API, a PHP marketing site and a Java service, each in its own repository on GitHub. The Git-Push-Deploy add-on attaches to an application server layer, connects a repository and branch, and redeploys on every push, with optional build commands and hooks.

What happens on a push

The add-on registers a webhook on the repository, GitHub and GitLab are supported directly, and stores the credentials or a deploy key for private repositories. When a push lands on the configured branch, the platform pulls the code, runs any build commands you configured, deploys it to each node in the layer and reloads the application server gracefully. If the layer has several nodes, they are updated sequentially, one at a time with a 30-second delay by default, behind the load balancer, so no request is dropped. For PHP applications the add-on uses the platform's zero-downtime deployment mode, which switches a symlink to the new release directory atomically, so even a single PHP node never serves a half-copied release.

The deployment log for each run is in the dashboard, which is where the developer looks when a build command fails. A non-zero exit from a build command aborts the deploy and leaves the previous release serving.

Repository one: the Node.js API

The developer installs the add-on on the API's Node.js layer, points it at main, and adds a build step of npm ci --omit=dev so dependencies are installed on the node after the pull. The Node.js container's process manager (PM2 on this layer) restarts the application after deployment. A post-deploy hook curls the API's health endpoint and posts the result to the team's Mattermost channel. From the first push, the pipeline is: merge to main, wait about forty seconds, see the health check message.

One constraint the developer respects: the add-on deploys to the application server's ROOT context only. An application already deployed there is overwritten at install, and multiple contexts from one repository are not supported. For a one-application-per-environment layout, which is the sensible one, it never matters.

Repository two: the PHP site

The PHP marketing site gets the same treatment on its NGINX PHP layer, with composer install --no-dev as the build step. Here the ZDT deployment mode earns its keep: the site's two application servers each switch to the new release atomically, one after the other, and the developer stops writing "deploying, back in 5" in the studio's chat.

Repository three: the Java service, and how it differs

For Java the add-on works differently, because a Java application must be built before it can be deployed. Installing it on a Java layer creates a separate small environment with a Maven build node. That node watches the repository, runs the Maven build on push, and deploys the resulting artefact to the application server. The build node is a platform container like any other, so it costs cloudlets only while it exists and can be stopped between releases; the developer leaves it running because a Maven build node idles at a cloudlet or two.

StackWhat the add-on does on pushDowntime
PHP (Apache or NGINX)Pull, build commands, ZDT symlink switch, graceful reloadNone, even on one node
Node.js, Python, Ruby, GoPull, build commands, process restart per node, sequentialNone with two or more nodes
JavaMaven build node builds and deploys the artefact to the server layerNone with two or more nodes

Where the add-on stops and a CI server starts

The developer is clear-eyed about the boundary. The add-on runs build commands and aborts on failure, so a test suite can run there, but it runs on the application node itself, in sequence, on every push. There are no parallel runners, no matrix builds, no artefact caching between runs, no review apps. For Halcyon's three small services that is exactly enough. When a project needs real CI, the platform has the GitLab Server and Jenkins packages, and the two approaches combine well: CI builds and tests, then pushes to a release branch that the add-on deploys.

Staging with a branch, and a clone

Two habits keep the pipeline honest. Every environment variable the code needs is documented in the repository's README, since it lives in the dashboard rather than in a file, and every build command is written to fail fast, because a failed build leaves the previous release serving and a slow one delays the deploy for everyone.

Halcyon's staging is a clone of each production environment with the add-on pointed at the develop branch instead of main. Because a clone carries the add-on's configuration, the developer only changes the branch name. Staging environments are stopped at night by the Start/Stop Scheduler and cost disk only while stopped. The whole setup, three production environments and three staging clones with push-to-deploy, took an afternoon and needs no server the studio has to maintain.

Frequently Asked Questions

Does the add-on work with Bitbucket or a self-hosted Git server?

Webhook integration is built for GitHub and GitLab, including the self-hosted GitLab Server package. For other hosts, the platform's Deployment Manager can poll any Git repository on a schedule, as often as every minute, which achieves nearly the same result without a webhook.

How are secrets handled?

Repository credentials or the generated deploy key are stored on the platform, not in your code. Application secrets belong in the layer's environment variables, set in the dashboard, which the deployed code reads at runtime; they are never in the repository.

Can I roll back a bad push?

Push a revert commit and the add-on deploys it the same way. The Deployment Manager also keeps the previous deployment, so a redeploy of the prior version from the dashboard is a one-click alternative.

Push to main, and it is live

Install the Git-Push-Deploy add-on on any application server layer on MassiveGRID PaaS, connect a repository and get zero-downtime deployments on every push, with no CI server to run. Free 14-day trial, no credit card.

Git-Push-Deploy on MassiveGRID PaaS

Further Reading