Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Harbor Laravel Package

mehrancodes/laravel-harbor

Laravel Harbor helps you deploy Laravel applications with Docker, offering Artisan commands and configuration for building, provisioning, and releasing your app to a server in a repeatable container-based workflow.

View on GitHub
Deep Wiki
Context7

Getting Started

Harbor is a dev-only CLI that spins up a throwaway Forge site per pull request, so reviewers get a working URL before merge. Treat it as CI infrastructure, not application code.

  1. Install as a dev dependency (skip in production): composer require mehrancodes/laravel-harbor --dev. Harbor v2 requires PHP 8.2+ — if your workflow uses kirschbaumdevelopment/laravel-test-runner, use :8.3; the older :8.1 examples in the docs will break.
  2. Run the package's install/init command to scaffold config/harbor.php and a GitHub Actions workflow. That workflow file is the real surface area — read it before you read the PHP.
  3. Collect secrets first, wire config second. You need FORGE_API_TOKEN (and a Forge server/organisation already provisioned), plus GIT_TOKEN if you want Harbor to register deploy keys and post PR/MR comments for you. The default GITHUB_TOKEN in Actions is not sufficient for deploy keys.
  4. Where to look when something's wrong, in order: the workflow YAML (env vars), config/harbor.php (site naming, directory, server), then the CI log — Harbor's output is line-prefixed INFO / WARNING / FAIL, and the prefix tells you whether provisioning continued.
  5. First use case: provision on pull_request (opened/synchronize/reopened), teardown on closed. Add the concurrency group from the v2.1.0 notes at the same time — see Gotchas.

The two docs pages worth bookmarking: Git Providers and Announcement Comments.

Implementation Patterns

Two git settings, not one. Since v2.1.0 Forge and Harbor are configured separately, and conflating them is the main source of confusion:

Setting Consumer Purpose
FORGE_GIT_PROVIDER Forge how the site clones the repo (default github)
FORGE_GIT_API_PROVIDER Harbor which API Harbor uses for deploy keys + PR/MR comments

FORGE_GIT_API_PROVIDER defaults to FORGE_GIT_PROVIDER. Keep it unset for plain GitHub/GitLab.com; set it explicitly only for self-hosted hosts.

Deploy keys: three modes, pick deliberately.

  • Auto — FORGE_DEPLOY_KEY=true plus a reachable GIT_TOKEN. Harbor generates a keypair, registers the public half on the provider, passes both halves to Forge, and removes the key on teardown. Cleanest for GitHub/GitLab.com.
  • Bring your own — FORGE_DEPLOY_KEY=true with FORGE_DEPLOY_KEY_PUBLIC / FORGE_DEPLOY_KEY_PRIVATE (store the private half as a secret). Use when Harbor can't reach your Git API, e.g. an internal GitLab behind a firewall.
  • Manual — no GIT_TOKEN. Harbor prints the public key; someone adds it to the repo. Fine for a one-off, untenable across a team.

Self-hosted GitLab, the canonical non-default setup:

FORGE_GIT_PROVIDER: custom          # Forge clones via the custom URL
FORGE_GIT_REPOSITORY_URL: https://gitlab.example.com/group/app.git
FORGE_GIT_API_PROVIDER: gitlab-custom
GIT_API_URL: https://gitlab.example.com/api/v4
GIT_TOKEN: ${{ secrets.GITLAB_TOKEN }}
FORGE_DEPLOY_KEY: true

With FORGE_GIT_PROVIDER=custom Harbor infers the API from a github.com / gitlab.com repository URL, so the explicit provider is only needed for non-hosted domains.

Commenting on PRs/MRs needs four things together: a configured Git API provider, GIT_TOKEN, GIT_COMMENT_ENABLED=true, and GIT_ISSUE_NUMBER. On GitLab, GIT_ISSUE_NUMBER is the merge request iid (project-scoped), not the global id.

Migrate the env var now, not later. FORGE_GITHUB_DEPLOY_KEY still works as an alias but emits a deprecation warning and is slated for removal in a future major:

- FORGE_GITHUB_DEPLOY_KEY: true
+ FORGE_DEPLOY_KEY: true

Dry-run locally. Run ./vendor/bin/harbor provision from your machine with the same env vars against a scratch PR/branch to iterate on config without burning CI minutes — just remember it will create a real Forge site and a real deploy key, so tear down afterwards.

Gotchas and Tips

Add a per-PR concurrency group — this is a correctness fix, not a nicety. Two runs for the same PR (back-to-back pushes, or reopening a PR right after pushing) race to create the same site and one dies with site: The site must be installed before it can be deployed. Put it on both provision and teardown:

concurrency:
  group: harbor-${{ github.event.pull_request.number }}
  cancel-in-progress: false   # false: cancelling mid-provision leaves an orphan site

403 Forbidden while registering the deploy key is a permissions problem, and the message names the fix. For a GitHub App token (actions/create-github-app-token): Repository permissions → Administration: Read & write, then accept the updated permissions on the installation — granting without accepting is the classic trap. For a PAT: repo scope. GITHUB_TOKEN can never do this.

"Deploy key not registered automatically" is a warning, not a failure. Harbor created the site with a valid keypair and printed the public key. Provisioning continues and the site works if you add the key to the repo. Cause is either a missing GIT_TOKEN or FORGE_GIT_PROVIDER=custom pointing somewhere Harbor can't infer an API for. Don't retry — configure the API or paste the key.

Provider validation is now strict and fails fast (before Forge is called). FORGE_GIT_PROVIDER must be one of github, gitlab, gitlab-custom, bitbucket, custom; custom additionally requires FORGE_GIT_REPOSITORY_URL. A typo that used to leak into a confusing Forge error now aborts early — that's an improvement, but it will surface latent typos on upgrade.

Silent-comment debugging order: API provider set? GIT_TOKEN valid for that host? GIT_COMMENT_ENABLED=true? GIT_ISSUE_NUMBER present and, on GitLab, the MR iid? Any one missing gives you a WARNING … no comment was posted and nothing else.

Teardown must run. Deploy keys and Forge sites are created eagerly; if the teardown job never fires (PR closed by a deleted branch, cancelled workflow), you own a dangling site and a deploy key on the repo. Sweep periodically, and never use cancel-in-progress: true on provision.

Extension points are thin on purpose. The site directory is now configurable (PR #131) and site naming lives in config/harbor.php; beyond that, customisation happens by shaping the env vars per job (e.g. a matrix over providers) rather than subclassing anything. If you find yourself wanting to fork internals, you probably want a second workflow instead.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource