> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hyperlane.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Deploy Hyperlane with Local Agents

> Advanced guide for deploying Hyperlane with local validators and relayers

<Tip>
  This guide is for advanced users who may eventually intend to run Hyperlane
  agents in a production-like environment. It will cover the basics of how to
  manually configure and run agents but **it is not a production setup guide**.
</Tip>

## Overview

There are six steps in this guide:

1. **Set up keys** that you will use to deploy contracts and run validators and relayers
2. **Deploy contracts** to the local chain and to every remote chain with which the local chain will be able to send and receive messages
3. **Run a validator** to provide the signatures needed for the Interchain Security Modules you deployed
4. **Run a relayer** to send and receive messages between the chains you deployed contracts to
5. **Send a test message** to confirm that your relayer is able to deliver messages to and from each pair of chains
6. **Deploy a Hyperlane Warp Route (HWR)** to send token value, not just messages, across chains

## Getting Started

## 1. Set up keys

Set up your keys for deploying contracts and running agents.

## 2. Deploy contracts

Deploy Hyperlane contracts to your chains.

## 3. Run a validator

Validators provide the security for messages sent *from* your chain to remote chains. They're only required when using a [Multisig ISM](/docs/protocol/ISM/standard-ISMs/multisig-ISM). Learn more about what validators do [here](/docs/protocol/agents/validators).

### Setup directories

First, generate an agent config file using the Hyperlane CLI. If you have a local registry with custom chain configurations, pass the registry path to the command:

```bash theme={null}
hyperlane registry agent-config --chains <chains separated by space> --registry /path/to/your/registry
```

This will create an agent config at `./configs/agent-config.json`.

Then, set the `CONFIG_FILES` environment variable to the path of the generated agent config:

```bash theme={null}
export CONFIG_FILES=/full/path/to/configs/agent-config.json
```

Next, create a local directory for your validator to write its signatures to. Remember the path, as you will need this when configuring your validator.

<Warning>
  The validator signatures path will be written on-chain as part of the
  [validator announcement
  transaction](/docs/alt-vm-implementations/implementation-guide#validator-announce).
  **Be careful not to reveal any security-sensitive or personal information!**
</Warning>

```bash theme={null}
# Pick an informative name specific to the chain you're validating
export VALIDATOR_SIGNATURES_DIR=/tmp/hyperlane-validator-signatures-<your_chain_name>

# Create the directory
mkdir -p $VALIDATOR_SIGNATURES_DIR
```

<Note>
  You will not be able to mount anything in `/tmp` when running the agent via Docker on Mac. To counter this, create a local `tmp` directory to mount instead.

  ```bash theme={null}
  # Create a local tmp directory that can be accessed by docker
  mkdir tmp

  # Pick an informative name specific to the chain you're validating
  export VALIDATOR_SIGNATURES_DIR=tmp/hyperlane-validator-signatures-<your_chain_name>

  # Create the directory
  mkdir -p $VALIDATOR_SIGNATURES_DIR
  ```
</Note>

### Configure

There are numerous parameters that validators can be configured with. For this guide, we are concerned with just a handful:

| Parameter                 | Description                                                                                                   |
| ------------------------- | ------------------------------------------------------------------------------------------------------------- |
| `--db`                    | Path for writing persistent data to disk.                                                                     |
| `--originChainName`       | Name of the chain being validated (e.g. `ethereum`).                                                          |
| `--checkpointSyncer.type` | Set to `localStorage` for this guide.                                                                         |
| `--checkpointSyncer.path` | Path to local directory where validator signatures will be written. Same path as `$VALIDATOR_SIGNATURES_DIR`. |
| `--validator.key`         | Your validator's hexadecimal private key.                                                                     |

<Info>
  Make sure the validator key corresponds to the address provided when setting
  up your MultisigIsmConfig. Otherwise, the Multisig ISM you deployed in the
  previous step will not be able to verify messages sent from your chain.
</Info>

To learn more about all the parameters you can change, read the [agent configuration reference](/docs/operate/config/config-reference).

<Tabs>
  <Tab title="Using Docker">
    **Update agent config**

    Unless you are running Docker on Linux, you will also need to update the agent configuration for your network. This is because Docker does not support the [`host` network mode](https://docs.docker.com/network/drivers/host/) on Mac, Windows or Windows Server.

    To do this, navigate to the agent-configuration at `$CONFIG_FILES` and replace all instances of "localhost" or "127.0.0.1" in to `host.docker.internal`. For example:

    ```json theme={null}
    ...
    "localnet1": {
      ...
      "rpcUrls": [
        {
          // "http": "http://localhost:8545"
          // "http": "http://127.0.0.1:8545"
          "http": "http://host.docker.internal:8545"
        }
      ],
      ...
    },
    ...
    ```

    **Mounting directories**

    Running with Docker adds an extra layer of complexity because config files need to be accessible from within the Docker container, and validator signatures need to be accessible from outside of the container for the relayer to read. This is so the relayer can construct the metadata required for the message to be successfully validated by the Multisig ISM.

    To solve this issue, you can mount directories on your file system into the container. In the arguments below, we:

    1. Set the `$CONFIG_FILES` environment variable to a fixed path within the container.
    2. Mount the agent config file to this fixed path and making it readonly.
    3. Mount the persistent data directory at a fixed path within the container.
    4. Mount the validator signatures directory to a fixed path within the container.

    ```bash theme={null}
    ...
    -e CONFIG_FILES=/config/agent-config.json \
    --mount type=bind,source=$CONFIG_FILES,target=/config/agent-config.json,readonly \
    --mount type=bind,source="$(pwd)"/hyperlane_db_validator_<your_chain_name>,target=/hyperlane_db \
    --mount type=bind,source="$(pwd)"/$VALIDATOR_SIGNATURES_DIR,target=/tmp/validator-signatures \
    ...
    ```

    Hardcoding these paths deduplicates the configuration between docker instances running validators for different origin chains. This makes it easier to pass the right arguments when running the container. See the example below, where the only items to be configured differently for different chains are the chain name and validator key.

    ```bash theme={null}
    ...
    ./validator \
    --db /hyperlane_db \
    --originChainName <your_chain_name> \
    --checkpointSyncer.type localStorage \
    --checkpointSyncer.path /tmp/validator-signatures \
    --validator.key <your_validator_key>
    ...
    ```
  </Tab>

  <Tab title="Building from source">
    **Clone and setup**

    First, clone the Hyperlane monorepo:

    ```bash theme={null}
    git clone git@github.com:hyperlane-xyz/hyperlane-monorepo.git
    ```

    Then follow the [setup instructions](https://github.com/hyperlane-xyz/hyperlane-monorepo/blob/main/rust/README.md) in the `rust` directory. This should setup `rustup` as well as Rosetta 2 if you are on Apple Silicon.

    ```bash theme={null}
    # install rustup
    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

    # (apple silicon only) install rosetta 2
    softwareupdate --install-rosetta --agree-to-license
    ```
  </Tab>
</Tabs>

### Run

<Tabs>
  <Tab title="Using Docker">
    Now that you understand more about configuring validator arguments, pull the latest docker image:

    ```bash theme={null}
    docker pull --platform linux/amd64 ghcr.io/hyperlane-xyz/hyperlane-agent:agents-v2.2.0
    ```

    Before running, ensure that all directories you need to mount are present. This may involve creating `hyperlane_db_validator_<your_chain_name>` if it does not exist yet.

    ```bash theme={null}
    mkdir -p hyperlane_db_validator_<your_chain_name>
    ```

    Finally, run the validator:

    ```bash theme={null}
    docker run \
      -it \
      -e CONFIG_FILES=/config/agent-config.json \
      --mount type=bind,source=$CONFIG_FILES,target=/config/agent-config.json,readonly \
      --mount type=bind,source="$(pwd)"/hyperlane_db_validator_<your_chain_name>,target=/hyperlane_db \
      --mount type=bind,source="$(pwd)"/$VALIDATOR_SIGNATURES_DIR,target=/tmp/validator-signatures \
      ghcr.io/hyperlane-xyz/hyperlane-agent:agents-v2.2.0 \
      ./validator \
      --db /hyperlane_db \
      --originChainName <your_chain_name> \
      --checkpointSyncer.type localStorage \
      --checkpointSyncer.path /tmp/validator-signatures \
      --validator.key <your_validator_key>
    ```
  </Tab>

  <Tab title="Building from source">
    After following the setup instructions, you should now be able to use `cargo` to run the Validator:

    ```bash theme={null}
    cargo run --release --bin validator -- \
        --db ./hyperlane_db_validator_<your_chain_name> \
        --originChainName <your_chain_name> \
        --checkpointSyncer.type localStorage \
        --checkpointSyncer.path $VALIDATOR_SIGNATURES_DIR \
        --validator.key <your_validator_key>
    ```

    <Note>
      **Optional: Run the binary directly**

      You can alternatively build out the agent:

      ```bash theme={null}
      cargo build --release --bin validator
      ```

      And run the binary directly:

      ```bash theme={null}
      ./target/release/validator \
          --db ./hyperlane_db_validator_<your_chain_name> \
          --originChainName <your_chain_name> \
          --checkpointSyncer.type localStorage \
          --checkpointSyncer.path $VALIDATOR_SIGNATURES_DIR \
          --validator.key <your_validator_key>
      ```
    </Note>
  </Tab>
</Tabs>

<Tip>
  For further information, check out the [Validators
  guide](/docs/operate/validators/run-validators). To learn about running
  multiple validators, see [this
  section](/docs/operate/validators/run-validators#running-multiple-validators).
</Tip>

## 4. Run a relayer

<Tip>
  * **Single Relayer Recommendation**: A single relayer is generally sufficient
    and can handle message delivery across 100+ chains efficiently. You don't need
    to run separate relayers for each network - this approach actually increases
    operational complexity without providing performance benefits.
</Tip>

<Warning>
  * **Trusted Relayer ISM Key Management**: If you're using a trusted relayer
    ISM (which is not recommended for production), avoid using the same relayer
    key across multiple relayer instances as this can cause nonce conflicts and
    transaction failures. Either run a single relayer or use different keys for
    each relayer.
  * For production deployments, use a multisig ISM instead of
    trusted relayer ISM.
</Warning>

Relayers deliver interchain messages sent between the local and remote chains. Learn more about what relayers do [here](/docs/protocol/agents/relayer).

You should already have set the `CONFIG_FILES` environment variable to the path of the agent config generated in the [agent configs](#agent-configs) step. If not, do so now.

```bash theme={null}
export CONFIG_FILES=/full/path/to/configs/agent-config.json
```

### Configure

There are numerous parameters that relayers can be configured with. For this guide, we are concerned with just a handful:

| Parameter                       | Description                                                                              |
| ------------------------------- | ---------------------------------------------------------------------------------------- |
| `--db`                          | Path for writing persistent data to disk.                                                |
| `--relayChains`                 | Comma separated names of the chains to relay between. E.g. `ethereum,polygon,avalanche`. |
| `--allowLocalCheckpointSyncers` | Allows the relayer to look for validator signatures on the local filesystem.             |
| `--defaultSigner.key`           | A hexadecimal private key used to sign transactions for all chains.                      |
| `--metrics-port`                | Optional. The port to expose prometheus metrics on, defaults to `9090`.                  |

<Tip>
  Your set of relay chains should include both the origin chain and the
  destination chain.
</Tip>

To learn more about all the parameters you can change, read the [agent configuration reference](/docs/operate/config/config-reference).

<Tabs>
  <Tab title="Using Docker">
    **Mounting directories**

    For the relayer, we provide almost the same arguments to Docker as the validator:

    1. Set the `$CONFIG_FILES` environment variable to a fixed path within the container.
    2. Mount the agent config file to this fixed path and making it **readonly**.
    3. Mount the persistent data directory at a fixed path within the container.
    4. Mount the validator signatures directory to a fixed path within the container and making it **readonly**.

    ```bash theme={null}
    ...
    -e CONFIG_FILES=/config/agent-config.json \
    --mount type=bind,source=$CONFIG_FILES,target=/config/agent-config.json,readonly \
    --mount type=bind,source="$(pwd)"/hyperlane_db_relayer,target=/hyperlane_db \
    --mount type=bind,source="$(pwd)"/$VALIDATOR_SIGNATURES_DIR,target=/tmp/validator-signatures,readonly \
    ...
    ```

    Hardcoding these paths deduplicates the configuration between docker instances running relayers for different sets of chains. This makes it easier to pass the right arguments when running the container. See the example below, where the only items to be configured differently for different chains are the list of chains to relay between and the relayer key.
  </Tab>

  <Tab title="Building from source">
    **Clone and setup**

    If you haven't already done so, clone the Hyperlane monorepo and follow the [setup instructions](https://github.com/hyperlane-xyz/hyperlane-monorepo/blob/main/rust/README.md) in the `rust` directory.

    ```bash theme={null}
    # clone hyperlane monorepo
    git clone git@github.com:hyperlane-xyz/hyperlane-monorepo.git

    # install rustup
    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

    # (apple silicon only) install rosetta 2
    softwareupdate --install-rosetta --agree-to-license
    ```
  </Tab>
</Tabs>

### Run

<Tabs>
  <Tab title="Using Docker">
    If you haven't already pulled the Docker image, do this now by running:

    ```bash theme={null}
    docker pull --platform linux/amd64 ghcr.io/hyperlane-xyz/hyperlane-agent:agents-v2.2.0
    ```

    Before running, ensure that all directories you need to mount are present. This may involve creating `hyperlane_db_relayer` if it does not exist yet.

    ```bash theme={null}
    mkdir -p hyperlane_db_relayer
    ```

    Finally, run the relayer:

    ```bash theme={null}
    docker run \
      -it \
      -e CONFIG_FILES=/config/agent-config.json \
      --mount type=bind,source=$CONFIG_FILES,target=/config/agent-config.json,readonly \
      --mount type=bind,source="$(pwd)"/hyperlane_db_relayer,target=/hyperlane_db \
      --mount type=bind,source="$(pwd)"/$VALIDATOR_SIGNATURES_DIR,target=/tmp/validator-signatures,readonly \
      ghcr.io/hyperlane-xyz/hyperlane-agent:agents-v2.2.0 \
      ./relayer \
      --db /hyperlane_db \
      --relayChains <chain_1_name>,<chain_2_name> \
      --allowLocalCheckpointSyncers true \
      --defaultSigner.key <your_relayer_key> \
    ```
  </Tab>

  <Tab title="Building from source">
    After following the setup instructions, you should now be able to use `cargo` to run the Relayer:

    ```bash theme={null}
    cargo run --release --bin relayer -- \
        --db ./hyperlane_db_relayer \
        --relayChains <chain_1_name>,<chain_2_name> \
        --allowLocalCheckpointSyncers true \
        --defaultSigner.key <your_relayer_key> \
        --metrics-port 9091
    ```

    The metrics port is overridden to avoid clashing with the validator.

    <Note>
      **Optional: Run the binary directly**

      You can alternatively build out the agent:

      ```bash theme={null}
      cargo build --release --bin relayer
      ```

      And run the binary directly:

      ```bash theme={null}
      ./target/release/relayer \
          --db ./hyperlane_db_relayer \
          --relayChains <chain_1_name>,<chain_2_name> \
          --allowLocalCheckpointSyncers true \
          --defaultSigner.key <your_relayer_key> \
          --metrics-port 9091
      ```
    </Note>
  </Tab>
</Tabs>

<Tip>
  For further information, check out the [Relayer
  guide](/docs/operate/relayer/run-relayer).
</Tip>

## 5. Send test messages

Send test messages to verify your setup is working correctly.

## 6. (Optional) Deploy a Hyperlane Warp Route

To connect tokens using your new Hyperlane deployment, see the [Hyperlane Warp Route deployment guide](/docs/guides/quickstart/deploy-warp-route).
