Installing EDB Postgres AI for ClickHouse on Rocky Linux v26.3

EDB distributes ClickHouse as RPM packages for Rocky Linux 10 on x86-64. The following packages are available:

PackageDescriptionInstall on
edb-clickhouse-serverClickHouse server engine, systemd services, and default configuration files. Includes clickhouse-keeper.service, so server nodes can run Keeper alongside the server without an additional package.Server nodes
edb-clickhouse-clientclickhouse-client, clickhouse-local, clickhouse-benchmark, and related tools.Server nodes, remote client hosts
edb-clickhouse-common-staticCompiled ClickHouse binary, required by the server and client packages.All server and client nodes
edb-clickhouse-keeperStandalone Keeper binary for dedicated coordination nodes. Only needed for multi-node deployments that run Keeper on separate nodes.Dedicated Keeper nodes only

For an explanation of node roles and deployment topologies, see Architecture.

Prerequisites

  • Rocky Linux 10
  • sudo or root access
  • An EDB subscription token, available from the EDB customer portal

Deploying a single node

ClickHouse runs as a standalone instance with no cluster coordination required. Suitable for development, testing, and single-tenant analytical workloads.

  1. Install the packages:

    export EDB_SUBSCRIPTION_TOKEN=<your-token>
    export EDB_SUBSCRIPTION_PLAN=clickhouse
    curl -1sSLf "https://downloads.enterprisedb.com/$EDB_SUBSCRIPTION_TOKEN/$EDB_SUBSCRIPTION_PLAN/setup.rpm.sh" | sudo -E bash
    sudo dnf install -y \
      edb-clickhouse-common-static \
      edb-clickhouse-server \
      edb-clickhouse-client
  2. Start the server:

    sudo systemctl enable clickhouse-server
    sudo systemctl start clickhouse-server

    Verify the server is running:

    sudo systemctl status clickhouse-server
  3. Connect using the ClickHouse command-line client:

    clickhouse-client

    By default, the default user has no password. To set one, run the following after connecting:

    ALTER USER default IDENTIFIED BY 'yourpassword';

    Then connect with:

    clickhouse-client --password
  4. Verify the EDB build by checking the version string:

    SELECT value FROM system.build_options WHERE name = 'VERSION_OFFICIAL';

    The output includes (EDB Build) for EDB-packaged releases.

Deploying a cluster

A cluster deployment distributes data across multiple server nodes using sharding, replication, or both. Replication requires ClickHouse Keeper running on at least three nodes. For an explanation of sharding, replication, and Keeper roles, see Architecture.

The following steps walk through a five-node deployment: four server nodes across two shards with two replicas each, with Keeper co-located on node-1 and node-2 and running as a dedicated service on node-5. Adjust the configuration for your own topology.

NodeRoleShardReplica
node-1ClickHouse server + Keeper11
node-2ClickHouse server + Keeper12
node-3ClickHouse server21
node-4ClickHouse server22
node-5Keeper

Installing packages

  1. Set up the EDB repository on every node:

    export EDB_SUBSCRIPTION_TOKEN=<your-token>
    export EDB_SUBSCRIPTION_PLAN=clickhouse
    curl -1sSLf "https://downloads.enterprisedb.com/$EDB_SUBSCRIPTION_TOKEN/$EDB_SUBSCRIPTION_PLAN/setup.rpm.sh" | sudo -E bash
  2. Install the role-appropriate packages on each node.

    On each server node:

    sudo dnf install -y \
      edb-clickhouse-common-static \
      edb-clickhouse-server \
      edb-clickhouse-client

    For co-located deployments, edb-clickhouse-server already includes clickhouse-keeper.service, so no additional package is needed.

    On each dedicated Keeper node:

    sudo dnf install -y edb-clickhouse-keeper

Configuring Keeper

Configure all Keeper nodes before starting any service. Use a minimum of three Keeper nodes to tolerate one node failure.

  1. The RPM installs a default /etc/clickhouse-keeper/keeper_config.xml. Replace its contents on each Keeper node with the following, setting <server_id> to a unique integer (1, 2, 3) per node:

    <clickhouse>
        <listen_host>0.0.0.0</listen_host>
        <keeper_server>
            <tcp_port>9181</tcp_port>
            <server_id>1</server_id><!-- Set to 1, 2, or 3 depending on the node -->
            <log_storage_path>/var/lib/clickhouse/coordination/log</log_storage_path>
            <snapshot_storage_path>/var/lib/clickhouse/coordination/snapshots</snapshot_storage_path>
            <coordination_settings>
                <operation_timeout_ms>10000</operation_timeout_ms>
                <session_timeout_ms>30000</session_timeout_ms>
                <raft_logs_level>information</raft_logs_level>
            </coordination_settings>
            <raft_configuration>
                <server><id>1</id><hostname><node-1-ip></hostname><port>9234</port></server>
                <server><id>2</id><hostname><node-2-ip></hostname><port>9234</port></server>
                <server><id>3</id><hostname><node-5-ip></hostname><port>9234</port></server>
            </raft_configuration>
        </keeper_server>
    </clickhouse>

Configuring the servers

Each server node needs a cluster configuration that defines the remote servers, Keeper endpoints, and the node's own shard and replica identity.

  1. Create /etc/clickhouse-server/config.d/cluster.xml on each server node, adjusting the <shard> and <replica> values in the <macros> section for each node:

    Node<shard><replica>
    node-10101
    node-20102
    node-30201
    node-40202
    <clickhouse>
        <listen_host>0.0.0.0</listen_host>
        <remote_servers>
            <my_cluster>
                <shard>
                    <internal_replication>true</internal_replication>
                    <replica><host><node-1-ip></host><port>9000</port></replica>
                    <replica><host><node-2-ip></host><port>9000</port></replica>
                </shard>
                <shard>
                    <internal_replication>true</internal_replication>
                    <replica><host><node-3-ip></host><port>9000</port></replica>
                    <replica><host><node-4-ip></host><port>9000</port></replica>
                </shard>
            </my_cluster>
        </remote_servers>
        <zookeeper>
            <node><host><node-1-ip></host><port>9181</port></node>
            <node><host><node-2-ip></host><port>9181</port></node>
            <node><host><node-5-ip></host><port>9181</port></node>
        </zookeeper>
        <macros>
            <cluster>my_cluster</cluster>
            <shard>01</shard><!-- Adjust per node, see table above -->
            <replica>01</replica><!-- Adjust per node, see table above -->
        </macros>
        <distributed_ddl>
            <path>/clickhouse/task_queue/ddl</path>
        </distributed_ddl>
    </clickhouse>

Starting services

  1. Start Keeper on all Keeper nodes. On each Keeper node:

    sudo systemctl enable clickhouse-keeper
    sudo systemctl start clickhouse-keeper
  2. Verify each Keeper node is healthy. Run the following on each Keeper node. A healthy node responds with imok:

    clickhouse-keeper-client -h 127.0.0.1 -p 9181 -q "ruok"
    Output
    imok
  3. Confirm quorum is formed from any one Keeper node. A value of 2 means two followers are synced to the leader, confirming all three Keeper nodes have formed a quorum:

    clickhouse-keeper-client -h 127.0.0.1 -p 9181 -q "mntr" | grep zk_synced_followers
    Output
    zk_synced_followers	2
  4. Start the server on all server nodes:

    sudo systemctl enable clickhouse-server
    sudo systemctl start clickhouse-server
  5. Verify the server is running on each server node:

    sudo systemctl status clickhouse-server

Connecting to the cluster

  1. Connect to any server node from a host with edb-clickhouse-client installed:

    clickhouse-client -h <server-node-ip>

    By default, the default user has no password. To set one, run the following after connecting:

    ALTER USER default IDENTIFIED BY 'yourpassword';

    Then connect with:

    clickhouse-client -h <server-node-ip> --password
  2. Confirm all server nodes are registered. system.clusters lists server nodes only, so the dedicated Keeper node-5 doesn't appear:

    SELECT cluster, shard_num, replica_num, host_name
    FROM system.clusters
    WHERE cluster = 'my_cluster';
    Output
    ┌─cluster────┬─shard_num─┬─replica_num─┬─host_name───┐
    │ my_cluster │         11<node-1-ip> │
    │ my_cluster │         12<node-2-ip> │
    │ my_cluster │         21<node-3-ip> │
    │ my_cluster │         22<node-4-ip> │
    └────────────┴───────────┴─────────────┴─────────────┘

Testing replication and sharding

Create a local ReplicatedMergeTree table and a Distributed table on top of it. Insert some rows and query both tables to confirm that replication is working within each shard and that the distributed table aggregates data across all shards.

  1. Create a local storage table. The ReplicatedMergeTree engine stores data physically on each node and replicates it within the shard:

    CREATE TABLE events ON CLUSTER my_cluster (
        event_id   UInt32,
        user_id    UInt32,
        event_type String,
        created_at DateTime
    ) ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/events', '{replica}')
    ORDER BY event_id;
  2. Create a Distributed table on top of events. Unlike the local table, it stores no data. It routes queries to events across all shards and aggregates the results:

    CREATE TABLE events_dist ON CLUSTER my_cluster (
        event_id   UInt32,
        user_id    UInt32,
        event_type String,
        created_at DateTime
    ) ENGINE = Distributed(my_cluster, default, events, rand());
  3. Insert some rows via events_dist. The rand() sharding key distributes each row across shards:

    INSERT INTO events_dist VALUES
        (1, 101, 'login',    now()),
        (2, 102, 'purchase', now()),
        (3, 103, 'logout',   now()),
        (4, 104, 'login',    now());
  4. Query the local table on any server node. Each node returns only the rows on its shard. The specific rows vary depending on how rand() distributed them:

    SELECT * FROM events;
    Output
    ┌─event_id─┬─user_id─┬─event_type─┬─────────────created_at─┐
    │        2102 │ purchase   │ 2026-06-10 14:48:15    │
    │        3103 │ logout     │ 2026-06-10 14:48:15    │
    └──────────┴─────────┴────────────┴────────────────────────┘
  5. Query events_dist from any node to confirm all rows are returned across shards:

    SELECT * FROM events_dist ORDER BY event_id;
    Output
    ┌─event_id─┬─user_id─┬─event_type─┬─────────────created_at─┐
    │        1101 │ login      │ 2026-06-10 14:48:15    │
    │        2102 │ purchase   │ 2026-06-10 14:48:15    │
    │        3103 │ logout     │ 2026-06-10 14:48:15    │
    │        4104 │ login      │ 2026-06-10 14:48:15    │
    └──────────┴─────────┴────────────┴────────────────────────┘