Deploy

Configure a Git repository URL, branch, and deploy path under the Deploy tab.

Deploy Configuration

Git Deploy is the repository-based redeploy and webhook flow. Use it when Herne should pull a saved Git repository branch on demand or from the signed per-site webhook.

Go to Sites → Deploy → Git Deploy and fill in:

  • Repository URL — HTTPS or SSH URL (e.g. git@github.com:user/repo.git)
  • Branch — the branch to deploy from (default: main)
  • Deploy Path — the site root is locked to /var/www/example.com/web_root; you may only append a safe suffix such as /current

The deploy path can never escape the current site&#039;s <code>web_root</code>. Path traversal segments such as <code>..</code> are rejected.

Site Root Modes

New sites choose an explicit root mode during creation. Empty / Deploy target and Publisher-managed app start with only /var/www/example.com/web_root; Herne does not create an empty public/ folder for those modes. Laravel app and Static site start with web_root/public because their initial runtime needs a public document root.

Existing sites keep their saved document_root. Runtime apply still prepares legacy public roots for existing records that were created before root modes existed.

Runtime User and Validation

Deploys run inside the current site's project path. Existing checkouts have their origin remote synchronized to the saved repository URL before fetch/reset, which prevents stale repository URLs from silently deploying old code.

After runtime-affecting settings are applied, Herne validates the generated Nginx/runtime config before reload. If validation fails, the staged change is rolled back instead of leaving a broken active config.

Build Steps

Enable the steps the managed application needs. They run in this order after git pull:

  1. composer install --no-dev --optimize-autoloader
  2. npm ci && npm run build only for managed apps that ship their own frontend build pipeline
  3. php artisan migrate --force
  4. php artisan config:cache && php artisan route:cache && php artisan view:cache

Herne Panel itself is static-asset based and does not use Vite, Tailwind, npm, lockfiles, <code>public/build</code>, or <code>public/hot</code>. The optional npm checkbox applies only to the site you are deploying, never to the panel runtime or release package.

Private Repositories (Deploy Keys)

For private repositories, generate a Deploy Key and add it to GitHub / GitLab as a read-only deploy key.

  1. Go to Sites → Deploy → Git Deploy and click Generate Deploy Key.
  2. Copy the public key shown on screen.
  3. On GitHub: Repository → Settings → Deploy keys → Add deploy key. Paste the key. Read-only access is sufficient.
  4. On GitLab: Repository → Settings → Repository → Deploy keys.

The deploy key is an ed25519 keypair stored in <code>storage/app/deploy-keys/</code>. Only the public key is shown in the panel.

Triggering a Deploy

Click Deploy Now to pull the latest code and run the configured steps. Navigate to Sites → Deploy → Git Deploy and click the Deploy Now button.

Deploy Logs

All deploy runs are logged — click any entry in Recent Deploys to see full output. Each log entry shows the full shell output, exit code, and whether the deploy succeeded or failed.

Publisher Deploy

The Sites → Deploy → Publisher Deploy screen supports GitHub-free deploys from Publisher. Publisher server, product, and channel can be remembered per site; Herne does not assume a default product. Sites without a saved server use https://publisher.webblocksui.com, the canonical Publisher server for current standard releases; any other server is entered as a custom HTTPS URL.

Create the product and generate a Publisher Product Key in Publisher product management, then paste that key into the Herne deploy form. Herne uses the key for Publisher metadata/artifact requests. Pasted keys are not persisted by default, but they can be saved encrypted per site, replaced, or cleared.

Herne sends the key to the selected Publisher server for release metadata and artifact requests, downloads the artifact ZIP, verifies its SHA-256 checksum, extracts to a staging directory, and then applies the selected safety profile. Laravel artifacts use laravel_app into the site's deploy path. Static artifacts use static_site only for Herne Static site roots and apply into the site's real public root. Root entries stay limited to index.html, robots.txt, assets/**, games/**, site/**, favicon.ico, manifest.json, and version.json. Static asset areas use a denylist-based profile, so Flutter web output such as games/*/main.dart.js, games/*/icons/**, games/*/assets/shaders/*.frag, games/*/assets/packages/**, games/*/canvaskit/**, product asset paths such as site/webblocks-play/css/site.css, and NOTICES files can deploy while hidden paths, traversal, backup/temp files, server configs, and executable/server-side files remain blocked. Existing static safe updates preserve the current public-root index.html in staging when the artifact does not include one, and still abort before apply if no staged or existing root index exists.

  • Empty target: Publisher Deploy performs the first install.
  • Publisher-managed first deploys switch to web_root/public and apply Laravel/static runtime when the artifact includes a public root.
  • Existing Laravel app: Publisher Deploy requires explicit confirmation, snapshots changed files, and performs a safe update.
  • Existing Static site: Publisher Deploy accepts explicit static-site/static_site metadata, shows a replacement warning instead of the Laravel blocker, requires acknowledgement, stages a replacement public root, and verifies index.html after apply.
  • Non-empty targets that do not look like Laravel apps are blocked for safety.
  • Missing product keys block the deploy before metadata fetch, artifact download, checksum verification, extraction, or post-deploy steps begin.
  • Unsafe ZIP entries are rejected, including path traversal, absolute paths, detectable symlinks, dot segments, .env, .git, .github, root-level dependency folders, storage/, bootstrap/cache/, generated frontend build outputs, and npm/yarn/pnpm lock files. Dependency directories are blocked at root level; Laravel resources/views/vendor/ published view overrides are allowed.
  • Artifact inspection failures show the first rejected relative path and reason in the deploy log without exposing tokens, temp paths, server absolute paths, or stack traces.
  • Existing .env, storage/, bootstrap/cache/, uploads, and runtime files are preserved.
  • Apply and post-deploy steps must run as the configured site runtime/deploy user that can write the target tree. Standard Herne-managed sites use the www-data runtime ownership/group model.
  • Permission preflight checks the target root, artifact apply targets, Laravel runtime directories, bootstrap/cache, and Composer vendor target before apply. Unsafe permissions abort before files are changed.
  • Optional post-deploy steps can run composer install --no-dev --prefer-dist --optimize-autoloader, php artisan migrate --force, and optimize/cache clear.
  • If .env is missing, artisan post-deploy steps are skipped and the deploy log explains the next step.

Publisher Deploy is reusable for any supported Publisher product, including WebBlocks Workbench, CMS, Plugins, QuizTem, or future products. Later updates may be taken through Publisher Deploy or through the product&#039;s own System Updates screen when one is available.

Quick Install Apps

Deploy is still the right tool for Git-based applications. For supported apps, Sites → Apps → Quick Install can create an app without a repository deploy step. WebBlocks CMS prepares the CMS app and generated database credentials. Laravel App creates only a clean latest Laravel skeleton, marks the site runtime as Laravel, and leaves package products such as QuizTem to be installed afterwards through Composer or Terminal. Quick Install accepts an empty web_root or an empty public/ directory, but it refuses arbitrary existing files and does not delete them automatically.

Per-Site Deploy Webhook

Each site with a saved deploy configuration also gets its own webhook card on the Git Deploy page.

  • URLPOST /sites/{site}/webhook/deploy
  • Secret — generated automatically and shown in the panel
  • Signature header — send X-Hub-Signature-256 with the HMAC SHA-256 signature of the raw JSON payload
  • Branch filter — pushes to other branches are ignored automatically

GitHub Setup

  1. Open your repository webhook settings on GitHub
  2. Set the payload URL to the value shown on the site's Git Deploy page
  3. Use application/json as the content type
  4. Paste the generated secret from Herne into the webhook secret field
  5. Select the push event only

This per-site webhook is for tenant application deploys only. Updating Herne itself is a separate admin-only flow — see the <strong>Panel Updates</strong> screen, which applies WebBlocks Publisher releases instead of a webhook.