Hello NixOS community,
I’m setting up Zabbix 7.0 with PostgreSQL and TimescaleDB using the following configuration:
{ config, pkgs, lib, ... }:
let
totalMem = 16384;
sharedBuffers = toString (totalMem / 4) + "MB";
workMem = "16MB";
maintenanceWorkMem = "128MB";
effectiveCacheSize = toString (totalMem / 2) + "MB";
# Path to official Zabbix schema files
zabbixSchemaDir = "${pkgs.zabbix70.server}/share/zabbix/database/postgresql/";
# Database connection info
db_user = "zabbix";
db_host = "localhost";
db_name = "zabbix";
db_passwordFile = config.sops.secrets."zabbix_db_password".path;
in {
# SOPS secret for Zabbix DB password
sops.secrets."zabbix_db_password" = {
sopsFile = ../secrets/secrets_sops.yaml;
owner = "zabbix";
group = "zabbix";
mode = "0440";
};
# Rendered SQL file with secret injected
sops.templates."zabbix-init.sql" = {
content = ''
DO $$
BEGIN
IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = '${db_user}') THEN
CREATE ROLE ${db_user} WITH LOGIN PASSWORD '${config.sops.placeholder.zabbix_db_password}';
ELSE
ALTER ROLE ${db_user} WITH PASSWORD '${config.sops.placeholder.zabbix_db_password}';
END IF;
END
$$;
CREATE DATABASE ${db_name} OWNER ${db_user};
GRANT ALL PRIVILEGES ON DATABASE ${db_name} TO ${db_user};
\c ${db_name}
CREATE EXTENSION IF NOT EXISTS timescaledb;
GRANT USAGE ON SCHEMA public TO ${db_user};
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO ${db_user};
'';
owner = "postgres";
};
# PostgreSQL service configuration
services.postgresql = {
enable = true;
extensions = [ pkgs.postgresql16Packages.timescaledb ];
ensureDatabases = [ db_name ];
ensureUsers = [
{
name = db_user;
ensureDBOwnership = true;
}
];
authentication = ''
local all ${db_user} md5
host all ${db_user} 127.0.0.1/32 md5
host all ${db_user} ::1/128 md5
'';
initialScript = config.sops.templates."zabbix-init.sql".path;
settings = {
max_connections = 100;
shared_buffers = sharedBuffers;
work_mem = workMem;
maintenance_work_mem = maintenanceWorkMem;
effective_cache_size = effectiveCacheSize;
wal_level = "replica";
synchronous_commit = "off";
checkpoint_completion_target = 0.9;
checkpoint_timeout = "15min";
max_worker_processes = 4;
max_parallel_workers_per_gather = 2;
autovacuum = "on";
autovacuum_vacuum_scale_factor = 0.05;
autovacuum_analyze_scale_factor = 0.02;
shared_preload_libraries = "timescaledb";
};
};
# Zabbix Server service configuration
services.zabbixServer = {
enable = true;
package = pkgs.zabbix70.server;
extraPackages = with pkgs; [ nettools nmap traceroute ];
openFirewall = true;
database = {
type = "pgsql";
createLocally = false;
host = db_host;
port = 5432;
name = db_name;
user = db_user;
passwordFile = db_passwordFile;
};
};
# Zabbix Web frontend
services.zabbixWeb = {
enable = true;
package = pkgs.zabbix70.web;
frontend = "nginx";
# Zabbix DB settings
database = {
type = "pgsql";
host = db_host;
name = db_name;
user = db_user;
passwordFile = db_passwordFile;
};
httpd.virtualHost = {
hostName = "zabbix.test.it";
adminAddr = "antonio.nardella@provinzia.bz.it";
};
};
# Firewall settings
networking.firewall = {
enable = true;
allowedTCPPorts = [ 80 443 ];
};
# Database initialization service
systemd.services.zabbix-init-db = {
description = "Initialize Zabbix DB schema";
after = [ "postgresql.service" "sops-nix.service" ];
wants = [ "postgresql.service" "sops-nix.service" ];
serviceConfig = {
Type = "oneshot";
User = db_user;
ExecStart = pkgs.writeShellScript "zabbix-schema-load.sh" ''
set -e
echo "Checking if Zabbix DB schema already exists..."
if ! ${pkgs.postgresql}/bin/psql -U ${db_user} -h ${db_host} -d ${db_name} -c "SELECT 1 FROM users LIMIT 1;" >/dev/null 2>&1; then
echo "Importing Zabbix schema..."
export PGPASSWORD=$(cat ${db_passwordFile})
${pkgs.postgresql}/bin/psql -U ${db_user} -h ${db_host} -d ${db_name} -f ${zabbixSchemaDir}/schema.sql
${pkgs.postgresql}/bin/psql -U ${db_user} -h ${db_host} -d ${db_name} -f ${zabbixSchemaDir}/images.sql
${pkgs.postgresql}/bin/psql -U ${db_user} -h ${db_host} -d ${db_name} -f ${zabbixSchemaDir}/data.sql
else
echo "Zabbix schema already exists. Skipping import."
fi
'';
};
wantedBy = [ "multi-user.target" ];
};
# Ensure zabbix-server starts after DB initialization
systemd.services.zabbix-server = {
requires = [ "postgresql.service" "zabbix-init-db.service" ];
after = [ "postgresql.service" "sops-nix.service" "zabbix-init-db.service" ];
serviceConfig = {
LoadCredential = [
"db_password:${db_passwordFile}"
];
};
};
}
The issue I’m encountering is that while the official Zabbix schema files are available in the Nix store at:
zabbixSchemaDir = "${pkgs.zabbix70.server}/share/zabbix/database/postgresql/";
The TimescaleDB-specific schema file (timescaledb.sql
) mentioned in the Zabbix documentation is missing.
When I download the 7.0.5.tar.gz from Zabbix’s official sources, I can see the expected schema files in the archive, but they’re not included in the Nix package.
Question: How can I make these TimescaleDB schema files available in the Nix store for my configuration?
I noticed the systemd.services.zabbix-init-db
service in my configuration loads the standard schema - how would I best modify this to also load the TimescaleDB schema?
Any guidance on the most NixOS-idiomatic way to handle this would be greatly appreciated!
Thanks in advance for your help.
Antonio