<a id="gateway-deploy-docker"></a>

# Configure and Deploy Confluent Gateway using Docker

Configure and deploy Confluent Gateway using Docker. You can use
this deployment path to run Confluent Gateway on-premises, in VPCs,
and across hybrid environments.

For general requirements and considerations, see
[Requirements and considerations](gateway-deploy-overview.md#gateway-deploy-requirements). For Docker-specific requirements, see
[Docker software requirements](gateway-deploy-overview.md#gateway-deploy-docker-software-requirements).

Deploy Confluent Gateway using Docker with the following steps:

1. [Configure Confluent Gateway](#gateway-config-using-docker) by
   defining streaming domains, routes, and administration settings in a
   Docker Compose file.
2. [Deploy Confluent Gateway](#gateway-install-with-docker) by pulling
   the Confluent Gateway Docker image and starting the service with Docker Compose.

After deployment, configure security and reconfigure clients to use the
Confluent Gateway endpoint. For more information, see [Next steps](#gateway-deploy-next-steps).

<a id="gateway-config-using-docker"></a>

## Configure Confluent Gateway using Docker Compose

Provide the configuration settings in a Docker Compose YAML file. This guide
uses `docker-compose.yaml` as an example.

The top-level layout for the Confluent Gateway configuration file is as follows:

```yaml
gateway:
  name:                   --- [1]
  streamingDomains: []    --- [2]
  secretStores: []        --- [3]
  routes: []              --- [4]
  admin: {}               --- [5]
```

* [1] The Confluent Gateway instance identifier.
* [2] A list of streaming domains that represent Apache Kafka® clusters. For more
  information, see [Streaming domains configuration](#gateway-config-streaming-domains-docker).
* [3] A list of secret stores. Required for authentication swapping. For
  details, see [Secret store configuration](gateway-security.md#gateway-secret-stores-docker).
* [4] A list of client routing rules. For more information, see
  [Routes configuration](#gateway-config-routes-docker).
* [5] Admin and metrics configuration. For more information, see
  [Administration and metrics configuration](#gateway-config-admin-metrics-docker).

The Confluent Gateway Docker image is not a Confluent Gateway configuration setting. Set it
with the `image` key on the Docker Compose service. Use
`confluentinc/confluent-gateway:<version_tag>`, where `<version_tag>` is the
Confluent Gateway version.

<a id="gateway-config-streaming-domains-docker"></a>

### Streaming domains configuration

Streaming domains are logical representations of your Kafka clusters in
Confluent Gateway.

```yaml
gateway:
  streamingDomains:
    - name:               --- [1]
      type:               --- [2]
      kafkaCluster:       --- [3]
        name:             --- [4]
        bootstrapServers: --- [5]
          - id:           --- [6]
            endpoint:     --- [7]
            ssl:          --- [8]
        nodeIdRanges:     --- [9]
          - name:         --- [10]
            start:        --- [11]
            end:          --- [12]
```

* [1] A unique name for the streaming domain.
* [2] The type of the streaming domain. Set to `kafka` by default.
* [3] A Kafka cluster, including Confluent Server, or Apache Kafka®, that the
  Confluent Gateway can route traffic to.
* [4] The name of the Kafka cluster.
* [5] A list of Kafka bootstrap servers in the format `host:port`. At
  minimum, one bootstrap server is required per Kafka cluster. For each
  listener, you can define one bootstrap server.
* [6] A unique identifier for the bootstrap server. Use the protocol name,
  such as `SASL_PLAINTEXT`, `SSL`, or `PLAINTEXT_SASL_PLAIN`,
  for clear distinction between the TLS channel type and SASL mechanism.
* [7] The bootstrap endpoint of the Kafka broker in the format:
  `host:port`.
* [8] Only required for SSL/SASL_SSL configuration. Supported certificate
  types are `JKS`, `PKCS12`, and `PEM`.

  For details, see [SSL configuration](gateway-security.md#gateway-ssl-docker).
* [9] The node ID ranges. Only required for port-based broker identification.
  These should be the broker IDs defined in the Kafka deployment.
* [10] The name of the node ID range.
* [11] The start of the node ID range, inclusive.
* [12] The end of the node ID range, inclusive.

An example configuration for a Confluent Gateway streaming domain:

```yaml
streamingDomains:
  - name: sales # unique across gateway
    type: kafka # default: kafka
    kafkaCluster:
      name: sales-cluster # default: <streamingDomain.name>
      bootstrapServers:
        - id: PLAINTEXT-1
          endpoint: kafka0.example.com:9092
        - id: SASL_SSL-1
          endpoint: kafka0.example.com:9093
          ssl:  # required when using SASL_SSL/SSL
            ignoreTrust: false
            truststore:
              type: PKCS12  # default: JKS
              location: /opt/ssl/client-truststore.p12
              password:
                file: /opt/secrets/client-truststore.password
            keystore: # gateway's identity when needed
              type: PKCS12 # default: JKS
              location: /opt/ssl/gw-keystore.p12
              password:
                file: /opt/secrets/gw-keystore.password
              keyPassword:
                value: inline-password
      nodeIdRanges:
        - name: default
          start: 0              # inclusive
          end: 3                # inclusive
```

* `password` can be a file path or an inline value. For details, see
  [Password configuration](gateway-security.md#gateway-password-docker).
* `ignoreTrust` skips certificate validation. Not recommended for
  production. When `true`, Confluent Gateway ignores the `truststore` setting.

<a id="gateway-config-routes-docker"></a>

### Routes configuration

Routes are Confluent Gateway endpoints where client applications connect to stream
data.

Confluent Gateway uses routes to define how client applications connect to Kafka
clusters. Clients connect to Confluent Gateway as if it were a Kafka cluster, while
Confluent Gateway handles routing and governance.

```yaml
gateway:
  routes:
    - name:                         --- [1]
      endpoint:                     --- [2]
      mode:                         --- [3]
      brokerIdentificationStrategy: --- [4]
        type:                       --- [5]
        pattern:                    --- [6]
      streamingDomain:              --- [7]
        name:                       --- [8]
        bootstrapServerId:          --- [9]
      streamingDomains:             --- [10]
        - name:                     --- [11]
          bootstrapServerId:        --- [12]
      rules:                        --- [13]
      security:                     --- [14]
```

* [1] The unique name for the route. The name can’t contain spaces.
* [2] The `host:port` combination that Confluent Gateway listens on. This is
  the external address clients use to bootstrap to the Kafka cluster.
* [3] **Early Access.** Optional. The routing mode of the route. Set to
  `STATIC` or `DYNAMIC`. The value isn’t case-sensitive.
  * `STATIC`: The route is bound to a single streaming domain ([7]).
  * `DYNAMIC`: The route uses [topic-based routing](gateway-topic-based-routing.md#gateway-topic-based-routing). You bind it to a list of streaming domains
    ([10]), and it routes each topic to the streaming domain that owns it.

  If you omit `mode`, Confluent Gateway infers it from the streaming domain binding:
  `streamingDomain` ([7]) sets the mode to `STATIC`, and
  `streamingDomains` ([10]) sets the mode to `DYNAMIC`. If you set
  `mode`, it must match the binding. For example, `mode: DYNAMIC` with
  `streamingDomain` is invalid.
* [4] Specifies the strategy for mapping client requests to a specific Kafka
  broker.
* [5] The type of broker identification strategy. Set to `port` (the default)
  or `host`. A dynamic route ([10]) supports only the `host` strategy.
  Confluent Gateway assigns its own node IDs to the brokers of the bound clusters, so
  overlapping broker IDs across clusters don’t conflict.
  * `port` strategy: Each Kafka broker is identified using a unique port
    number. This is the default strategy.

    Clients connect to different ports to reach specific brokers. For example,
    port 9092 to connect with broker-0, port 9093 to connect with broker-1.

    The `nodeIdRanges` from the streaming domain configured in
    [Streaming domains configuration](#gateway-config-streaming-domains-docker) is used. The
    `nodeIdRanges` must be present in the streaming domain associated
    with the route.
  * `host` strategy: Each Kafka broker is represented using a unique hostname.

    Clients use different host names to reach specific brokers, such as
    `broker-0.kafka.company.com` and `broker-1.kafka.company.com`, and
    Confluent Gateway routes based on the Server Name Indication (SNI) header.
    Because SNI is part of the TLS handshake, configure TLS on the route. For
    more information, see [SSL configuration](gateway-security.md#gateway-ssl-docker).

    The `host` strategy uses the `pattern` setting ([6]).
* [6] The pattern for the broker identification strategy. Required if the type
  ([5]) is `host`. For example,
  `broker-$(nodeId).eu-gw.sales.example.com:9092`.
* [7] The reference to a streaming domain. Use this setting for a static
  route. Required if the route doesn’t use `streamingDomains` ([10]).
* [8] The name of the streaming domain. Must be a valid name from the
  `gateway.streamingDomains[].name`.
* [9] The bootstrap server ID. Must match
  `kafkaCluster.bootstrapServers[].id`.
* [10] **Early Access.** The list of references to streaming domains that the
  route is bound to. Use this setting for a dynamic route. Required if the
  route doesn’t use `streamingDomain` ([7]). Setting `streamingDomains`
  makes the route a dynamic route. You can’t bind the same streaming domain
  more than once, and the list can’t contain null entries.
* [11] The name of a streaming domain to bind to the route.
  Must be a valid name from the `gateway.streamingDomains[].name`.
* [12] The bootstrap server ID to use for the streaming
  domain ([11]). Must match `kafkaCluster.bootstrapServers[].id`.
* [13] Optional. The routing rules (Early Access) and fencing rules of the
  route. For more information, see [Routing rules configuration (Early Access)](#gateway-config-dynamic-routing-rules-docker)
  and [Fencing rules configuration](#gateway-config-fence-rules-docker).
* [14] The security configuration. For more information, see
  [Configure Security for Confluent Gateway](gateway-security.md#gateway-security-docker).

Each route must specify exactly one of `streamingDomain` ([7]) or
`streamingDomains` ([10]). Specifying both or neither is invalid.

The following examples show a static route and a dynamic route:

### Static route

A static route binds one streaming domain with `streamingDomain`.

```yaml
gateway:
  routes:
    - name: eu-sales
      endpoint: eu-gw.sales.example.com:9092
      brokerIdentificationStrategy:
        type: host
        pattern: broker-$(nodeId).eu-gw.sales.example.com:9092
      streamingDomain:
        name: sales
        bootstrapServerId: SASL_SSL-1
```

### Dynamic route (Early Access)

A dynamic route binds a list of streaming domains with
`streamingDomains` and requires `rules.routing`. For more
information, see [Routing rules configuration (Early Access)](#gateway-config-dynamic-routing-rules-docker).

```yaml
gateway:
  routes:
    - name: migration-route
      endpoint: migration-gw.example.com:9092
      mode: DYNAMIC
      brokerIdentificationStrategy:
        type: host
        pattern: broker-$(nodeId).migration-gw.example.com:9092
      streamingDomains:
        - name: cp
          bootstrapServerId: cp-bootstrap
        - name: cc
          bootstrapServerId: cc-bootstrap
      rules:
        routing:
          coordination:
            group: cc
          default: cp
```

<a id="gateway-config-dynamic-routing-rules-docker"></a>

### Routing rules configuration (Early Access)

Configure `rules.routing` on dynamic routes (`mode: DYNAMIC`) to map
topics to specific streaming domains. For more information, see
[Routes configuration](#gateway-config-routes-docker).

You configure routing rules in the `rules.routing` setting of the route. A
dynamic route requires `rules.routing`, and a static route can’t use it.

* To learn how to migrate a topic with routing rules, see
  [Migrate topics between clusters](gateway-topic-based-routing.md#gateway-topic-based-routing-migrate).
* To review the limitations, see
  [Limitations](gateway-topic-based-routing.md#gateway-topic-based-routing-limitations).

#### NOTE
Topic-based routing is an **Early Access** feature. Property names and YAML
structure might change before General Availability (GA), and the changes
might not be backward compatible.

```yaml
gateway:
  routes:
    - name:
      streamingDomains:
      rules:
        routing:                        --- [1]
          coordination:                 --- [2]
            group:                      --- [3]
          conditions:                   --- [4]
            - topics:                   --- [5]
              topicPatterns:            --- [6]
              streamingDomain:          --- [7]
          conditionsFile:               --- [8]
          default:                      --- [9]
```

* [1] The routing rules that map topics to the streaming domains that own them.
  Required on a dynamic route.
* [2] Required. Pins consumer group coordination to a streaming domain.
* [3] Required. The name of the streaming domain that coordinates all consumer
  groups on the route, including their committed offsets. Must be a streaming
  domain bound to the route. All consumer group offsets for the route are stored
  on this cluster. Disable consumer offset sync on the cluster link, and on any
  other replicator that you use, so that replication doesn’t overwrite offsets
  that clients commit through Confluent Gateway.
* [4] Optional. The list of conditions that map topics to
  streaming domains. Confluent Gateway evaluates the conditions in order, and the first
  condition that matches a topic decides which streaming domain owns it. You
  can’t use `conditions` with `conditionsFile` ([8]).
* [5] A list of exact topic names. Confluent Gateway matches topic names literally.
* [6] A list of Java regular expressions. A pattern must match the entire topic
  name. For example, the pattern `teamA.*` matches `teamA-orders`, but the
  pattern `teamA` doesn’t. Confluent Gateway validates the patterns when it loads the
  configuration.

  To match a literal period, escape it with a backslash. How you write the
  backslash depends on the type of YAML string:
  * In a double-quoted string, write the backslash twice, for example
    `"teamA\\..*"`.
  * In a single-quoted or unquoted string, write the backslash once, for
    example `'teamA\..*'`.

  Both examples match topics that start with `teamA.`.

  A condition matches a topic if the topic is listed in `topics` ([5]) or
  matches any pattern in `topicPatterns` ([6]). Each condition requires at
  least one of `topics` or `topicPatterns`.
* [7] Required for each condition. The name of the streaming
  domain that owns the matching topics. Must be a streaming domain bound to the
  route.
* [8] Optional. The path to a YAML file that contains the
  list of conditions, as an alternative to inline `conditions` ([4]). The
  path is resolved against the working directory of Confluent Gateway inside the
  container, so mount the file into the container, for example with a
  `volumes` entry in `docker-compose.yaml`. The file must be readable and
  contain at least one condition. Confluent Gateway reads the
  file when it loads the configuration and watches only the main configuration
  file, so a change to the conditions file takes effect only after the
  configuration reloads.
* [9] Optional. The name of the streaming domain that owns
  every topic that no condition matches. Must be a streaming domain bound to
  the route. If you omit `default`, the route is strict. Confluent Gateway doesn’t
  show clients a topic that no condition matches, and it rejects requests to
  create, delete, read, or write that topic.

Every streaming domain that you reference in `coordination`, `conditions`,
and `default` must be one of the streaming domains in the route’s
`streamingDomains` list.

The following example shows the `rules.routing` settings of a route:

```yaml
gateway:
  routes:
    - name: migration-route
      rules:
        routing:
          coordination:
            group: cc
          conditions:
            - topics: ["payments"]
              streamingDomain: cp
            - topicPatterns: ["teamA\\..*"]
              streamingDomain: cc
          default: cp
```

For an example of a complete route, see
the [configure step](gateway-topic-based-routing.md#gateway-topic-based-routing-configure-step) and the
[reroute step](gateway-topic-based-routing.md#gateway-topic-based-routing-reroute-step) of the
migration procedure.

To keep the conditions in a separate file, set `conditionsFile` to the path of
a YAML file instead of listing `conditions`. The file contains the list of
conditions, with the same fields as the inline `conditions` list:

```yaml
- topics: ["payments"]
  streamingDomain: cp
- topicPatterns: ["teamA\\..*"]
  streamingDomain: cc
```

### Route filters configuration

Filters allow you to control and manage traffic flow for specific routes in
Confluent Gateway. You can apply filters at the route level to enforce policies, block
or allow requests, and customize error handling for different scenarios.

<a id="gateway-config-fencing-docker"></a>

#### Fencing filter

The fencing filter in Confluent Gateway is a route-level filter that allows you to
control the traffic flow on a specific route. You can configure fencing in two
ways:

* `fence` (deprecated): Blocks or allows all requests on a route. Use
  `rules.fencing` instead. For more information, see
  [Fence an entire route](#gateway-config-fence-docker).
* `rules.fencing`: Blocks or allows traffic by traffic type
  and topic. You can use `rules.fencing` on static and dynamic routes. For
  more information, see [Fencing rules configuration](#gateway-config-fence-rules-docker).

A route can use `fence` or `rules.fencing`, but not both.

<a id="gateway-config-fence-docker"></a>

##### Fence an entire route

The `fence` configuration supports two fencing scopes:

* `ALL`: Blocks all requests on the specified route. Useful for scenarios
  such as maintenance windows or when you want to temporarily disable
  access to a route.
* `NONE`: Allows all requests on the specified route.

```yaml
gateway:
  routes:
    - name:
      fence:
        scope:          --- [1]
        errorCode:      --- [2]
        errorMessage:   --- [3]
```

* [1] Optional. The fencing scope of the filter. The default value is `ALL`,
  which blocks all requests on the route. Set to `NONE` to allow all requests
  on the route. If you add a `fence` section without `scope`, Confluent Gateway
  blocks all requests on the route.
* [2] Optional. The error code to return for blocked requests. The default
  value is `BROKER_NOT_AVAILABLE`.

  For a list of valid error codes, see [Kafka protocol error codes](https://kafka.apache.org/42/design/protocol/#error-codes).
* [3] Optional. The error message to return for blocked requests. The default
  value is `This route is currently unavailable - all requests are blocked.`

The following is an example configuration for a Confluent Gateway route with the
fencing filter enabled:

```yaml
gateway:
  routes:
    - name: eu-sales
      endpoint: eu-gw.sales.example.com:9092
      fence:
        scope: ALL
        errorCode: BROKER_NOT_AVAILABLE
        errorMessage: "Maintenance in progress - route temporarily unavailable"
      brokerIdentificationStrategy:
        type: host
        pattern: broker-$(nodeId).eu-gw.sales.example.com:9092
      streamingDomain:
        name: sales
        bootstrapServerId: SASL_SSL-1
```

This example shows only the settings that the fencing filter requires. A route
that uses `type: host` also requires an SSL keystore in its `security`
settings. For more information, see [Configure Security for Confluent Gateway](gateway-security.md#gateway-security-docker).

<a id="gateway-config-fence-rules-docker"></a>

##### Fencing rules configuration

Use the `rules.fencing` setting to block traffic by traffic type and topic,
instead of blocking the entire route. For example, you can block produce
requests to a set of topics while those topics migrate to another cluster, and
let all other traffic continue. To learn how to use fencing to migrate a topic,
see [Migrate topics between clusters](gateway-topic-based-routing.md#gateway-topic-based-routing-migrate).

```yaml
gateway:
  routes:
    - name:
      rules:
        fencing:                        --- [1]
          - trafficType:                --- [2]
            topics:                     --- [3]
            topicPatterns:              --- [4]
            blocked:                    --- [5]
```

* [1] The list of [fencing rules](gateway-topic-based-routing.md#gateway-topic-based-routing-concepts).
  Confluent Gateway evaluates the rules in order, and the first rule that matches a
  request decides whether to block it. Confluent Gateway doesn’t fence requests that
  match no rule. Each rule must set at least one of `trafficType` ([2]),
  `topics` ([3]), or `topicPatterns` ([4]). A route can’t use both
  `rules.fencing` and `fence`.
* [2] Optional. The traffic type that the rule applies to. Set to `PRODUCE` or
  `CONSUME`. If you omit `trafficType`, the rule applies to both types.
  * `PRODUCE`: Requests that write records.
  * `CONSUME`: Requests that read records or manage consumer groups and
    offsets. For the requests that each type covers, see the
    [responses table](#gateway-config-fence-rules-handling-docker).

  A rule that lists `topics` or `topicPatterns` doesn’t fence consumer group
  membership requests (join, sync, heartbeat, and leave), because they don’t
  name topics. To fence them, use a `CONSUME` rule that sets neither
  `topics` nor `topicPatterns`. Such a rule blocks all consume traffic on
  the route, for every topic and consumer group, not only for the topics that
  you migrate.
* [3] Optional. A list of exact topic names that the rule applies to.
* [4] Optional. A list of Java regular expressions that the rule applies to,
  with the same syntax as `topicPatterns` in routing rules. For more
  information about pattern syntax, see
  [Routing rules configuration (Early Access)](#gateway-config-dynamic-routing-rules-docker).

  A rule matches a topic if the topic is listed in `topics` ([3]) or matches
  any pattern in `topicPatterns` ([4]).
* [5] Required. Set to `true` to block the traffic that matches the rule, or
  `false` to allow it. To make an exception to a broader `true` rule, list a
  `false` rule for those topics before it, because the first matching rule
  wins.

A rule that sets only `trafficType` applies to all traffic of that type.

The following example blocks produce requests to the `orders` topic and to all
topics that start with `teamA.`, except for `teamA.audit`. The `false` rule
comes first because Confluent Gateway evaluates the rules in order:

```yaml
gateway:
  routes:
    - name: migration-route
      rules:
        fencing:
          - trafficType: PRODUCE
            topics: ["teamA.audit"]
            blocked: false
          - trafficType: PRODUCE
            topics: ["orders"]
            topicPatterns: ["teamA\\..*"]
            blocked: true
```

<a id="gateway-config-fence-rules-handling-docker"></a>

When a rule blocks a request, the response depends on the request type. Fencing
returns errors that clients can retry, so most clients retry instead of
failing. Clients can retry these errors, which aligns with Kafka behavior, so
client applications don’t need extra error handling. Unlike
`fence`, which has an `errorCode` setting, fencing rules don’t let you
configure the error codes. The following table lists the response that each type
of request receives when a fencing rule blocks it:

| Traffic type   | Request                                     | Response for blocked requests                                 |
|----------------|---------------------------------------------|---------------------------------------------------------------|
| `PRODUCE`      | Produce                                     | `NOT_ENOUGH_REPLICAS`                                         |
| `CONSUME`      | Fetch                                       | An empty response with no error, so the consumer polls again. |
| `CONSUME`      | ListOffsets                                 | `OFFSET_NOT_AVAILABLE`                                        |
| `CONSUME`      | OffsetCommit                                | `COORDINATOR_LOAD_IN_PROGRESS`                                |
| `CONSUME`      | OffsetForLeaderEpoch                        | `NOT_LEADER_OR_FOLLOWER`                                      |
| `CONSUME`      | JoinGroup, SyncGroup, Heartbeat, LeaveGroup | `COORDINATOR_LOAD_IN_PROGRESS`                                |

Client timeouts limit how long a fence can last. A producer stops retrying when
its `delivery.timeout.ms` expires (120,000 ms by default). If a consumer
can’t send heartbeats before its `session.timeout.ms` expires, the group
coordinator might remove it from its consumer group. Keep fences as short as
possible.

If a request names more than one topic and only some of them are fenced,
Confluent Gateway returns the fencing error, or an empty result for fetch requests, for
the fenced topics and processes the rest.

For the requests that Confluent Gateway doesn’t fence, such as OffsetFetch, and the
effect of fencing on producers that use `acks=0`, see
[Limitations](gateway-topic-based-routing.md#gateway-topic-based-routing-limitations).

<a id="gateway-config-admin-metrics-docker"></a>

### Administration and metrics configuration

The `admin` section configures the Confluent Gateway administrative service,
including the bind address, TCP port, metrics endpoint, JVM metrics
collection, and custom metric tags.

```yaml
gateway:
  admin:
    bindAddress:             --- [1]
    port:                    --- [2]
    endpoints:
      metrics:               --- [3]
    jvmMetrics:              --- [4]
      - JvmGcMetrics
      - JvmMemoryMetrics
      - JvmThreadMetrics
      - ProcessorMetrics
      - UptimeMetrics
    commonTags:              --- [5]
      host:
      region:
```

* [1] The local address to bind admin service and to listen on for incoming
  connections. The default value is `0.0.0.0`.

  This address determines which network interfaces the Confluent Gateway uses to
  expose its administrative endpoints, such as metrics and liveness checks.
* [2] The TCP port for exposing admin endpoints. The default value is `9190`.

  The Confluent Gateway serves metrics at `http://{bindAddress}:{port}/metrics`.
  It exposes a liveness check at `http://{bindAddress}:{port}/livez`.
* [3] The metrics endpoints to be enabled and exposed. The default value is
  `true`.
* [4] Standard JVM metrics captured using Micrometer classes. By default,
  `JvmGcMetrics`, `JvmMemoryMetrics`, `JvmThreadMetrics`,
  `ProcessorMetrics`, and `UptimeMetrics` are enabled. If you set this
  list, it replaces the defaults, so include every metric class you want.
* [5] Optional. The common tags to be applied to all the metrics.

An example configuration for Confluent Gateway administration and metrics:

```yaml
admin:
  bindAddress: 0.0.0.0
  port: 9190
  endpoints:
    metrics: true
  jvmMetrics:
    - JvmGcMetrics
    - JvmMemoryMetrics
    - JvmThreadMetrics
    - ProcessorMetrics
    - UptimeMetrics
  commonTags:
    host: pod-0
    region: us-west-2
```

For a recommended set of metrics to monitor and example alerting queries,
see [Monitor Confluent Gateway Metrics](gateway-metrics-monitoring.md#gateway-metrics-monitoring).

<a id="gateway-config-license-docker"></a>

### Optional: Enterprise license configuration

Enterprise mode enables unlimited routes and requires a valid Confluent Platform
Confluent Enterprise license that includes the Confluent Gateway add-on. The default Trial mode, which doesn’t require
a key, is limited to a maximum of four routes. For a full comparison of
modes, see [License modes](gateway-deploy-overview.md#gateway-license-modes).

If you’re using Enterprise mode, follow these steps to apply your license
key:

1. Contact Confluent to get a Confluent Enterprise license for Confluent Platform that includes the
   Confluent Gateway add-on for production use. For more information, see
   [Manage Confluent Platform Licenses](../installation/license.md#cp-license-overview).
2. Using the license key, configure the `GATEWAY_LICENSES` environment variable
   by exporting it or defining in the `docker-compose.yaml`.
   * Set the environment variable before starting the Confluent Gateway.
     ```bash
     export GATEWAY_LICENSES="your-license-key"
     ```

     To add multiple license keys, use Bash ANSI-C quoting (`$'...'`) so
     that the shell expands `\n` into a newline between keys.
     ```bash
     export GATEWAY_LICENSES=$'your-first-license-key\nyour-second-license-key'
     ```
   * Edit `docker-compose.yaml`. You can add multiple license
     keys, one per line.
     ```yaml
     gateway:
       environment:
         GATEWAY_LICENSES: |
           your-first-license-key
           your-second-license-key
     ```
3. To verify the license status, check the Confluent Gateway logs for license
   information after starting the Confluent Gateway.
   ```bash
   docker compose -f docker-compose.yaml logs gateway | grep -i license
   ```

After completing your configuration, save the file as `docker-compose.yaml`.

<a id="gateway-install-with-docker"></a>

## Deploy Confluent Gateway using Docker

To deploy Confluent Gateway:

1. Pull the Confluent Gateway Docker image to ensure you have the correct version
   and avoid using a stale locally cached image. For available version
   tags, see [confluent-gateway on Docker Hub](https://hub.docker.com/r/confluentinc/confluent-gateway/tags).
   ```bash
   docker pull confluentinc/confluent-gateway:<version_tag>
   ```
2. Start Confluent Gateway using the `docker-compose.yaml` configuration file
   you set up in [Configure Confluent Gateway using Docker Compose](#gateway-config-using-docker).
   ```bash
   docker compose -f docker-compose.yaml up -d
   ```
3. Verify that Confluent Gateway is running.
   ```bash
   docker ps
   ```

   Confluent Gateway starts in the background after the `docker compose` command
   completes. Confirm the Confluent Gateway container appears in the output.

<a id="gateway-deploy-next-steps"></a>

## Next steps

After you deploy Confluent Gateway:

* Verify the deployment and resolve any startup or connectivity problems. For
  diagnostic steps and symptom-based resolutions, see
  [Troubleshoot Confluent Gateway Docker Deployments](docker-troubleshoot.md#gateway-troubleshoot-docker).
* [Configure security](gateway-security.md#gateway-security-docker) for the Confluent Gateway.
  Security configuration covers authentication, SSL/TLS, secret stores, and
  passwords for client-to-Confluent Gateway and Confluent Gateway-to-Kafka cluster
  connections.
* Reconfigure clients to communicate with the Confluent Gateway endpoint by
  pointing their `bootstrap.servers` to the route endpoint defined in the
  Confluent Gateway configuration. For migration scenarios between Kafka clusters,
  see [Migrate between Kafka Clusters using Confluent Gateway](gateway-migrate.md#gateway-client-switchover).
