Skip to content

Instantly share code, notes, and snippets.

@gvolpe
Created December 20, 2025 10:50
Show Gist options
  • Select an option

  • Save gvolpe/a9f51ae544262182bcc5ac5b6ec03d67 to your computer and use it in GitHub Desktop.

Select an option

Save gvolpe/a9f51ae544262182bcc5ac5b6ec03d67 to your computer and use it in GitHub Desktop.
Plausible uses ClickHouse, Postgres and Redis as the storage backend
{ ... }:
let
host = "analytics.gvolpe.com";
internalPort = 8000;
# free space allowed before it starts failing with "not enough space" errors
freeSpaceBytes = "10737418240"; # 10 GBs
in
{
# docs: https://clickhouse.com/docs/en/operations/settings/settings
services = {
clickhouse = {
enable = true;
usersConfig = {
profile.default = {
max_threads = 1;
max_block_size = 8192;
max_download_threads = 1;
input_format_parallel_parsing = 0;
output_format_parallel_formatting = 0;
};
};
# optimize disk usage: https://github.com/plausible/community-edition/issues/256
serverConfig = {
storage_configuration = {
data = {
path = "/var/lib/clickhouse/data/";
keep_free_space_bytes = freeSpaceBytes;
};
disks = {
default.keep_free_space_bytes = freeSpaceBytes;
backups = {
type = "local";
path = "/var/lib/clickhouse/backups/";
};
};
};
backups = {
allowed_disk = "backups";
allowed_path = "/var/lib/clickhouse/data/clickhouse/backups/";
};
mark_cache_size = 524288000; # 524 MBs
logger = {
level = "warning";
console = true;
};
# disable unnecessary logging
metric_log = { };
asynchronous_metric_log = { };
query_thread_log = { };
text_log = { };
trace_log = { };
session_log = { };
part_log = { };
# keep the query_log table compact
query_log = {
database = "system";
table = "query_log";
flush_interval_milliseconds = 7500;
engine = ''
ENGINE = MergeTree
PARTITION BY event_date
ORDER BY (event_time)
TTL event_date + interval 30 day
SETTINGS ttl_only_drop_parts=1
'';
};
merge_tree = {
allow_experimental_replacing_merge_with_cleanup = 1;
};
};
};
plausible = {
enable = true;
mail.email = "noreply@gvolpe.addy.io";
server = {
baseUrl = "https://${host}";
port = internalPort;
secretKeybaseFile = "/run/agenix/keybase";
};
};
nginx = {
enable = true;
virtualHosts."${host}" = {
forceSSL = true;
enableACME = true;
locations = {
"/" = {
proxyPass = "http://localhost:${toString internalPort}";
proxyWebsockets = true;
};
};
};
};
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment