Why the Agent Decision Is the One That Scales
Every other tier in the Zabbix stack scales by adding more boxes. The agent scales by being installed on the box you already have, hundreds or thousands of times. A clicky "next, next, finish" install on every Windows host you ever provision is the kind of toil that, three years in, has eaten more engineer-hours than the rest of the monitoring build combined.
That makes the agent the right place to invest in automation. The Linux side is a one-line apt install and a config-file edit; the Windows side is a Powershell script that does the same job idempotently and can be re-run on a schedule against the whole estate. This post is both, with a working Install-ZabbixAgent.ps1 you can drop into a startup-script GPO or a configuration-management run and forget about.
The other concrete reason this post is more code than prose: the agent is the layer where the active vs passive distinction shows up in the config file (not just on the proxy), and where the PSK key for encrypted traffic gets installed. Both are easy to get wrong silently, and both are easier to get right if your install script is the only thing that ever writes the config.
Agent Install
As I mentioned on my previous post, we'll be installing the Zabbix agent on Windows and Linux operating systems.
This guide assumes that you are capable of deploying a virtual machine on your own.
In my environment I'll be pointing all agents at the proxy we built in the previous post:
10.0.0.246: ZbxProxy01 (the proxy / server the agent will report to)10050: passive agent port (server connects to agent)10051: active agent port (agent connects to proxy)
Windows Install
The Windows agent ships as a signed .msi from the Zabbix download page. It can be installed by hand with the GUI, but for any environment with more than a handful of hosts you'll want to script it.
1. Manual Install (GUI)
- Download
zabbix_agent-7.4.9-windows-amd64-openssl.msifrom the Zabbix site. - Run the installer.
- Set:
Zabbix server IP/DNS:10.0.0.246Server or Proxy for active checks:10.0.0.246Hostname: the machine's hostname (the default value is fine). - Leave the rest as default and finish the installer.
The installer registers a Windows service called Zabbix Agent and starts it automatically.
2. Automated Install with Powershell
The script below downloads the MSI, installs it silently with the parameters we want, and then verifies that the service is running and listening on port 10050.
Run Powershell as Administrator. The MSI install requires elevation.
<#
.SYNOPSIS
Installs the Zabbix Agent on Windows and verifies it is healthy.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$ZabbixServer, # e.g. 10.0.0.246
[string]$AgentHostname = $env:COMPUTERNAME,
[string]$Version = '7.4.9',
[string]$DownloadDir = "$env:TEMP\zabbix"
)
begin
{
$ErrorActionPreference = 'Stop'
}
process
{
# 1. Download the MSI
$msiName = "zabbix_agent-$Version-windows-amd64-openssl.msi"
$msiUrl = "https://cdn.zabbix.com/zabbix/binaries/stable/7.4/$Version/$msiName"
$msiPath = Join-Path $DownloadDir $msiName
if (-not (Test-Path $DownloadDir))
{
$null = New-Item -ItemType Directory -Path $DownloadDir
}
Write-Verbose "Downloading $msiUrl"
Invoke-WebRequest -Uri $msiUrl -OutFile $msiPath -UseBasicParsing
# 2. Silent install with our parameters
$msiArgs = @(
'/i', "`"$msiPath`""
'/qn'
"SERVER=$ZabbixServer"
"SERVERACTIVE=$ZabbixServer"
"HOSTNAME=$AgentHostname"
'ENABLEPATH=1'
'/l*v', "`"$DownloadDir\install.log`""
)
Write-Verbose "Installing Zabbix Agent"
$proc = Start-Process -FilePath 'msiexec.exe' -ArgumentList $msiArgs -Wait -PassThru
if ($proc.ExitCode -ne 0)
{
throw "msiexec failed with exit code $($proc.ExitCode). See $DownloadDir\install.log"
}
}
Save the script as Install-ZabbixAgent.ps1 and run it like so:
.\Install-ZabbixAgent.ps1 -ZabbixServer '10.0.0.246' -Verbose
3. Verify the Agent is Working
A successful MSI install does not always mean the agent is reporting correctly. The function below performs a few quick health checks: service state, listening port, config file values, and the agent's own ping using zabbix_agent.exe -t agent.ping.
function Test-ZabbixAgent
{
[CmdletBinding()]
[OutputType([PSCustomObject])]
param
(
[string]
$ServiceName = 'Zabbix Agent',
[int]
$Port = 10050,
[string]
$ConfigPath = 'C:\Program Files\Zabbix Agent\zabbix_agentd.conf',
[string]
$BinaryPath = 'C:\Program Files\Zabbix Agent\zabbix_agentd.exe'
)
begin
{
Write-Verbose -Message '[Test-ZabbixAgent] Begin'
}
process
{
$service = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
$localPort = Get-NetTCPConnection -LocalPort $Port -State Listen -ErrorAction SilentlyContinue
$listening = if($localPort){$true}else{$false}
$config = @{}
if (Test-Path $ConfigPath)
{
Get-Content $ConfigPath |
Where-Object { $_ -match '^\s*[^#].*=' } |
ForEach-Object {
$k,$v = $_ -split '=', 2
$config[$k.Trim()] = $v.Trim()
}
}
$ping = $null
if (Test-Path $BinaryPath)
{
$ping = & $BinaryPath -t 'agent.ping' 2>$null
}
[PSCustomObject]@{
ServiceState = $service.Status
ListeningOn = $Port
IsListening = $listening
Server = $config['Server']
ServerActive = $config['ServerActive']
Hostname = $config['Hostname']
AgentPing = $ping
Healthy = ($service.Status -eq 'Running') -and $listening -and ($ping -match '\[u\|1\]')
}
}
end
{
Write-Verbose -Message '[Test-ZabbixAgent] End'
}
}
Test-ZabbixAgent | Format-List
A healthy host returns something like:
ServiceState : Running
ListeningOn : 10050
IsListening : True
Server : 10.0.0.246
ServerActive : 10.0.0.246
Hostname : WIN-APP01
AgentPing : agent.ping [u|1]
Healthy : True
If
HealthyisFalse, check the agent log atC:\Program Files\Zabbix Agent 2\zabbix_agent2.log.
Linux Install
The Linux install uses the official Zabbix repository. The example below targets Ubuntu 24.04 to match the proxy from the previous post.
1. Install the Zabbix Repository
wget https://repo.zabbix.com/zabbix/7.4/release/ubuntu/pool/main/z/zabbix-release/zabbix-release_latest_7.4+ubuntu24.04_all.deb
sudo dpkg -i zabbix-release_latest_7.4+ubuntu24.04_all.deb
sudo apt update -y
2. Install the Agent
sudo apt -y install zabbix-agent
3. Edit the Config File
Edit /etc/zabbix/zabbix_agentd.conf and update the items below:
Server=10.0.0.246
ServerActive=10.0.0.246
Hostname=lnx-app01
4. Enable and Start the Service
sudo systemctl enable zabbix-agent
sudo systemctl restart zabbix-agent
5. Verify the Agent is Working
# service is up
sudo systemctl status zabbix-agent
# port 10050 is listening
sudo ss -tlnp | grep 10050
# the agent answers its own ping
zabbix_agentd -t agent.ping
The last command should return:
agent.ping [u|1]
You Now Have a Complete Zabbix HA Stack
Going back to the topology overview: four tiers, five if you count the agents themselves. Database on 10.0.0.20, server pair on .21/.22, frontend on .23, proxy on .246, agents on every host. Each tier survives a reboot of any other; the failover behaviour is exercised, not theoretical.
Verify End-To-End Before Moving On
The five-minute sanity check that proves the whole pipeline works:
- Find a host that just got the agent. Configuration → Hosts. Click the host. Latest data should appear within 60 seconds of the first agent restart.
- Force a heartbeat alert. Stop the agent on a test host (
sudo systemctl stop zabbix-agent). WithinTimeout*MaxAttemptsseconds the host shows as unreachable in the frontend; restarting the agent clears it. - Trigger a test value. From the host:
zabbix_sender -z 10.0.0.246 -s "<host name>" -k system.test -o "hello". The value lands in Latest data → System. If it does not, the path agent → proxy → server → database has a break and you have a one-liner to reproduce it.
Next in the Series
The hosts can now report in by name, but doing that on every new VM by hand defeats the point of having a proxy. The autoregistration post wires up the metadata-driven registration flow so a new server appears in Zabbix the first time its agent successfully connects, with the right templates already attached. After that, the operational topics (alert quieting, templates as code, proxy load balancing) become possible.


