> For the complete documentation index, see [llms.txt](https://developer.harness.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developer.harness.io/harness-platform/use-harness-platform/references/harness-cloud-byoi.md).

# Harness Cloud Byoi

Create custom VM images with your tools pre-installed for faster CI builds on Harness Cloud.

## Prerequisites <a href="#prerequisites" id="prerequisites"></a>

* Harness CI Enterprise license
* `CI_ENABLE_BYOI_HOSTED` feature flag enabled (contact Harness support)
* Harness Cloud infrastructure (not self-hosted runners)

***

## Quick Start <a href="#quick-start" id="quick-start"></a>

### 1. Create a Packer File <a href="#id-1-create-a-packer-file" id="id-1-create-a-packer-file"></a>

Add a `.pkr.hcl` file to your repository with your customizations:

```hcl
# packer/my-image.pkr.hcl <a href="#packermy-imagepkrhcl" id="packermy-imagepkrhcl"></a>

# Optional: Define variables for reusability <a href="#optional-define-variables-for-reusability" id="optional-define-variables-for-reusability"></a>
variable "node_version" {
  type    = string
  default = "20"
}

# Install your tools <a href="#install-your-tools" id="install-your-tools"></a>
provisioner "shell" {
  inline = [
    "sudo apt-get update",
    "sudo apt-get install -y nodejs npm python3",
    "sudo npm install -g typescript yarn"
  ]
}

# Copy config files (optional) <a href="#copy-config-files-optional" id="copy-config-files-optional"></a>
provisioner "file" {
  source      = "configs/settings.json"
  destination = "/tmp/settings.json"
}

provisioner "shell" {
  inline = ["sudo mv /tmp/settings.json /etc/myapp/"]
}
```

### 2. Build the Image <a href="#id-2-build-the-image" id="id-2-build-the-image"></a>

Add this step to your pipeline:

```yaml
- step:
    type: Plugin
    name: Build Image
    spec:
      connectorRef: account.dockerhub
      image: harness/byoi-builder:1.0.0
      settings:
        mode: build
        packerFilePath: packer/my-image.pkr.hcl
        targetOs: linux
        targetArch: amd64
        imageName: my-dev-image
        imageVersion: v1
        baseImage: ubuntu/22.04
```

### 3. Use the Image <a href="#id-3-use-the-image" id="id-3-use-the-image"></a>

Reference it in your stage configuration:

```yaml
- stage:
    type: CI
    spec:
      platform:
        os: Linux
        arch: Amd64
      runtime:
        type: Cloud
        spec:
          imageSpec:
            imageName: my-dev-image:v1
      execution:
        steps:
          - step:
              type: Run
              spec:
                command: node --version  # Pre-installed!
```

{% hint style="info" %}
**LINUX AND WINDOWS BYOI IMAGES ARE STORED AND SERVED BY HARNESS**

Reference the image by `imageName:imageVersion` only. Linux and Windows BYOI do not support supplying a custom image connector (for example, the [Override Image Connector](/harness-platform/use-harness-platform/connectors/artifact-repositories/connect-to-harness-container-image-registry-using-docker-connector.md) stage infrastructure setting) to pull the VM image from your own registry. The image must be built with the Harness BYOI builder plugin and served from Harness-managed storage to be used with Linux or Windows BYOI.
{% endhint %}

***

## Plugin Settings <a href="#plugin-settings" id="plugin-settings"></a>

### Build Mode <a href="#build-mode" id="build-mode"></a>

| Setting          | Required | Default        | Description                                                             |
| ---------------- | -------- | -------------- | ----------------------------------------------------------------------- |
| `mode`           | No       | `build`        | Operation mode: `build` or `delete`                                     |
| `packerFilePath` | Yes      | -              | Path to your Packer file (relative to repo root)                        |
| `imageName`      | Yes      | -              | Image name (3-30 chars, lowercase letters, numbers, hyphens)            |
| `imageVersion`   | Yes      | -              | Version tag (1-20 chars, alphanumeric and hyphens)                      |
| `targetOs`       | No       | `linux`        | Target operating system: `linux` or `windows`                           |
| `targetArch`     | No       | `amd64`        | Target architecture: `amd64` or `arm64`. Windows supports `amd64` only. |
| `baseImage`      | No       | `ubuntu/22.04` | Base image to build from (see Supported Base Images)                    |
| `dockerVersion`  | No       | `28`           | Docker version to pre-install (e.g., `28`, `27`)                        |
| `debug`          | No       | `false`        | Enable verbose Packer logging                                           |

### Delete Mode <a href="#delete-mode" id="delete-mode"></a>

To rebuild with the same version, delete the existing image first:

```yaml
- step:
    type: Plugin
    name: Delete Image
    spec:
      connectorRef: account.dockerhub
      image: harness/byoi-builder:1.0.1
      settings:
        mode: delete
        imageName: my-dev-image
        imageVersion: v1
```

***

## Supported Base Images <a href="#supported-base-images" id="supported-base-images"></a>

### Linux <a href="#linux" id="linux"></a>

| Base Image     | Architectures |
| -------------- | ------------- |
| `ubuntu/24.04` | amd64, arm64  |
| `ubuntu/22.04` | amd64, arm64  |

### Windows <a href="#windows" id="windows"></a>

| Base Image            | Architectures |
| --------------------- | ------------- |
| `windows-server/2022` | amd64         |
| `windows-server/2025` | amd64         |

{% hint style="info" %}
The BYOI builder plugin also accepts `windows-server/2019`, but that version is not yet qualified to run as CI VMs on Harness Cloud. Use `windows-server/2022` or `windows-server/2025` for Windows BYOI images intended to run on Harness Cloud.
{% endhint %}

**Advanced options:**

| Type                     | Format                                            | Example                  |
| ------------------------ | ------------------------------------------------- | ------------------------ |
| Harness pre-configured   | `{name}`                                          | `ubuntu-v1-hosted-amd64` |
| Your previous BYOI image | `byoi-{sanitizedAccountId}-{imageName}-{version}` | `byoi-abc123-my-base-v1` |

To use a previous BYOI image, specify the **full image name** (as shown in build output), not `imageName:version`.

**Note:** Account IDs are sanitized in image names: lowercase, `_` becomes `-`, and special characters are removed. For example, if your account ID is `My_Account_123`, your images are stored as `byoi-my-account-123-...`.

***

## Writing Your Packer File <a href="#writing-your-packer-file" id="writing-your-packer-file"></a>

You provide **variables** and **provisioners**. Harness handles source configuration, authentication, and cleanup automatically.

### Example with Variables <a href="#example-with-variables" id="example-with-variables"></a>

```hcl
# Define reusable variables <a href="#define-reusable-variables" id="define-reusable-variables"></a>
variable "java_version" {
  type    = string
  default = "17"
}

variable "maven_version" {
  type    = string
  default = "3.9.6"
}

# Install Java <a href="#install-java" id="install-java"></a>
provisioner "shell" {
  inline = [
    "sudo apt-get update",
    "sudo apt-get install -y openjdk-${var.java_version}-jdk"
  ]
}

# Install Maven <a href="#install-maven" id="install-maven"></a>
provisioner "shell" {
  inline = [
    "wget -q https://archive.apache.org/dist/maven/maven-3/${var.maven_version}/binaries/apache-maven-${var.maven_version}-bin.tar.gz",
    "sudo tar -xzf apache-maven-${var.maven_version}-bin.tar.gz -C /opt",
    "sudo ln -s /opt/apache-maven-${var.maven_version} /opt/maven",
    "rm apache-maven-${var.maven_version}-bin.tar.gz"
  ]
}
```

### Copying Files <a href="#copying-files" id="copying-files"></a>

```hcl
# Copy files from your repo into the image <a href="#copy-files-from-your-repo-into-the-image" id="copy-files-from-your-repo-into-the-image"></a>
provisioner "file" {
  source      = "configs/app.conf"
  destination = "/tmp/app.conf"
}

provisioner "shell" {
  inline = ["sudo mv /tmp/app.conf /etc/myapp/app.conf"]
}
```

### What Harness Adds Automatically <a href="#what-harness-adds-automatically" id="what-harness-adds-automatically"></a>

**Linux:**

* Git, Git LFS, wget, curl, CA certificates
* Docker (configurable version)
* `git safe.directory *` configuration
* HOME environment variable
* Cleanup (apt cache, logs) to reduce image size

### What Gets Ignored <a href="#what-gets-ignored" id="what-gets-ignored"></a>

If your Packer file contains `source` or `build` blocks, they will be ignored. Harness uses its own secure configuration. Only your `variable` and `provisioner` blocks are used.

***

## Limitations <a href="#limitations" id="limitations"></a>

### Image Naming <a href="#image-naming" id="image-naming"></a>

* `imageName`: 3-30 characters, must start with lowercase letter
* `imageVersion`: 1-20 characters, must start/end with alphanumeric
* Combined length of `imageName` + `imageVersion` should not exceed \~35 characters (the full name includes your account ID)

### Platform <a href="#platform" id="platform"></a>

* **Linux:** Ubuntu (amd64 and arm64)
* **Windows:** Windows Server 2022 or 2025 (amd64 only). The builder plugin also accepts `windows-server/2019`, but that version is not yet qualified to run as CI VMs on Harness Cloud.
* **macOS:** Coming soon
* Harness Cloud only. Self-hosted runners are not supported.

### Image storage and registry <a href="#image-storage-and-registry" id="image-storage-and-registry"></a>

* Linux and Windows BYOI images must be built with the Harness BYOI builder plugin and are stored in Harness-managed storage.
* Linux and Windows BYOI do not support supplying a custom image connector. The [Override Image Connector](/harness-platform/use-harness-platform/connectors/artifact-repositories/connect-to-harness-container-image-registry-using-docker-connector.md) stage infrastructure setting does not apply to the Linux or Windows BYOI VM image, so you cannot point Linux or Windows BYOI at an image hosted in your own registry.
* Reference Linux and Windows BYOI images by `imageName:imageVersion` only. To build on top of an existing image, go to [Supported Base Images](#supported-base-images) to use the full Harness-managed image name as `baseImage`.
* This restriction applies only to the BYOI VM image. Step-level `image:` fields inside your pipeline (for example, on a Run step) continue to honor their own `connectorRef` and can pull from any registry as usual.

### Build Process <a href="#build-process" id="build-process"></a>

* Maximum build time: 3 hours (bounded by authentication token lifetime)
* Automatic retries: 3 attempts on transient failures
* Disk size: 100GB
* Cannot build same image name/version concurrently

### Security <a href="#security" id="security"></a>

Do not include credentials in your Packer file. The following patterns will cause the build to fail:

* `credentials = "..."`
* `account_file = "..."`
* `access_token = "..."`

Harness injects credentials securely.

***

## Troubleshooting <a href="#troubleshooting" id="troubleshooting"></a>

| Issue                        | Solution                                             |
| ---------------------------- | ---------------------------------------------------- |
| Build fails                  | Set `debug: "true"` to see detailed Packer output    |
| "Image name too long" error  | Shorten `imageName` or `imageVersion`                |
| "Image already exists" error | Use `mode: delete` first, or use a different version |
| Packer file not found        | Check `packerFilePath` is relative to repo root      |
| Authentication error         | Contact Harness support                              |
| Build times out              | The maximum build time is 3 hours.                   |

***

## FAQ <a href="#faq" id="faq"></a>

**Can I use my image across all projects?** Yes, BYOI images are available to all projects in your account.

**Can I build on ARM64?** Yes, set `targetArch: arm64` in your plugin settings (Linux only).

**Can I build on top of a previous BYOI image?** Yes. Use the full image name from your previous build output as `baseImage`. For example: `baseImage: byoi-abc123-my-base-v1` (not `my-base:v1`). Note that the account ID in the image name is sanitized (lowercase, `_` → `-`, special chars removed). You can only use your own account's BYOI images.

**Can I host my Linux or Windows BYOI image in my own registry and pull it with an image connector?** No. Linux and Windows BYOI do not support supplying a custom image connector, and the [Override Image Connector](/harness-platform/use-harness-platform/connectors/artifact-repositories/connect-to-harness-container-image-registry-using-docker-connector.md) stage infrastructure setting does not apply to the Linux or Windows BYOI VM image. The image must be built with the Harness BYOI builder plugin and served from Harness-managed storage. Reference it by `imageName:imageVersion`.

**Do I need to set mode to build?** No, `build` is the default mode. You only need to explicitly set `mode: delete` when deleting an image.

**What is the maximum build time?** 3 hours, bounded by the GCP authentication token lifetime. If your build needs more time, optimize your Packer provisioners.

***

## Support <a href="#support" id="support"></a>

If you encounter issues:

1. Enable `debug: "true"` for verbose logs
2. Check the error message against the troubleshooting table above
3. Contact Harness support
