Skip to main content
This guide runs open-source ClickHouse on Linux servers with its whole data directory on an Archil disk. ClickHouse keeps using ordinary MergeTree tables on what looks like a local file system, and Archil keeps the files durable in object storage. That gives a self-hosted ClickHouse three properties it doesn’t have on local disks:
  • One copy of the data, in object storage. Archil makes a write durable across Availability Zones as soon as fsync returns, so you don’t need ClickHouse replicas to keep the data safe.
  • Replaceable servers. No table data or metadata lives on the server. When a server dies, another one mounts the disk and starts ClickHouse with every table intact.
  • Isolated copies for heavy queries. A branch gives you a writable copy of the whole database in about 50 ms (a 15 ms checkpoint plus a 35 ms branch), whatever its size. Run a long modeling query or a backfill on a second server against the branch, and it never competes with ingest on the primary.
ClickHouse can also store parts in S3 with an s3 disk, but the server then keeps the metadata for those parts on its local disk, and sharing one copy of the data between replicas relies on zero-copy replication, which ClickHouse doesn’t recommend for production. With the data directory on Archil, nothing in ClickHouse needs to know about object storage. You’ll set up a primary server, load 100 million rows, move the database to a second server, and then run a heavy query on a branch while the primary keeps taking inserts.

Prerequisites

  • Two Linux servers running Ubuntu 22.04 or later, x86-64 or arm64, in the same cloud region as your disk. This guide calls them ch-primary and ch-analytics. Any instance with 4 vCPUs and 16 GiB of memory is enough for the examples; we used EC2 m7i.xlarge instances in us-east-1. Both need outbound access to Archil.
  • An Archil disk for the database, created in the Archil console. Branches need Archil-managed storage or a flat-block bring-your-own-bucket disk; see Branches & Checkpoints.
  • A disk token for that disk, which both servers use to mount it. In the console, open the disk, select Connections, click Add User, and choose Disk Token.
  • An API key in the disk’s region, for creating branches.
On both servers, export the disk’s name, its ID, its region, and the disk token:

Install ClickHouse and the Archil client

Run this on both servers. It installs the Archil client and ClickHouse from ClickHouse’s official package repository, then stops ClickHouse, which still points at its default data directory on the local disk:
install.sh

Point ClickHouse at the Archil disk

Still on both servers, add a configuration file that moves everything ClickHouse needs to restart onto the disk. The path setting covers table data, table and database definitions, and ClickHouse’s own state. Users and grants created with SQL are stored separately, so user_directories moves them too. tmp_path, which ClickHouse uses for large sorts and joins that spill out of memory, stays on the local disk: it’s scratch space, and it’s faster there.
/etc/clickhouse-server/config.d/archil.xml
By default, ClickHouse doesn’t fsync the parts it writes, so an INSERT can return before its data is durable. On an Archil disk, writes that haven’t been flushed are held by the client on that server, and they’re lost if the server dies. The two merge_tree settings make every INSERT wait until its part is durable, so a server failure never loses an acknowledged insert. They also make sure a checkpoint contains every insert that finished before it. Each insert now waits for a round trip to Archil, so send data in large batches, as ClickHouse recommends anyway, or turn on asynchronous inserts. Finally, stop ClickHouse from ever starting while the disk isn’t mounted. Without a guard, it would create an empty database in /mnt/archil on the local disk:

Start the primary

On ch-primary, mount the disk, hand a directory on it to the clickhouse user, and start the server:
archil mount takes the disk in exclusive mode, so ch-primary is the only server that can write to it. That’s what ClickHouse expects: one server owns a data directory. Create a table and load 100 million rows of synthetic events:
schema.sql
In our runs, the load took about 12 seconds, with every part fsynced. The query took 2.5 seconds right after the load, while ClickHouse was still merging the new parts in the background, and about 0.5 seconds on repeat runs. The table takes about 740 MiB after compression. Every file ClickHouse wrote for it is under /mnt/archil/clickhouse.
By default, ClickHouse listens only on localhost, and its default user has no password, so this guide runs clickhouse-client on the servers themselves. Before you open ClickHouse to the network, set up users and passwords as described in ClickHouse’s access control guide, then set listen_host.

Move the database to another server

Because the whole database is on the disk, moving it is a remount. On ch-primary, stop ClickHouse and unmount the disk. archil unmount flushes every outstanding write before it returns:
Then, on ch-analytics, mount the disk and start ClickHouse:
ch-analytics didn’t copy anything. It read the table’s files from Archil as ClickHouse opened them, and anything already in Archil’s server-side cache was served from there. In our runs, unmounting took about 0.15 seconds, mounting on ch-analytics 0.1 seconds, and starting ClickHouse about 1 second. The category query from the previous section took 0.9 seconds the first time on ch-analytics, against 0.5 seconds on a server that had already read the table.

When a server dies

If a server crashes instead of shutting down, it still holds the disk, and a normal archil mount on a replacement fails with another client has an outstanding delegation to the root of the disk. Once you know the old server is down, take the disk over with --force:
--force revokes the old server’s ownership of the disk, and any writes it hadn’t flushed are lost. With fsync_after_insert on, those are only inserts that hadn’t returned yet, and background merges that ClickHouse redoes on its own. At startup, ClickHouse logs Removing temporary directory for each part that was still being written, and deletes it, as it would after a crash on a local disk. ClickHouse commits a large INSERT one block at a time, so an insert that was still running can be partly applied. We tested this by force-stopping ch-analytics in the middle of an INSERT ... SELECT. --force mounted the disk on ch-primary in 0.1 seconds, ClickHouse started in about 1 second, every row from inserts that had returned was there, and no parts were detached as broken. Move the database back to ch-primary the same way before you continue: stop ClickHouse and unmount on ch-analytics, then mount and start on ch-primary.

Run heavy queries on a branch

A long query on the primary competes with inserts and with every other query for CPU, memory, and I/O. Instead, take a checkpoint of the running database, branch the disk from it, and run the query on ch-analytics against the branch. The primary keeps running the whole time. On ch-primary, take a checkpoint with a unique name:
A checkpoint captures the disk exactly as it is at that moment, like a crash at that instant without losing any writes. MergeTree commits a part by renaming its finished directory into place, so the checkpoint contains only whole parts, and every insert that returned before it. Create a branch from the checkpoint. This needs your API key and the disk ID, and it can run anywhere the archil client is installed:
On ch-analytics, mount the branch and start ClickHouse on it. Pass the same CHECKPOINT value you used on ch-primary:
In our runs, the checkpoint took 40 ms and the branch 80 ms, both measured from the command line. ClickHouse logs Status file ... already exists - unclean restart when it starts on the branch, because the checkpoint was taken while the primary was running; that’s expected. ch-analytics now has its own writable copy of the database as of the checkpoint. Run the heavy query there:
Meanwhile, the primary keeps taking inserts. On ch-primary, add 10 million rows:
The branch on ch-analytics still has 100 million rows. Nothing either server does reaches the other: the branch can create tables, run backfills, or drop data without touching the primary. When you’re done with the branch, stop ClickHouse and unmount it:
The server on a branch runs background merges like any other ClickHouse server. If you only read from it, run SYSTEM STOP MERGES after it starts, so all of its CPU goes to your queries.
You can’t delete branches and checkpoints yet. Use a new name for each branch, as the timestamped CHECKPOINT above does. See Branches & Checkpoints.
Checkpoints also work as instant backups. If someone drops a table on the primary, branch the disk from a checkpoint taken before the drop, start ClickHouse on the branch, and copy the table back with the remote table function.

Running it in production

  • One server per disk or branch. Two ClickHouse servers must never share one data directory, and exclusive mounts enforce that. To scale writes, shard: give each shard its own disk and query across them with a Distributed table.
  • No replication needed for durability. Use plain MergeTree tables. ClickHouse Keeper and ReplicatedMergeTree are only worth running if you need a standby that’s already started when the primary fails.
  • Failover time grows with the number of parts. At startup, ClickHouse reads a few small files from every active part. Keep the part count in check with a sensible partition key and batched inserts, and measure a remount on your own data.
  • Size the client cache for your working set. The Archil client caches file data in memory, and by default it uses at most 2 GiB. On a dedicated ClickHouse server, raise it with --max-cache-mb when you mount. See Client caching.
  • Mount at boot. The guide’s ExecStartPre check keeps ClickHouse from starting until the disk is mounted, and the service retries every 30 seconds. Mount the disk from your provisioning or a boot script, and ClickHouse starts once the mount appears.

Run it in Archil sandboxes

Everything above also works in persistent sandboxes, and that’s the most cost-effective way to run it: reads between a sandbox and its disks are transfer within Archil, which is free. The official clickhouse/clickhouse-server image already includes the archil client in a sandbox. Sandboxes don’t run systemd, so ClickHouse runs as a sandbox service instead, which restarts if it crashes. This script sets up the primary. It’s the configuration from earlier in this guide, with ClickHouse registered as a service:
primary-setup.sh
Create the primary with the disk mounted at /mnt/archil, upload archil.xml, schema.sql, and the script, and run it:
Take checkpoints in the primary with archil checkpoints create /mnt/archil "$CHECKPOINT", exactly as on a server, and create branches with archil branches create as before. A sandbox’s mounts attach the disk itself, not a branch, so the analytics sandbox is created without any and mounts the branch itself with archil mount --branch. Pass the disk’s ID, region, and token, and the checkpoint name, as environment variables:
analytics-setup.sh
In our runs in aws-us-west-2, the 100-million-row load took about 7 seconds in a 4 vCPU, 16 GiB sandbox. In the analytics sandbox, archil mount --branch took under half a second, ClickHouse was ready about 2 seconds later, and the heavy query from the previous section returned the same result in about 2 seconds. Delete the analytics sandbox when you’re done with the branch: it mounts the branch from its setup script, so it isn’t meant to be stopped and started again.

Cost compared with ClickHouse Cloud

Running this setup in Archil sandboxes costs 17% to 61% less than ClickHouse Cloud’s published example services. This section compares list prices in AWS us-east-1 as of November 2026: Archil’s Developer and Team rates from Pricing & Billing, and ClickHouse Cloud’s from its pricing page. One server instead of two. ClickHouse Cloud’s Scale and Enterprise services keep at least two replicas once they’re larger than 12 GiB. On Archil, the disk already keeps every write durable across Availability Zones, so one ClickHouse server per shard is enough. Per unit of compute, a sandbox also costs less: Storage without a second copy. Archil stores the data for $0.025 per GB-month, or $25 per TB. ClickHouse Cloud charges $25.30 per TB, and bills its default daily backup as a second copy at the same rate; on Archil, checkpoints take its place. Archil also bills $0.20 per GiB-month for active data, which is data read or written in the last hour, so the total depends on how much of the table your queries touch each hour. Here is the monthly cost of ClickHouse Cloud’s published examples, running 24 hours a day, next to one sandbox the size of one of their replicas, with 10% and 100% of the data active: The Archil columns are one sandbox (2 vCPU and 8 GiB, 4 vCPU and 16 GiB, or 16 vCPU and 64 GiB) running all month, plus storage. A branch sandbox for heavy queries, like a ClickHouse Cloud warehouse, only costs compute while it runs. To see where your workload falls between the two Archil columns, run it for a day and check the disk’s active data on its Usage tab in the Archil console.

Clean up

On each server that’s running ClickHouse, stop it and unmount the disk:
Then delete the disk in the Archil console, and terminate both servers. If you ran ClickHouse in sandboxes, stop and delete them instead.

Next steps

Branches & Checkpoints

How checkpoints and branches work, and their CLI commands.

Mount on Linux

Requirements, authorization, and mount options for Linux servers.

Client caching

Size, warm, and refresh the client’s in-memory cache.

Analytics with DuckDB

Query Parquet in S3 in place, without loading it into a database.