Zabbix 7.0 LTS 双机部署实录

手上两台云主机跑了大半年,一直是裸奔状态——没监控、没告警,全靠时不时登上去 top 一眼。周末抽了半天把 Zabbix 搭起来,一台做服务端,一台做被监控机。

环境:两台都是 Ubuntu 24.04,Zabbix 用 7.0 这个 LTS 版本。

最终架构

                    ┌─────────────────────────┐
    浏览器 ────────▶│      Server A           │
                    │  Nginx        :8081     │
                    │  PHP-FPM      8.3       │
                    │  Zabbix Server :10051   │
                    │  MariaDB      10.11     │
                    │  Zabbix Agent (监控自身) │
                    └────────────┬────────────┘
                                 │ 轮询 :10050
                                 ▼
                    ┌─────────────────────────┐
                    │      Server B           │
                    │  Zabbix Agent 2         │
                    └─────────────────────────┘

Server A 装全套(Server + Web + 数据库),Server B 只装一个 Agent。Server B 不跑数据库,内存占用很低,1G 内存的机器也够。

下文出现的地址统一用占位符,实际部署时替换成自己的:

占位符说明
203.0.113.10Server A 公网 IP
198.51.100.20Server B 公网 IP
zabbix.example.com指向 Server A 的域名
ZBX_DB_PASSZabbix 数据库密码,自己换

动手前先定三件事

这三件事如果装到一半再改,返工成本很高,先想清楚。

一、数据库用 MySQL 还是 MariaDB。 官方文档默认写的是 MySQL,我一开始也打算照做。结果发现 Server A 只有 2G 内存,而且上面还跑着别的东西,空闲内存不到 900M。MySQL 8.0 的默认配置光 InnoDB 缓冲池就要吃掉几百兆,装完大概率被 OOM Killer 干掉。所以换成了 MariaDB——同源、协议兼容、内存开销小一截,配上一份低内存参数就能稳住。

二、Web 端口。 Zabbix 官方的 Nginx 配置模板默认监听 80。但如果你的机器上已经跑了别的东西占了 80,别急着把它停掉腾地方——Zabbix 完全可以挂在别的端口上,改一行配置的事。我这次就是因为 80/443 已经被 Caddy 占着,把 Zabbix 挪到了 8081,两者互不干扰。

三、版本选 LTS。 Zabbix 的版本号分 LTS 和标准版。7.0 是 LTS,支持到 2029 年,够用很久了。追最新的标准版,支持周期可能只有一年半,不值当。

第一步:先看看机器上已经有什么

这一步很多人跳过,我建议别跳。尤其是云主机,镜像里往往预装了你不知道的东西。

# 系统版本和架构
lsb_release -d
uname -m

# 内存、磁盘、CPU
free -h
df -h /
nproc

# 时区
timedatectl

# 谁在占端口
sudo ss -tlnp

这次就是靠最后一条命令发现 Server A 的 80 和 443 早就被一个反向代理占了,8080 上还挂着 Docker 容器。如果当时闷头装下去,Nginx 启动直接就会因为端口冲突失败。

输出里如果看到一堆不认识的进程,先别慌着清理。搞清楚它们干什么的再说,很多是云厂商的监控组件或者你自己以前部署的服务。

顺手把时区设对,Zabbix 的图表时间轴会用到:

sudo timedatectl set-timezone Asia/Shanghai

Server A(一):装数据库

sudo apt update
sudo apt install -y mariadb-server mariadb-client

装完先别急着启动,把低内存参数写进去。MariaDB 在 Ubuntu 上会读 /etc/mysql/mariadb.conf.d/ 下的所有 .cnf 文件,新建一个:

sudo tee /etc/mysql/mariadb.conf.d/99-zabbix-lowmem.cnf > /dev/null <<'EOF'
[mysqld]
innodb_buffer_pool_size        = 128M
innodb_log_file_size           = 48M
innodb_flush_log_at_trx_commit = 2
innodb_file_per_table          = 1
innodb_default_row_format      = dynamic
max_connections                = 60
table_open_cache               = 400
tmp_table_size                 = 32M
max_heap_table_size            = 32M
performance_schema             = OFF
log_bin_trust_function_creators = 1
character-set-server           = utf8mb4
collation-server               = utf8mb4_bin
EOF

几个参数说明一下:

  • innodb_buffer_pool_size 从默认的 128M 起步,内存充足的话可以往上加。2G 的机器就别贪心。
  • performance_schema = OFF 能省几十兆,对小型监控场景没什么影响。
  • innodb_default_row_format = dynamic 是 Zabbix 的硬性要求,MariaDB 10.2 以后默认就是这个值,写上是图个保险。
  • log_bin_trust_function_creators = 1 是为了后面导入建库脚本时不被二进制日志卡住。
如果你的机器内存有 8G 以上,把 innodb_buffer_pool_size 提到 1G 甚至 2G 都行,性能会好很多。

然后启动:

sudo systemctl enable --now mariadb
sudo systemctl status mariadb

Server A(二):装 Zabbix 服务端

加官方源。注意源包的版本号里带着系统代号,Ubuntu 24.04 就是 ubuntu24.04:

cd /tmp
wget https://repo.zabbix.com/zabbix/7.0/ubuntu/pool/main/z/zabbix-release/zabbix-release_latest_7.0+ubuntu24.04_all.deb
sudo dpkg -i zabbix-release_latest_7.0+ubuntu24.04_all.deb
sudo apt update

装组件:

sudo apt install -y \
  zabbix-server-mysql \
  zabbix-frontend-php \
  zabbix-nginx-conf \
  zabbix-sql-scripts \
  zabbix-agent

这几个包各管什么:

  • zabbix-server-mysql —— 服务端主程序
  • zabbix-frontend-php —— Web 界面。虽然名字带 php,但里面并不含 PHP 运行环境,apt 会自动把 php-fpm 作为依赖装上
  • zabbix-nginx-conf —— Nginx 的配置模板
  • zabbix-sql-scripts —— 建库用的 SQL 脚本
  • zabbix-agent —— 顺手装上,用来监控服务端自己
7.0 把 SQL 脚本单独拆成了 zabbix-sql-scripts 包。6.0 及以前这些脚本是塞在 zabbix-server-mysql 里的,路径也不一样。照着旧教程做会找不到文件。

Server A(三):建库导表

登录数据库:

sudo mariadb

在 SQL 提示符里执行:

CREATE DATABASE zabbix CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
CREATE USER 'zabbix'@'localhost' IDENTIFIED BY 'ZBX_DB_PASS';
GRANT ALL PRIVILEGES ON zabbix.* TO 'zabbix'@'localhost';
SET GLOBAL log_bin_trust_function_creators = 1;
FLUSH PRIVILEGES;
EXIT;

字符集必须是 utf8mb4 配 utf8mb4_bin,这是 Zabbix 的硬要求,用 utf8mb4_general_ci 会在导入时报错。

导入表结构。脚本是 gzip 压缩的,直接用 zcat 管道喂给客户端:

zcat /usr/share/zabbix-sql-scripts/mysql/server.sql.gz \
  | mariadb --default-character-set=utf8mb4 -uzabbix -p'ZBX_DB_PASS' zabbix

导入过程视机器性能而定,我这边 200 多张表用了十几秒。

导完把刚才开的那个参数关掉:

sudo mariadb -e "SET GLOBAL log_bin_trust_function_creators = 0;"

确认一下结果,正常应该有 200 张以上的表:

sudo mariadb -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='zabbix';"

Server A(四):改配置

服务端配置

编辑 /etc/zabbix/zabbix_server.conf,DBName 和 DBUser 装包时已经填好了,要找的是 DBPassword——它默认是注释掉的:

DBName=zabbix
DBUser=zabbix
DBPassword=ZBX_DB_PASS

改完可以这样确认:

sudo grep -E '^(DBName|DBUser|DBPassword)=' /etc/zabbix/zabbix_server.conf

Nginx 配置

zabbix-nginx-conf 会生成 /etc/nginx/conf.d/zabbix.conf,但里面 listen 和 server_name 两行是注释状态,必须手动放开,否则 Nginx 加载后不监听任何端口。

sudo sed -i 's|^#\s*listen\s*8080;|        listen          8081;|' /etc/nginx/conf.d/zabbix.conf
sudo sed -i 's|^#\s*server_name\s*example.com;|        server_name     _;|' /etc/nginx/conf.d/zabbix.conf

模板里写的占位端口是 8080,按自己情况改。server_name 填 _ 表示接受任意 Host,后面要绑域名再换成具体域名。

改完检查语法:

sudo nginx -t

跳过 Web 安装向导

正常流程是启动服务后打开浏览器,走一遍 Web 安装向导。但那样每次部署都要手工点一遍,不方便自动化。

Zabbix 的判断逻辑很简单:/etc/zabbix/web/zabbix.conf.php 存在就跳过向导。所以我们直接把这个文件写出来:

sudo tee /etc/zabbix/web/zabbix.conf.php > /dev/null <<'PHPEOF'
<?php
$DB['TYPE']           = 'MYSQL';
$DB['SERVER']         = 'localhost';
$DB['PORT']           = '0';
$DB['DATABASE']       = 'zabbix';
$DB['USER']           = 'zabbix';
$DB['PASSWORD']       = 'ZBX_DB_PASS';

$DB['SCHEMA']         = '';
$DB['ENCRYPTION']     = false;
$DB['KEY_FILE']       = '';
$DB['CERT_FILE']      = '';
$DB['CA_FILE']        = '';
$DB['VERIFY_HOST']    = false;
$DB['CIPHER_LIST']    = '';

$ZBX_SERVER           = 'localhost';
$ZBX_SERVER_PORT      = '10051';
$ZBX_SERVER_NAME      = 'Zabbix';

$IMAGE_FORMAT_DEFAULT = IMAGE_FORMAT_PNG;
PHPEOF

注意 $DB['TYPE'] 这里填 MYSQL,即便底层是 MariaDB——因为 Zabbix 把 MariaDB 归在 MySQL 家族里,两侧驱动是共用的。

权限要设对,这个文件里有数据库密码:

sudo chown www-data:www-data /etc/zabbix/web/zabbix.conf.php
sudo chmod 640 /etc/zabbix/web/zabbix.conf.php

PHP 时区

PHP 不设时区会在日志里刷警告,顺手加上:

echo 'date.timezone = Asia/Shanghai' \
  | sudo tee /etc/php/8.3/fpm/conf.d/99-zabbix-timezone.ini

Ubuntu 24.04 自带的 PHP 是 8.3,版本号对不上就 ls /etc/php/ 看一眼。

Server A(五):配置 Agent 并启动

Zabbix Agent 装完默认的 Server 是 127.0.0.1,服务端监控自己正好用这个值,确认一下就行:

grep -E '^(Server|ServerActive|Hostname)=' /etc/zabbix/zabbix_agentd.conf

然后启动全部服务:

sudo systemctl daemon-reload

sudo systemctl restart php8.3-fpm
sudo systemctl restart zabbix-server zabbix-agent nginx

sudo systemctl enable zabbix-server zabbix-agent nginx php8.3-fpm mariadb

注意 php-fpm 要先于 zabbix-server 重启,因为 Nginx 通过 unix socket 连它,顺序反了第一次请求可能 502。

检查状态:

for s in mariadb php8.3-fpm nginx zabbix-server zabbix-agent; do
  printf '%-16s %s\n' "$s" "$(systemctl is-active $s)"
done

五个都是 active 才算过。

Server A(六):验证

端口有没有起来:

sudo ss -tlnp | grep -E ':10051|:8081'

Web 能不能访问:

curl -s -o /dev/null -w 'HTTP %{http_code}\n' http://127.0.0.1:8081/
curl -s http://127.0.0.1:8081/ | grep -oE '<title>[^<]*</title>'

如果标题是 Zabbix 而不是安装向导的标题,说明配置文件生效了。

最直接的办法是调一次 API,能返回版本号就说明 Server、数据库、Web 三者这条链路全通了:

curl -s -X POST http://127.0.0.1:8081/api_jsonrpc.php \
  -H 'Content-Type: application/json-rpc' \
  -d '{"jsonrpc":"2.0","method":"apiinfo.version","params":{},"id":1}'

正常返回:

{"jsonrpc":"2.0","result":"7.0.31","id":1}

服务端到这就完事了。默认账号是 Admin / zabbix,第一次登录后会强制改密码。

Server B:装 Agent

被监控机只需要装 Agent,不用数据库也不用 Web。

cd /tmp
wget https://repo.zabbix.com/zabbix/7.0/ubuntu/pool/main/z/zabbix-release/zabbix-release_latest_7.0+ubuntu24.04_all.deb
sudo dpkg -i zabbix-release_latest_7.0+ubuntu24.04_all.deb
sudo apt update
sudo apt install -y zabbix-agent2

7.0 提供了两个 Agent:老的 C 语言 zabbix-agent,和新的 Go 语言 zabbix-agent2。新机器直接用 zabbix-agent2,支持更多内置插件,性能也更好。

改配置 /etc/zabbix/zabbix_agent2.conf,三个关键项:

Server=203.0.113.10
ServerActive=203.0.113.10:10051
Hostname=web-b-01
  • Server 是被动模式的白名单——服务端可以主动来连这台机器的 10050 端口。填服务端的 IP。
  • ServerActive 是主动模式的目标地址,Agent 会把数据推过去。
  • Hostname 必须全局唯一,而且要和在 Web 界面里添加主机时填的名字完全一致,否则主动模式的数据会因为对不上号被丢弃。

配置里的 Hostname 默认取系统主机名。云主机的主机名通常是 iZxxxxxx 这种随机串,又长又难记,建议手动改成有意义的名字。

启动:

sudo systemctl enable --now zabbix-agent2
sudo systemctl status zabbix-agent2

自测一下:

zabbix_agent2 -t agent.ping

返回 [s|1] 就正常。

打通网络:这一步最容易卡住

Zabbix 的监控数据流有两个方向,取决于你用哪种模式:

模式数据流需要放行的端口
被动服务端 → 被监控机被监控机入站 10050
主动被监控机 → 服务端服务端入站 10051

云服务器的安全组默认是不放行这两个端口的,很多人装完发现 Web 界面里主机一直亮红,八成是这里。

这次踩的坑更绕一点:两台机器虽然都是同一个云厂商,但分属不同的 VPC,内网根本不通:

# 在 Server A 上查内网地址
ip -4 -o addr show | awk '{print $2, $4}'
# eth0  10.0.0.16/22
# 而 Server B 是 172.16.0.89/18

网段完全对不上,只能走公网。所以必须去控制台放行安全组。

我选的是被动模式,只放行一条规则:

方向:入站
协议端口:TCP:10050
来源:203.0.113.10/32
策略:允许

来源写成 /32 只放行服务端那一台机器,比 0.0.0.0/0 安全得多。被动模式下 Agent 端口没必要对整个互联网开放。

如果服务端和被监控机都在内网且互通,把 Server 填成服务端的内网地址,就能完全绕开公网和安全组。

放行之后,先在服务端上装个测试工具验证:

sudo apt install -y zabbix-get

zabbix-get 是一个独立的命令行工具,它做的事情和 Zabbix Server 采集数据时一模一样:按 Zabbix 协议去连 Agent 的 10050 端口取值。用它测试比在 Web 界面里猜要快得多。

zabbix_get -s 198.51.100.20 -p 10050 -k agent.ping

返回 1 说明通了。再多取几个指标确认:

zabbix_get -s 198.51.100.20 -p 10050 -k system.hostname
zabbix_get -s 198.51.100.20 -p 10050 -k 'system.cpu.load[all,avg1]'
zabbix_get -s 198.51.100.20 -p 10050 -k 'vm.memory.size[available]'
zabbix_get -s 198.51.100.20 -p 10050 -k 'vfs.fs.size[/,free]'

如果这里就报 Timeout 或者 Connection refused,别去 Web 界面折腾了,问题百分之百在网络层:

  1. 端口有没有在监听 —— 去被监控机跑 ss -tlnp | grep 10050
  2. 系统防火墙 —— sudo ufw status,有的话 sudo ufw allow from 203.0.113.10 to any port 10050 proto tcp
  3. 云安全组 —— 就是上面说的那条规则

添加主机

图形界面操作:登录后进 数据采集 → 主机 → 创建主机。

  • 主机名称:必须和 Agent 配置里的 Hostname 一致
  • 主机群组:选 Linux servers
  • 接口:选 Agent,IP 填 198.51.100.20,端口 10050
  • 模板:搜 Linux by Zabbix agent,关联上

保存后等一分钟左右,主机列表里那一列可用性会从灰色变成绿色。

用 API 添加适合批量或者写进脚本。核心就三步:登录拿 token、查出模板和主机组的 ID、创建主机。

API=http://127.0.0.1:8081/api_jsonrpc.php

# 登录,拿到 token
TOKEN=$(curl -s -X POST $API -H 'Content-Type: application/json-rpc' \
  -d '{"jsonrpc":"2.0","method":"user.login","params":{"username":"Admin","password":"你的密码"},"id":1}' \
  | python3 -c 'import sys,json; print(json.load(sys.stdin)["result"])')

# 查模板 ID
curl -s -X POST $API -H 'Content-Type: application/json-rpc' \
  -d "{\"jsonrpc\":\"2.0\",\"method\":\"template.get\",\"params\":{\"filter\":{\"host\":[\"Linux by Zabbix agent\"]},\"output\":[\"templateid\",\"host\"]},\"auth\":\"$TOKEN\",\"id\":1}"

# 查主机组 ID
curl -s -X POST $API -H 'Content-Type: application/json-rpc' \
  -d "{\"jsonrpc\":\"2.0\",\"method\":\"hostgroup.get\",\"params\":{\"filter\":{\"name\":[\"Linux servers\"]},\"output\":[\"groupid\",\"name\"]},\"auth\":\"$TOKEN\",\"id\":1}"

拿到两个 ID 后创建主机:

curl -s -X POST $API -H 'Content-Type: application/json-rpc' \
  -d "{\"jsonrpc\":\"2.0\",\"method\":\"host.create\",\"params\":{
    \"host\":\"web-b-01\",
    \"interfaces\":[{\"type\":1,\"main\":1,\"useip\":1,\"ip\":\"198.51.100.20\",\"dns\":\"\",\"port\":\"10050\"}],
    \"groups\":[{\"groupid\":\"2\"}],
    \"templates\":[{\"templateid\":\"10001\"}]
  },\"auth\":\"$TOKEN\",\"id\":1}"

接口的 type 字段有讲究:1 是 Zabbix Agent,2 是 SNMP,3 是 IPMI,4 是 JMX。填错了接口就采集不到数据。

主机建完,用 API 查一下采集状态:

curl -s -X POST $API -H 'Content-Type: application/json-rpc' \
  -d "{\"jsonrpc\":\"2.0\",\"method\":\"host.get\",\"params\":{
    \"filter\":{\"host\":[\"web-b-01\"]},
    \"selectInterfaces\":[\"ip\",\"port\",\"available\"]
  },\"auth\":\"$TOKEN\",\"id\":1}"

available 字段的含义:0 是还没检测,1 可用,2 不可用。有个细节是——服务端不是实时检测的,默认最快也要一分钟才轮询一次。改完配置别急着下结论,等一分钟再看。

给 Web 加一层 HTTPS(可选)

Zabbix 的 Web 界面走的是明文 HTTP,登录密码也是明文传输。如果机器有公网 IP,强烈建议套一层 HTTPS。

用 Caddy 最省事,证书申请和续期全自动:

sudo apt install -y caddy

编辑 /etc/caddy/Caddyfile:

zabbix.example.com {
    reverse_proxy 127.0.0.1:8081 {
        header_up Host {host}
        header_up X-Real-IP {remote_host}
    }
}

前提是域名已经解析到这台机器的公网 IP,且 80、443 端口能通——Caddy 要通过 80 端口完成 ACME 验证来签发证书。

sudo systemctl reload caddy

如果前面 Zabbix 已经占了 80 端口,记得把它改回 8081,让 Caddy 独占 80/443。

验证:

curl -s -o /dev/null -w 'HTTP %{http_code}\n' https://zabbix.example.com/
echo | openssl s_client -connect zabbix.example.com:443 \
  -servername zabbix.example.com 2>/dev/null | openssl x509 -noout -dates
Caddy 的 reload 依赖管理 API。如果配置里写了 admin off,reload 会直接失败,这时改用 systemctl restart caddy。代价是所有站点中断一两秒。

踩过的坑

安全组没放行,卡了最久。 表现是 Web 界面里主机一直是红的,available 显示 2。第一反应会去查 Agent 配置,其实应该反过来查网络。养成习惯:zabbix_get 能通再谈后面的事,通不了就是网络问题。

两台机器不同 VPC,内网完全不通用。 以为同一个云厂商就能走内网,实际网段都对不上。查内网地址用 ip -4 -o addr show 一眼就能看出来。

Nginx 配置模板里的 listen 是注释状态。 zabbix-nginx-conf 生成的配置文件,listen 和 server_name 默认都被 # 注释掉了,不手动放开就什么都不会监听,而且 Nginx 启动还不报错。

DBPassword 默认注释。 zabbix_server.conf 里 DBPassword 是注释状态,改了密码忘了填这里,服务端启动时会连不上库。

Agent 的 Hostname 和 Web 里填的主机名必须一致。 主动模式下对不上号,数据会被静默丢弃,日志里也不一定有明显的报错。

改完配置等服务端刷新。 Zabbix Server 有配置缓存,打开或关闭主机的监控项后不会立即生效,默认要等一分钟。

内存小的机器一定要调数据库参数。 这事没有商量余地。不调的话 MySQL/MariaDB 的默认配置很可能在半夜被 OOM Killer 干掉,而且白天完全看不出来。

附录:常用文件与命令

服务端文件

路径用途
/etc/zabbix/zabbix_server.conf服务端主配置
/etc/zabbix/web/zabbix.conf.phpWeb 界面数据库配置
/etc/nginx/conf.d/zabbix.confNginx 站点配置
/etc/php/8.3/fpm/pool.d/zabbix.confPHP-FPM 进程池
/var/log/zabbix/zabbix_server.log服务端日志
/usr/share/zabbix-sql-scripts/mysql/server.sql.gz建库脚本

Agent 文件

路径用途
/etc/zabbix/zabbix_agent2.confAgent 配置
/var/log/zabbix/zabbix_agent2.logAgent 日志

排错顺序

# 1. 服务在不在
systemctl status zabbix-server

# 2. 端口在不在
ss -tlnp | grep -E '10051|10050'

# 3. 网络通不通(在服务端执行)
zabbix_get -s <被监控机IP> -p 10050 -k agent.ping

# 4. 数据库连不连得上
mariadb -uzabbix -p"$(sudo grep ^DBPassword= /etc/zabbix/zabbix_server.conf | cut -d= -f2)" zabbix -e "SELECT 1"

# 5. 看日志
tail -50 /var/log/zabbix/zabbix_server.log
tail -50 /var/log/nginx/error.log

重启顺序

改了配置之后按这个顺序来,能避免大部分莫名其妙的报错:

sudo systemctl restart php8.3-fpm
sudo systemctl restart zabbix-server zabbix-agent nginx

改的是数据库配置的话,先重启 mariadb 再重启 zabbix-server。

最后修改:2026 年 10 月 10 日
如果觉得我的文章对你有用,请随意赞赏