# Sign a bundle

Create a signing key, sign a build, and give the target machine the public key it needs.

Source: https://debark.dev/docs/trust/signing

---
Signing lets the target check who prepared a bundle and whether its contents have changed. The private key stays with the builder. The public key goes to the people who will verify and install the bundle.

## Create a key pair

On the online builder:

```bash
debark keygen --out operator.key --comment "Package bundles"
```

This creates:

- `operator.key`: the private Ed25519 signing key.
- `operator.pub`: the public verification key.

The private key is unencrypted. Keep it outside source control and shared folders, with access limited to whoever should be able to sign builds. Use GPG if you need a passphrase-protected key.

If your output name does not end in `.key`, the public filename gets `.pub` appended instead.

## Build with the key

```bash
debark build --snapshot target.snapshot.tar.zst \
  --out ./bundle --sign operator.key jq
```

An explicit `--sign` makes signing required. A missing or unusable key fails the build.

Check the result:

```bash
debark verify ./bundle --key operator.pub
```

## Give the target your public key

Provide `operator.pub` through a trusted channel separate from the bundle, for example during machine setup. Never transfer the private key.

A key supplied alongside an unfamiliar bundle does not establish who created it. Debark also refuses verification keys whose paths are inside the bundle folder.

On the target:

```bash
debark verify ./bundle --key operator.pub
sudo debark install ./bundle --key operator.pub --yes
```

For regular use, set `verify_keys` in the target’s [configuration](/docs/reference/configuration).

## Use an existing GPG key

If you already manage keys with GPG, use `--sign gpg:KEY_ID`. Replace the value below with your signing key’s fingerprint:

```bash
SIGNING_FINGERPRINT='replace-with-your-gpg-signing-key-fingerprint'
debark build --snapshot target.snapshot.tar.zst \
  --out ./bundle --sign "gpg:$SIGNING_FINGERPRINT" jq
```

The builder needs GPG and access to that signing key. On the target, provide a GPG keyring containing the expected public key:

```bash
debark verify ./bundle --gpg-keyring release-keys.gpg
```

`--gpg-keyring` takes a file. `--keyring` takes a directory of Ed25519 public keys. Without `--gpg-keyring`, GPG uses the machine’s default keyring.

## Use a signing plugin

`--sign plugin:NAME` lets an external signer handle the private key. This is useful when your organization already has a signing service or hardware-backed key.

Plugin setup depends on the signer. Developers integrating one can use the [plugin schema](https://github.com/inferops/debark/blob/main/api/schema/plugin.v1.schema.json) and the signer implementation in the source repository.

## Default and unsigned builds

Without `--sign` or `--no-sign`, the build uses a configured `sign_key` if available. Signing is not required in this mode. Use an explicit `--sign` in scripts that must produce signed bundles.

To deliberately create an unsigned bundle, pass `--no-sign`. Verification and installation then require `--allow-unsigned`. This checks file integrity without requiring a valid signature from a trusted builder.

<NextSteps
  items={[
    {
      title: 'Verify a bundle',
      href: '/docs/trust/verifying',
      description: 'Check the signature and files.',
    },
    {
      title: 'How verification works',
      href: '/docs/trust/trust-model',
      description: 'Understand what signing does and does not establish.',
    },
  ]}
/>
