Overview
Every post in this series so far has had agents talking to proxies, proxies talking to servers, and the API answering Powershell scripts all in clear text. That's fine on a trusted segment, but the moment a single hop crosses an untrusted network it needs to be encrypted.
This guide assumes you have working agents and proxies (from the earlier posts) and that you can edit their config files and restart the services.
Zabbix supports two encryption modes for every agent-proxy-server hop:
| Mode | Pros | Cons |
|---|---|---|
| PSK | Trivial to deploy, no PKI needed | Per-host key management at scale |
| TLS | Standard PKI, central revocation | Requires a CA and cert distribution |
A common pattern: PSK for agents (lots of hosts, simple to script) and TLS certificates for proxies and the API (few endpoints, benefits from PKI). That's what we'll build.
Part 1: PSK for Agents
A PSK is just an identity string + a hex-encoded random secret. Both ends must have the same value.
1. Generate a PSK
On any Linux host (or WSL):
openssl rand -hex 32 > /tmp/zbx-psk.key
This produces a 64-character hex string the minimum length Zabbix accepts is 32 characters, but 64 is a sensible default.
Treat this like a password. Store it in your secrets manager (Vault, Azure Key Vault, AWS Secrets Manager) and pull it from there at agent-install time.
2. Configure the Agent (Linux)
Copy the key to the agent and lock it down:
sudo mkdir -p /etc/zabbix/psk
sudo mv /tmp/zbx-psk.key /etc/zabbix/psk/agent.psk
sudo chown zabbix:zabbix /etc/zabbix/psk/agent.psk
sudo chmod 600 /etc/zabbix/psk/agent.psk
Edit /etc/zabbix/zabbix_agentd.conf:
TLSConnect=psk
TLSAccept=psk
TLSPSKIdentity=PSK-lnx-app01
TLSPSKFile=/etc/zabbix/psk/agent.psk
sudo systemctl restart zabbix-agent
3. Configure the Agent (Windows) with Powershell
The same idea, scripted. The function below fetches a PSK from a file (swap in your secrets-manager call) and patches the agent config in place.
<#
.SYNOPSIS
Enables PSK encryption on a Zabbix Agent 2 install.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory)] [string]$Identity, # e.g. PSK-WIN-APP01
[Parameter(Mandatory)] [string]$PskHex, # 64-char hex string
[string]$ConfigPath = 'C:\Program Files\Zabbix Agent\zabbix_agentd.conf',
[string]$PskPath = 'C:\Program Files\Zabbix Agent\agent.psk',
[string]$ServiceName = 'Zabbix Agent'
)
begin
{
$ErrorActionPreference = 'Stop'
# 1. Write the PSK file with strict ACLs (SYSTEM + Zabbix service account only)
Set-Content -Path $PskPath -Value $PskHex -Encoding ASCII -NoNewline
function Set-ConfigValue
{
param
(
[Parameter()]
[string[]]$Lines,
[Parameter()]
[string]$Key,
[Parameter()]
[string]$Value
)
process
{
$pattern = "^\s*#?\s*$Key\s*="
$newLine = "$Key=$Value"
if ($Lines -match $pattern)
{
return $Lines -replace $pattern + '.*', $newLine
}
return $Lines + $newLine
}
}
}
process
{
$acl = New-Object System.Security.AccessControl.FileSecurity
$acl.SetAccessRuleProtection($true, $false) # disable inheritance
foreach ($principal in 'NT AUTHORITY\SYSTEM', 'BUILTIN\Administrators')
{
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule(
$principal, 'FullControl', 'Allow')
$acl.AddAccessRule($rule)
}
Set-Acl -Path $PskPath -AclObject $acl
# 2. Patch the config (idempotent - replaces existing keys)
$lines = Get-Content -Path $ConfigPath
$lines = Set-ConfigValue -Lines $lines -Key 'TLSConnect' -Value 'psk'
$lines = Set-ConfigValue -Lines $lines -Key 'TLSAccept' -Value 'psk'
$lines = Set-ConfigValue -Lines $lines -Key 'TLSPSKIdentity' -Value $Identity
$lines = Set-ConfigValue -Lines $lines -Key 'TLSPSKFile' -Value $PskPath
Set-Content -Path $ConfigPath -Value $lines -Encoding ASCII
Restart-Service -Name $ServiceName
}
Run it as:
.\Enable-ZabbixPsk.ps1 -Identity 'PSK-WIN-APP01' -PskHex (Get-Content .\agent.psk -Raw).Trim()
4. Configure the Host in the Frontend
Go to Data Collection -> Hosts -> host -> Encryption tab:
Connections to host:PSKConnections from host: tickPSKonlyPSK identity:PSK-WIN-APP01(must match the agent)PSK: paste the same 64-character hex string
Save and wait one minute. The host's Availability indicator turns green again, and Reports -> Audit log will show the encryption change.
If the host stays red, check
zabbix_agentd.logon the host. The two most common errors areinvalid PSK identity(mismatched identity strings) andinvalid PSK length(file has a trailing newlineNoNewlinematters).
5. Verify the Connection Is Encrypted
From the proxy or server:
zabbix_get -s 10.0.0.50 -k 'agent.ping' \
--tls-connect=psk \
--tls-psk-identity='PSK-WIN-APP01' \
--tls-psk-file=/etc/zabbix/psk/win-app01.psk
A successful reply (1) confirms the agent only accepts PSK-encrypted requests. Try the same call without the TLS flags it should fail.
6. Automating PSK Rollout
Pair the script above with the autoregistration flow from the earlier post:
- Pull a fresh 64-char hex from your secrets manager during VM provisioning.
- Inject
TLSPSKIdentityintoHostMetadata(e.g.windows-prod|PSK-WIN-APP01). - Run the PSK script as part of the Zabbix-agent install.
- After autoregistration, use the API (Powershell wrapper from the proxy load-balancing post) to set the
tls_connect,tls_accept,tls_psk_identity, andtls_pskfields on the new host.
That gives you fully encrypted agents from first boot no UI clicks.
Part 2: TLS Certificates for Proxies and Server
PSK works fine for thousands of agents, but for the handful of proxies and especially for cross-site links TLS certificates are easier to rotate and easier to revoke.
1. Issue a Cert From Your CA
For a proxy named ZbxProxy01.example.com, generate a CSR and have your internal CA sign it. The cert needs:
Subject CN:ZbxProxy01.example.com(or whatever you'll use asTLSServerCertIssuer/Subject)Extended Key Usage:serverAuth, clientAuthZabbix uses the same cert for both directions
Drop the resulting files on the proxy:
sudo install -o zabbix -g zabbix -m 600 proxy01.crt /etc/zabbix/ssl/proxy01.crt
sudo install -o zabbix -g zabbix -m 600 proxy01.key /etc/zabbix/ssl/proxy01.key
sudo install -o zabbix -g zabbix -m 644 ca.crt /etc/zabbix/ssl/ca.crt
2. Configure the Proxy
Edit /etc/zabbix/zabbix_proxy.conf:
TLSConnect=cert
TLSAccept=cert
TLSCAFile=/etc/zabbix/ssl/ca.crt
TLSCertFile=/etc/zabbix/ssl/proxy01.crt
TLSKeyFile=/etc/zabbix/ssl/proxy01.key
TLSServerCertIssuer=CN=Internal Issuing CA,O=Example,C=US
TLSServerCertSubject=CN=zabbix.example.com,O=Example,C=US
sudo systemctl restart zabbix-proxy
3. Configure the Server Side
Same idea, but on the Zabbix server itself. Then in the frontend:
Administration -> Proxies -> proxy -> Encryption tab:
Connections to proxy:CertificateConnections from proxy: tickCertificateIssuerandSubject: optional but strongly recommended they pin the exact cert that's allowed.
Pinning issuer and subject means a stolen cert from another internal service won't work even if it was signed by the same CA. Skip pinning only if you understand what you're giving up.
4. Verify
Watch the proxy log for the handshake:
sudo tail -f /var/log/zabbix/zabbix_proxy.log | grep -i tls
You want a line like TLS handshake with [10.0.0.21:10051] successful. If it loops on failed, mismatched issuer/subject is almost always the cause.
Operational Notes
- Rotate PSKs annually. Generate a new key, push it to the host, update the frontend via the API, restart the agent. The script above is idempotent re-running it with a new PSK is the rotation procedure.
- Monitor cert expiry. Add a
system.run[openssl x509 -enddate -noout -in /etc/zabbix/ssl/proxy01.crt]item with a trigger 30 days before expiry. Or even better use the LLD pattern from the previous post to discover all certs in/etc/zabbix/ssl/and graph their expiry dates. - Don't mix modes mid-flight. Set
TLSAccept=psk,unencryptedtemporarily during rollout, then dropunencryptedonce every host is migrated. Leaving both on permanently defeats the purpose.
What to Do Next
PSK gives you a fast, scriptable way to encrypt the long tail of agents; TLS certificates give you proper PKI for the few high-value links between proxies and the server. Use both. PSK on hosts where rotating a 256-bit hex string is the simplest possible operation, and certs on the inter-tier links where revocation, expiry monitoring, and CA chains earn their keep.
Three concrete moves to harden your fleet this week:
- Stand up
TLSAccept=psk,unencryptedfor the rollout window. Don't try to flip the entire fleet at once. The dual-mode setting lets old and new agents coexist while you migrate; removeunencryptedonly after you've verified every host reports as PSK-connected. - Add a cert-expiry trigger today, not "soon". A
system.run[openssl x509 -enddate -noout -in /etc/zabbix/ssl/proxy01.crt]item plus a 30-day-before-expiry trigger has saved more outages than the actual encryption has prevented. Schedule the trigger as part of the cert rollout itself so it's never forgotten. - Script PSK rotation as the deployment. Generate a new key, push it to the host, update the frontend via the API, restart the agent. The same script is the rollout and the rotation. If the rollout script doesn't survive being re-run, neither will your annual rotation.
Pairs naturally with the templates as code post (so PSK assignments and TLS settings are version-controlled, not clicked into the UI) and the autoregistration post (so new hosts come up encrypted on the first connection, not after a cleanup pass).


