ARTIFACTORY: How to configure Homebrew Repository in Artifactory

Products
Frog_Artifactory
Content Type
User_Guide
AuthorFullName__c
Tomer Avisar
articleNumber
000007012
FirstPublishedDate
2026-06-15T12:20:48Z
lastModifiedDate
2026-06-15

ARTIFACTORY: How to configure Homebrew Repository in Artifactory

Introduction

Homebrew is the most popular package manager for macOS and Linux. Since Homebrew 3.2.7, pre-compiled binaries (called bottles) are distributed as OCI images via GitHub Container Registry (ghcr.io). Because bottles are OCI images, Artifactory supports Homebrew using Docker or OCI repositories, not a dedicated Homebrew package type. The same repository infrastructure that handles container images also stores, proxies, and aggregates Homebrew bottles.

Note:

There is no "Homebrew" package type in the Artifactory repository creation UI. Select Docker or OCI when creating repositories for Homebrew use. Both package types are fully supported and behave identically for Homebrew.


Artifactory supports the following repository configurations for Homebrew:

Type
Use Case
Local
Host internally built bottles for private packages
Remote
Proxy and cache public Homebrew bottles from ghcr.io
Virtual
Aggregate local and remote repositories under a single URL
Smart Remote
Proxy Homebrew repositories from another Artifactory instance

For organizations running multiple Artifactory instances, a Smart Remote repository can proxy a Homebrew repository hosted on another Artifactory instance or Edge node, enabling centralized bottle management across environments. Smart Remote configuration is covered in a separate article.


Local Repository


A local Homebrew repository stores internally built bottles (pre-compiled binaries packaged as OCI images). This lets your organization distribute private packages through Homebrew without publishing them to a public registry.

Step 1: Create a Docker Local Repository
  1. In the Administration tab, click Repositories > Create a Repository.
  2. Select Local.
  3. Select the Docker package type.
  4. In the Repository Key field, enter a name for the repository (for example, homebrew-local).
  5. Click Create Repository.
Step 2: Point Your Formula at Artifactory
In your tap's formula file, the bottle do block must set root_url to the base path of your Artifactory local repository:
bottle do
  root_url "https://<artifactory-host>/artifactory/homebrew-local/homebrew/internal"
  sha256 x86_64_linux: "<bottle-sha256>"
  sha256 arm64_monterey: "<bottle-sha256>"
end
This tells Homebrew where to look for bottles when a client runs brew install.

Step 3: Push Bottles to Artifactory
Homebrew bottles are distributed as Docker/OCI images. Once you have built and packaged your bottle as an OCI image, push it to Artifactory using the Docker CLI.
The image path and tag must match the formula's root_url. If root_url is set to https://<host>/artifactory/homebrew-local/homebrew/internal, the image must be pushed to:
<host>/homebrew-local/homebrew/internal/<package>:<version>.<platform>
For example:
docker login <artifactory-host>
docker push <artifactory-host>/homebrew-local/homebrew/internal/my-package:1.0.0.x86_64_linux
The tag format Homebrew expects is <version>.<platform> (for example, 1.0.0.x86_64_linux or 1.0.0.arm64_monterey).

Step 4: Configure Clients
On each developer machine that will install from your tap:
# Set the Artifactory instance as the bottle source
export HOMEBREW_ARTIFACT_DOMAIN="https://<artifactory-host>/artifactory/homebrew-local"

# Provide an Artifactory Identity Token for authentication
export HOMEBREW_DOCKER_REGISTRY_TOKEN="<identity-token>"

# Tap the internal repository
brew tap <your-org>/<tap-name> <git-url>

# Install the package
brew install <your-org>/<tap-name>/my-package
To make these settings persistent, add the export lines to your shell profile (.zshrc, .bash_profile, etc.).
Note:

Shell session scope: An export added to .zshrc or .bash_profile only takes effect in shells opened after the file is sourced. Verify in the same terminal where brew install was run:

echo $HOMEBREW_DOCKER_REGISTRY_TOKENbrew config | grep HOMEBREW_DOCKER_REGISTRY_TOKEN
If echo returns nothing, the variable is not set in that shell. Run source ~/.zshrc or open a new terminal and try again.


Remote Repository

A remote Homebrew repository proxies and caches public Homebrew bottles from GitHub Container Registry (ghcr.io). When a developer installs a Homebrew package, bottles are fetched from Artifactory rather than directly from ghcr.io, providing offline resilience, traffic control, and a central audit point.


Step 1: Create a Docker Remote Repository
  1. In the Administration tab, click Repositories > Create a Repository.
  2. Select Remote.
  3. Select the Docker package type.
  4. In the Repository Key field, enter a name (for example, homebrew-remote).
  5. In the URL field, enter https://ghcr.io.
  6. Click Create Repository.
No additional authentication is required for public Homebrew bottles. ghcr.io serves the homebrew/core namespace publicly without credentials.
Note:

The Artifactory OCI remote configured against https://ghcr.io proxies all paths under ghcr.io, not only homebrew/core. If a third-party tap publishes bottles to ghcr.io under its own namespace, those downloads are also routed through the same remote automatically.


Step 2: Configure Clients
Homebrew reads HOMEBREW_ARTIFACT_DOMAIN to redirect bottle download URLs to your Artifactory instance. Set it to the remote repository URL:
# JFrog Cloud — subdomain format
export HOMEBREW_ARTIFACT_DOMAIN="https://<instance>-homebrew-remote.jfrog.io"
# JFrog Cloud — repository path format (also valid)
# export HOMEBREW_ARTIFACT_DOMAIN="https://<instance>.jfrog.io/homebrew-remote"
# Self-managed — use the Docker registry URL from Set Me Up in the Artifactory UI
# export HOMEBREW_ARTIFACT_DOMAIN="https://<repo>.<host>"
export HOMEBREW_DOCKER_REGISTRY_TOKEN="<identity-token>"
To make these settings persistent, add the export lines to your shell profile (.zshrc, .bash_profile, etc.).
Note:

HOMEBREW_ARTIFACT_DOMAIN must be set to the Docker registry URL for your repository, not the Artifactory API URL. The key rule: do not include /artifactory/ in the path. https://<host>/artifactory/<repo> is the Artifactory HTTP API path — it is not a Docker Registry v2 endpoint and Homebrew will silently fall back to ghcr.io without any error.

For JFrog Cloud, both https://<instance>-<repo>.jfrog.io (subdomain) and https://<instance>.jfrog.io/<repo> (repository path) are valid. For self-managed instances, use the Docker registry URL shown in Set Me Up for the repository.

With this configuration, brew install wget will fetch the wget bottle through Artifactory rather than directly from ghcr.io.
How HOMEBREW_ARTIFACT_DOMAIN Works
When HOMEBREW_ARTIFACT_DOMAIN is set, Homebrew replaces the hostname in bottle download URLs with your Artifactory domain. For example:
Without env var:  https://ghcr.io/v2/homebrew/core/wget/manifests/1.25.0
With env var:     https://<artifactory-URL>/v2/homebrew-remote/homebrew/core/wget/manifests/1.25.0
Artifactory's OCI remote receives the request and fetches from ghcr.io on the client's behalf, caching the result.
Limitation: Non-Bottle URLs Are Not Proxied
HOMEBREW_ARTIFACT_DOMAIN only works for bottles distributed via OCI-compatible registries (ghcr.io). It does not work for packages that download pre-built binaries from vendor-hosted URLs.
When a formula downloads from a non-OCI URL, Homebrew prefixes the artifact domain to the full original URL rather than replacing the hostname:
Original URL:  https://releases.hashicorp.com/terraform/1.14.9/terraform_1.14.9_darwin_arm64.zip
With env var:  https://<artifactory>/https://releases.hashicorp.com/terraform/1.14.9/...
This produces an invalid path that Artifactory cannot resolve, and the download fails with a 404.
Affected packages include:

Tap

Download Source

hashicorp/tap (terraform, vault, packer)

releases.hashicorp.com

heroku/brew

cli-assets.heroku.com

Other vendor-hosted taps

Varies


For packages that download from a known vendor URL, you can create a Generic remote repository in Artifactory pointing directly at that vendor's base URL. Clients then download from the Generic remote directly, not via HOMEBREW_ARTIFACT_DOMAIN.
Example for HashiCorp tools:
  1. Create a Generic remote repository with URL https://releases.hashicorp.com.
  2. Clients download Terraform directly from:
https://<artifactory>/artifactory/<generic-remote-key>/terraform/1.x.x/terraform_1.x.x_darwin_arm64.zip
Casks are similarly not proxied. Cask installers (.app, .dmg, .pkg) are hosted at arbitrary URLs provided by the package author. Use standard forward proxy environment variables (HTTP_PROXY, HTTPS_PROXY) to route Cask downloads through a proxy.
Note:

Bottles fetching from ghcr.io directly, ignoring Artifactory
brew fetch and brew install report success even when Homebrew falls back to ghcr.io. The only reliable way to confirm traffic is routing through Artifactory is to check the repository's cache in the Artifactory UI or API — if the artifact appears in <repo>-cache, it went through Artifactory.
If nothing is being cached, first verify HOMEBREW_ARTIFACT_DOMAIN is visible to the Homebrew process:
brew config | grep HOMEBREW_ARTIFACT_DOMAIN
If the output is empty, source your shell profile or open a new terminal. If the value is set but still not caching, verify the URL is the Docker registry endpoint, not the Artifactory API path — see the note in the Remote Repository section above.


Virtual Repository
A virtual Homebrew repository aggregates one or more local and remote Docker repositories under a single URL. Clients point HOMEBREW_ARTIFACT_DOMAIN to the virtual repository and Artifactory resolves bottle requests from the appropriate member transparently.
Step 1: Create a Docker Virtual Repository
  1. In the Administration tab, click Repositories > Create a Repository.
  2. Select Virtual.
  3. Select the Docker package type.
  4. In the Repository Key field, enter a name (for example, homebrew-virtual).
  5. In the Repositories section, add your local and remote Docker repositories as members (for example, homebrew-local and homebrew-remote).
  6. Set the Default Deployment Repository to your local repository if you want docker push commands without an explicit repository to land in the local repo.
  7. Click Create Repository.
Step 2: Configure Clients

Set HOMEBREW_ARTIFACT_DOMAIN to the virtual repository:
export HOMEBREW_ARTIFACT_DOMAIN="https://<artifactory-host>/artifactory/homebrew-virtual"
export HOMEBREW_DOCKER_REGISTRY_TOKEN="<identity-token>"
With this configuration:
  • brew install <org>/<internal-tap>/<package> resolves from homebrew-local
  • brew install wget (public Homebrew Core formula) resolves from homebrew-remote (ghcr.io cache)
To make these settings persistent, add the export lines to your shell profile (.zshrc, .bash_profile, etc.).
Important Constraint: All Members Must Be the Same Package Type
A Docker virtual repository can only include Docker (local and remote) repositories as members. Generic remote repositories cannot be added as members of a Docker virtual repository.
This means the bottle proxy (OCI remote) and vendor download proxy (Generic remote) remain separate repositories with separate access paths:

Download type

Path

OCI bottles (ghcr.io packages)

HOMEBREW_ARTIFACT_DOMAIN → Docker virtual → Docker remote (ghcr.io)

Non-bottle vendor downloads (Hashicorp, Heroku, etc.)

Direct URL to a Generic remote repository