# Git deploy

> Deploy from a Git repository with automatic framework detection, sandboxed builds, health-checked zero-downtime releases, push webhooks and one-click rollback.

Source: https://zopanel.net/docs/git-deploy  
Updated: 2026-10-07

Git deploy builds and runs your code straight from a repository. ZoPanel detects the framework, proposes install, build and start commands, builds in a sandbox limited to the account's CPU and memory, and only switches traffic to the new release after it passes a health check. If anything fails, the previous release keeps running.

## Create a website from Git

1. Open **Websites → New website** and choose the **Git deploy** type.
2. Enter the **Repository URL**, the **Branch** (default `main`) and, for monorepos, the **Root directory** (for example `apps/web`).
3. Keep **Free SSL (Let's Encrypt)** on and click **Create website**.

The first deployment starts immediately. When it has finished, ZoPanel issues the SSL certificate in the same task, so the two never collide.

You can also deploy into an existing website from its **Deploy** tab.

### Repository URLs

| Form | Example |
| --- | --- |
| Public HTTPS | `https://github.com/owner/repo` |
| SSH (private repositories) | `git@github.com:owner/repo.git` or `ssh://git@git.example.com:2222/owner/repo` |

The repository host must be a public address. For a private repository, open **Deploy → Deploy key (private repositories)**, click **Show deploy key**, add that public key to the repository as a read-only deploy key, and use the `git@…` URL.

Other sources in the **Source** list: **Uploaded files (File Manager)**, where you upload the project to `domains/<domain>/source` with the File Manager or SFTP, and **Ready-made Docker image**.

## Framework detection

On every deploy (unless you turn **Auto-detect** off), ZoPanel inspects the repository and fills in the build settings. The first match wins:

| Found in the repository | Detected as |
| --- | --- |
| `composer.json` (and no Node server framework) | Laravel (`artisan` or `laravel/framework`), Symfony, or PHP (Composer). Front-end assets are built with npm when `package.json` has a `build` script. |
| `package.json` | Next.js, Nuxt, Remix / React Router, SvelteKit, Astro, NestJS, Gatsby, Angular, Create React App, Docusaurus, VitePress, Vite (React/Vue/Svelte), or a Node.js server (Express, Fastify, Koa, Hono…) |
| `wp-config-sample.php` + `wp-login.php` | WordPress |
| `Gemfile` | Ruby on Rails, Rack (Sinatra, Hanami…) or Ruby |
| `pom.xml`, `build.gradle` | Java / Spring Boot |
| `*.csproj` | .NET / ASP.NET Core |
| `manage.py`, `requirements.txt`, `pyproject.toml`, `Pipfile` | Django, FastAPI, Flask or Python |
| `go.mod` | Go |
| `index.php` / `index.html` | PHP / static HTML |
| `Dockerfile` only | Dockerfile (container) |

A few details worth knowing:

- **Package manager:** `pnpm-lock.yaml` → `pnpm install --frozen-lockfile`, `yarn.lock` → `yarn install --frozen-lockfile`, `package-lock.json` → `npm ci`, otherwise `npm install`.
- **Node.js version:** taken from `.nvmrc`, `.node-version` or `engines.node`. If that major version is not installed, the newest installed one is used.
- **Static exports:** Next.js with `output: 'export'`, Astro without `@astrojs/node`, SvelteKit with `adapter-static`, Vite, Angular and similar builds are served as static sites from their output folder.
- **Procfile:** a `web:` line always provides the start command.
- **Laravel:** an `APP_KEY` is generated if missing, `storage` and `.env` are kept between releases, and sessions and cache use the account's Redis when it is available.

Click **Analyze repository** to see the detection before you deploy, then **Use these settings and customize** if you want to change them.

## Build and run settings

The **Build & run** card shows what will run:

| Field | Notes |
| --- | --- |
| Runtime / Version | node, python, go, php, ruby, java, dotnet, static or docker. **Latest installed** uses the newest version on the server. |
| Type | **Server app (process)**, **Static site**, **PHP (PHP-FPM)** or **Container (Dockerfile)**. |
| Install command | For example `npm ci` or `composer install --no-dev --optimize-autoloader --no-interaction`. |
| Build command | For example `npm run build`. Chain several commands with `&&` on a single line. |
| Start command | Server apps only. The app must listen on `127.0.0.1:$PORT`. |
| Output directory / Document root | Folder served for static and PHP sites, such as `dist` or `public`. |
| Persistent paths | Kept between releases, such as `storage`, `uploads` or `.env`. |
| Health check path | Must answer with a status below 500 before the release goes live. Default `/`. |

**Environment variables** are available during the build and at runtime; `PORT` is set automatically. Use **Paste .env** to add many at once (up to 200 variables, single-line values).

Container (Dockerfile) mode must first be enabled once on the server by an administrator:

```bash
zopanel ctl feature enable custom-docker
```

## How a deployment runs

1. The code is fetched into a new release folder: `domains/<domain>/releases/<timestamp>/`.
2. Install and build commands run as the hosting account through systemd, inside the account's CPU and memory limits, unable to write outside its home.
3. Server apps start in the idle slot on their own port. ZoPanel waits up to 90 seconds for the health check path to answer.
4. nginx switches to the new release (a graceful reload), then the previous process is stopped. `current` points to the live release.

Each deployment is listed under **Deployments** with its commit, trigger (**Manual**, **Git push** or **Created**) and status. If a deployment fails, the owner gets a **Deployment failed** notification.

## Automatic deploys on push

1. On the **Deploy** tab, turn on **Deploy when main is pushed** in the **Automatic deploys** card.
2. Copy the **Payload URL** (`https://<panel-domain>:8888/api/hooks/deploy/<id>`) and the **Secret**.
3. Add the webhook in your Git host:
   - **GitHub:** Settings → Webhooks → paste the URL, content type `application/json`, and the secret.
   - **GitLab / Gitea:** paste the URL and put the secret in **Secret token**.

ZoPanel verifies the signature (GitHub's `X-Hub-Signature-256`) or the token header (GitLab, Gitea); the secret is never accepted in the URL. Only pushes to the configured branch deploy. Duplicate deliveries are ignored, and at most one webhook deploy starts per 15 seconds, never while another deployment is running. GitHub's ping event answers `pong`.

**Regenerate secret** replaces the secret; update the webhook in your Git host afterwards.

### Deploy from CI with an API token

With a Pro license, create an API token in **My account → API tokens** and trigger a deployment from any CI system:

```bash
curl -X POST \
  -H "Authorization: Bearer zpat_..." \
  https://panel.example.com:8888/api/sites/<site-id>/app/deploy
```

## Rollback

The **Releases** card keeps the last 5 builds. Click **Rollback** on any of them: server apps are started in the idle slot and switched over after the health check, exactly like a deployment, so rolling back causes no downtime.

## Logs

- **Deploy tab → Application output** shows the latest output of the running app; turn on **Live** to follow it.
- Each deployment's build log is kept in **Tasks**.
- The website's **Logs** tab shows the nginx access and error logs, and **Run diagnostics** explains recent errors.
