Zabbix Proxy: Step-by-Step Setup for 7.0 and 6.4

Quick answer
Zabbix proxy takes 20-30 minutes to set up and rests on four things:
  • Proxy on the same major version as the server: server 7.0 means proxy 7.0.
  • Proxy config has the mode, server address, and Hostname set correctly.
  • A proxy with the exact same name, letter for letter, and the same mode exists in the web interface.
  • Port 10051/tcp is open between the proxy and the server, and clocks on both machines are in sync.

If the proxy fails to start with an invalid option or unknown parameter error, it’s almost always a typo or an outdated parameter in zabbix_proxy.conf. Fix it by checking the config, see the “Troubleshooting” section.

A minimal working config for an active proxy 7.0 on SQLite looks like this. Below we’ll break down every line and everything around it.


# /etc/zabbix/zabbix_proxy.conf on proxy zbx-proxy-01
ProxyMode=0
Server=10.10.0.10
Hostname=zbx-proxy-01
DBName=/var/lib/zabbix/zabbix_proxy.db
LogFile=/var/log/zabbix/zabbix_proxy.log
PidFile=/run/zabbix/zabbix_proxy.pid
SocketDir=/run/zabbix

Diagnosis: why you need Zabbix proxy and why it’s “stuck grey”

You set up a Zabbix proxy at a branch office, and in the web interface it shows grey with “last seen: never”. Agents are silent, the queue is growing. Sound familiar?

Here’s the deal. Zabbix proxy is a data collector that acts on behalf of the server. It polls agents, SNMP, HTTP, and everything else within its own segment, stores the data in a local buffer, and sends it to the server in batches. The server gives it configuration: which hosts, which items, at what intervals.

In practice, a proxy solves three problems. It offloads the server when you have thousands of hosts. It gives you monitoring of remote sites over a single TCP connection instead of a hundred. And it doesn’t lose data when the link to the central site drops: it buffers locally and sends later.

What you’ll get after this article: a working active proxy 7.0 LTS with PSK encryption, verified through logs and the API, with self-monitoring, backups, and an upgrade plan. Plus a breakdown of the errors people trip over most often, including the mysterious “zabbix proxy 7 invalid option”.

Time: 30-40 minutes on a clean machine. If you’re adding encryption and proxy groups, budget an hour.

What you’ll need:

  • A working Zabbix server, here it’s 7.0 LTS on host zbx-server with address 10.10.0.10.
  • A VM or physical box for the proxy: zbx-proxy-01, 192.168.50.20, Ubuntu 24.04.
  • Root or sudo on the proxy and admin rights in the Zabbix web interface.
  • Network access from the proxy to the server on 10051/tcp.

What’s covered in this article:

  • How a proxy works and how active mode differs from passive.
  • Seven reasons a proxy won’t connect.
  • Installation on Ubuntu, Debian, and RHEL, plus a PostgreSQL option for large sites.
  • PSK encryption and proxy groups in 7.0.
  • Verification: logs, ports, database, API.
  • Errors with ready-to-use commands, including invalid option and unknown parameter.
  • Alternatives, prevention, backup, upgrades, and FAQ.

Architecture: where the proxy sits and where data flows

Before installing, look at the diagram. Half of all proxy problems come from not understanding who connects to whom.

%%{init: {
  'theme': 'base',
  'themeVariables': {
    'primaryColor': '#ffffff',
    'primaryTextColor': '#1e293b',
    'primaryBorderColor': '#94a3b8',
    'lineColor': '#64748b',
    'fontSize': '15px',
    'fontFamily': 'ui-sans-serif, system-ui, sans-serif'
  },
  'flowchart': {'curve': 'linear', 'nodeSpacing': 50, 'rankSpacing': 50}
}}%%
flowchart TD
    A["Branch agents"] --> P["Zabbix proxy"]
    S1["SNMP devices"] --> P
    H1["HTTP and ICMP checks"] --> P
    P --> B["Proxy local buffer"]
    B --> Z["Zabbix server"]
    Z --> D["Server database"]
    W["Web interface"] --> Z
    style A fill:#f8fafc,stroke:#3b82f6,stroke-width:2px,color:#1e40af
    style S1 fill:#f8fafc,stroke:#3b82f6,stroke-width:2px,color:#1e40af
    style H1 fill:#f8fafc,stroke:#3b82f6,stroke-width:2px,color:#1e40af
    style P fill:#f8fafc,stroke:#22c55e,stroke-width:2px,color:#15803d
    style B fill:#f8fafc,stroke:#22c55e,stroke-width:2px,color:#15803d
    style Z fill:#f8fafc,stroke:#3b82f6,stroke-width:2px,color:#1e40af
    style D fill:#f8fafc,stroke:#3b82f6,stroke-width:2px,color:#1e40af
    style W fill:#f8fafc,stroke:#3b82f6,stroke-width:2px,color:#1e40af

Here’s the important part: the proxy doesn’t store history for graphs and doesn’t evaluate triggers. It only collects and forwards. All triggers, events, and notifications live on the server. So if the server goes down, the proxy keeps collecting data, but no alerts will fire.

Active or passive proxy: which one to pick

The mode determines the direction of the connection. An active proxy initiates contact with the server itself, pulls configuration, and pushes data. A passive proxy waits for the server to come to it.

%%{init: {
  'theme': 'base',
  'themeVariables': {
    'primaryColor': '#f8fafc',
    'primaryTextColor': '#1e293b',
    'primaryBorderColor': '#94a3b8',
    'noteBkgColor': '#fefce8',
    'noteTextColor': '#713f12',
    'noteBorderColor': '#fbbf24',
    'actorBkg': '#f8fafc',
    'actorBorder': '#94a3b8',
    'actorTextColor': '#1e293b',
    'fontSize': '15px',
    'fontFamily': 'ui-sans-serif, system-ui, sans-serif'
  },
  'sequence': {
    'mirrorActors': false,
    'messageAlign': 'center',
    'actorMargin': 120,
    'width': 160,
    'noteMargin': 12
  }
}}%%
sequenceDiagram
    participant P as Active proxy
    participant S as Zabbix server
    Note over P,S: Connection is always opened by the proxy
    P->>S: Configuration request
    S->>P: List of hosts and items
    P->>S: Batch of collected data
    S->>P: Receipt confirmation
Parameter Active, ProxyMode=0 Passive, ProxyMode=1
Who opens the connection Proxy to server Server to proxy
Needs inbound access to proxy from server No Yes, port 10051
Works behind NAT without port forwarding Yes No
Load on server Lower Higher, needs StartProxyPollers
When to choose Branches, cloud, DMZ, almost always When security policy forbids outbound connections from the segment

My default choice is active. A branch behind NAT, an ISP router nobody has touched since install day: an active proxy couldn’t care less about any of that. It only needs one outbound port. I use passive only where security teams explicitly forbid initiating connections out of a protected segment.

Causes: why Zabbix proxy won’t connect to the server

Before you treat the symptom, figure out what’s actually wrong. Here are the causes I’ve run into most often over years of working with distributed monitoring, roughly in order of frequency.

# Cause Why it breaks things
1 Hostname in the config doesn’t match the proxy name in the interface The server looks up the proxy by name. A case mismatch, a space, a trailing dot, and the server reports no such proxy exists
2 The mode in the config doesn’t match the mode in the interface The proxy is active, but a passive proxy was created in the web interface. Each side waits for the other to call first
3 Port 10051 is closed or NAT blocks it An active proxy can’t reach the server, a passive proxy won’t accept connections
4 Proxy version differs from server version A 7.0 server with a 6.x proxy runs in a degraded mode, anything older doesn’t work at all
5 An error in zabbix_proxy.conf The proxy refuses to start on an unknown parameter or invalid value. Hence invalid option and unknown parameter
6 PSK identity or key mismatch The TLS handshake fails, the server drops the connection, logs complain about encryption
7 No permissions on the SQLite database directory The process runs as the zabbix user and can’t create the database file

The first cause beats everything else by a wide margin. I once spent half a day figuring out why a branch proxy wouldn’t register. Network was clean, ports were open, versions matched. Turned out the interface had “Zbx-Proxy-Kazan” and the config had “zbx-proxy-kazan”. One capital letter cost me six hours. Nice request you’ve got there, said the server, and quietly closed the socket.

Cause five is my favorite because admins create it themselves. They copy a config from an old 5.0 proxy onto a new 7.0 box, and that config has parameters that no longer exist or whose meaning has changed. The proxy reads the file, sees an unfamiliar word, and refuses to start.

Recipe: installing Zabbix proxy 7.0 step by step

System requirements

At the time of writing, the current branch is Zabbix 7.0 LTS for production and 7.4 as the stable release with full support until 8.0 ships. The 8.0 LTS branch is at release candidate stage: the first RC came out on October 1, 2026. Before installing, check the latest releases on the release notes page and support timelines in the Zabbix life cycle and release policy.

Component Recommended Also works Comment
Proxy OS Ubuntu 24.04 LTS Debian 12, RHEL/Alma/Rocky 9 Check the OS list for your version on the download page
Zabbix proxy 7.0 LTS, latest minor 7.4 Must strictly match the same major branch as the server
Zabbix server 7.0 LTS 7.4 Server is upgraded first, proxies second
Proxy database SQLite 3 PostgreSQL, MySQL/MariaDB SQLite is enough for most branch sites
CPU and memory 2 vCPU, 2 GB RAM 1 vCPU, 1 GB for small sites More is needed for thousands of items and SNMP polling
Disk 20 GB 10 GB The buffer grows while the server is unreachable

A note on Zabbix 6.4. The official documentation already lists the 6.4 branch as unsupported. If your server runs 6.4, install proxy 6.4 as well, otherwise it won’t come up. But to be honest: plan a move to 7.0 LTS, because security fixes for 6.4 are no longer released.

Port table

Port Protocol Direction Purpose Exposed externally?
10051 TCP Proxy to server Active proxy sends data and pulls configuration Only on the server, only from proxy addresses
10051 TCP Agents to proxy Active agent checks, zabbix_sender, traps Only from the branch local network
10051 TCP Server to proxy Passive proxy only Only from the server address
10050 TCP Proxy to agents Passive agent checks No, stays within the segment
161 UDP Proxy to devices SNMP polling No
162 UDP Devices to proxy SNMP traps, if configured No
22 TCP Admin to proxy SSH Only from admin addresses

Prep: check your environment before installing

Three minutes of checking saves an hour of troubleshooting. Start with hostname and time. Time matters: if the proxy clock drifts, data arrives at the server with skewed timestamps, and your graphs turn into abstract art.


# On proxy zbx-proxy-01: hostname, OS, and time sync
hostnamectl
timedatectl status
sudo apt update && sudo apt install -y chrony netcat-openbsd sqlite3 jq
sudo systemctl enable --now chrony
chronyc tracking | head -n 5

Expected result: timedatectl output shows System clock synchronized: yes, and chronyc tracking shows an offset in milliseconds, not minutes.

Now the network. From the proxy, check that the server’s port responds. If this comes up empty, there’s no point going further, fix the route or firewall first.


# On proxy zbx-proxy-01: is the server's port reachable
nc -zv 10.10.0.10 10051

Expected response: Connection to 10.10.0.10 10051 port [tcp/*] succeeded. If you see timed out, a firewall along the way is dropping packets. If Connection refused, you’re reaching the server, but nothing is listening there, or the server is rejecting the connection.

While you’re at it, check the server’s version. You can see it at the bottom of the web interface or with a single command on the server itself.


# On server zbx-server: Zabbix server version
zabbix_server -V | head -n 1

Note the major branch, for example 7.0. That’s exactly what you’ll install on the proxy.

Step 1. Add the Zabbix repository

Why: the distro’s default repositories either carry an outdated version or build it differently from the official one. The official repository gives you the latest minor versions and consistent file paths across all machines.

Ubuntu 24.04, 7.0 branch:


# On proxy zbx-proxy-01 (Ubuntu 24.04): Zabbix 7.0 repository
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

Debian 12:


# On proxy zbx-proxy-01 (Debian 12): Zabbix 7.0 repository
cd /tmp
wget https://repo.zabbix.com/zabbix/7.0/debian/pool/main/z/zabbix-release/zabbix-release_latest_7.0+debian12_all.deb
sudo dpkg -i zabbix-release_latest_7.0+debian12_all.deb
sudo apt update

RHEL 9 and compatible systems. There’s a gotcha here: if EPEL is enabled, it will offer its own zabbix packages and break the install. Exclude them before adding the official repository.


# On proxy zbx-proxy-01 (RHEL 9): exclude zabbix from EPEL, if EPEL is enabled
sudo sed -i '/^\[epel\]/a excludepkgs=zabbix*' /etc/yum.repos.d/epel.repo

# Same host: add the Zabbix 7.0 repository
sudo rpm -Uvh https://repo.zabbix.com/zabbix/7.0/rhel/9/x86_64/zabbix-release-latest-7.0.el9.noarch.rpm
sudo dnf clean all

Expected result: apt update or dnf makecache shows a line referencing repo.zabbix.com with no key warnings. If wget returns a 404, the filename has changed. Open the Zabbix download page, pick the version, OS, and Proxy component, and copy the current link from there.

For a 6.4 server, the logic is the same, just swap in the 6.4 branch and the distro it was built for in the URL. Example for Ubuntu 22.04, double-check the link on the download page before running:


# On proxy (Ubuntu 22.04), ONLY if the server runs 6.4: Zabbix 6.4 repository
cd /tmp
wget https://repo.zabbix.com/zabbix/6.4/ubuntu/pool/main/z/zabbix-release/zabbix-release_6.4-1+ubuntu22.04_all.deb
sudo dpkg -i zabbix-release_6.4-1+ubuntu22.04_all.deb
sudo apt update

Step 2. Install the proxy package

Why you choose a package based on the database: the proxy binary is built for a specific DBMS. The zabbix-proxy-sqlite3 package ships a binary with SQLite support, zabbix-proxy-pgsql with PostgreSQL, zabbix-proxy-mysql with MySQL. You can only switch databases later by swapping the package.

For a branch site with a hundred hosts, go with SQLite. Running a dedicated DBMS server just for a buffer is like buying a safe to store your bus fare.


# On proxy zbx-proxy-01 (Ubuntu/Debian): proxy with SQLite and fping for ICMP checks
sudo apt install -y zabbix-proxy-sqlite3 zabbix-sql-scripts fping

# On proxy zbx-proxy-01 (RHEL 9): the same, via dnf
sudo dnf install -y zabbix-proxy-sqlite3 zabbix-sql-scripts fping

Expected result: the package is installed, the file /etc/zabbix/zabbix_proxy.conf exists, and the zabbix-proxy service is present. Check the binary version.


# On proxy zbx-proxy-01: installed proxy version
zabbix_proxy -V | head -n 1
which fping

The first line should show the same branch as the server. Note the fping path: on Ubuntu and Debian it’s usually /usr/bin/fping, while the config default is /usr/sbin/fping. This path mismatch is a quiet reason why ICMP checks end up as “not supported”.

Step 3. Prepare the SQLite database directory

Why: the proxy runs as the zabbix user. If the database directory doesn’t exist or is owned by root, the proxy won’t be able to create the file and will fail to start.


# On proxy zbx-proxy-01: database directory with correct ownership
sudo install -d -o zabbix -g zabbix -m 750 /var/lib/zabbix
ls -ld /var/lib/zabbix

Expected result: drwxr-x— zabbix zabbix /var/lib/zabbix.

Modern proxy versions create the SQLite schema themselves on first start, if the database file doesn’t exist yet. If for some reason the file wasn’t created, build the database from the stock script. First check that the script is present.


# On proxy zbx-proxy-01: manual database creation, ONLY if the proxy didn't create it itself
ls /usr/share/zabbix-sql-scripts/sqlite3/
sudo -u zabbix sqlite3 /var/lib/zabbix/zabbix_proxy.db < /usr/share/zabbix-sql-scripts/sqlite3/proxy.sql

Step 4. Configure zabbix_proxy.conf

This is where everything gets decided. The stock config is 1000+ lines of comments and a couple dozen parameters. I prefer a minimal file where every line means something and it’s clear why it’s there. We don’t delete the original, we rename it: it’ll come in handy as a reference.


# On proxy zbx-proxy-01: save the stock config as a reference
sudo cp -a /etc/zabbix/zabbix_proxy.conf /etc/zabbix/zabbix_proxy.conf.orig

Now let’s write the working config. Replace the server address and proxy name with your own.


# On proxy zbx-proxy-01: write a working config for an active proxy 7.0
sudo tee /etc/zabbix/zabbix_proxy.conf > /dev/null <<'EOF'
############ MAIN ############
# 0 = active proxy, 1 = passive proxy
ProxyMode=0
# Zabbix server address. Default port is 10051, a non-standard port is set with a colon
Server=10.10.0.10
# Proxy name. MUST MATCH the name in the web interface, case-sensitive
Hostname=zbx-proxy-01
ListenPort=10051

############ LOGS AND SERVICE SETTINGS ############
LogFile=/var/log/zabbix/zabbix_proxy.log
LogFileSize=10
DebugLevel=3
PidFile=/run/zabbix/zabbix_proxy.pid
SocketDir=/run/zabbix

############ DATABASE ############
DBName=/var/lib/zabbix/zabbix_proxy.db

############ DATA BUFFER ############
# How many hours to keep data if the server is unreachable
ProxyOfflineBuffer=24
# Don't keep data locally after sending
ProxyLocalBuffer=0
# Hybrid buffer in 7.0: memory, falls back to disk when full
ProxyBufferMode=hybrid
ProxyMemoryBufferSize=16M

############ SYNCING WITH THE SERVER ############
# How often to request configuration, seconds
ProxyConfigFrequency=10
# How often to send data, seconds
DataSenderFrequency=1

############ COLLECTORS ############
StartPollers=5
StartPingers=1
StartTrappers=5
Timeout=4
FpingLocation=/usr/bin/fping

############ SECURITY ############
StatsAllowedIP=127.0.0.1
LogSlowQueries=3000
EOF

Let’s break down the less obvious lines.

Server. In active mode, this holds a single server address or an HA cluster. Cluster nodes are listed separated by semicolons. A non-standard port is written right in the value with a colon. The old ServerPort parameter is deprecated in 7.0, and the proxy will warn about it in the log.

Hostname. This isn’t the machine’s DNS name, it’s the proxy’s unique name within Zabbix. You can use the machine name, but then keep it identical in three places: the config, the web interface, and your own documentation.

ProxyBufferMode. New in 7.0. Options are disk, memory, hybrid. Disk writes everything to the database, like in 6.x. Memory keeps data in RAM and loses it on restart. Hybrid keeps data in memory and flushes to disk when full or when the server has been unreachable for a while. For a branch site, hybrid is the best compromise: less disk load, no data lost on a dropped link. With memory or hybrid, you must set ProxyMemoryBufferSize, otherwise the proxy won’t start.

ProxyConfigFrequency. Replaced the old ConfigFrequency in 6.4. If you’re porting a config from 6.0, find and rename it.

FpingLocation. Set this to the path returned by which fping in step 2.

Before starting, check the syntax. In 7.x the binary has a -T flag: it reads the config, validates the parameters, and exits without starting anything.


# On proxy zbx-proxy-01: validate the config without starting
sudo -u zabbix zabbix_proxy -T -c /etc/zabbix/zabbix_proxy.conf

Expected result: empty output or a success message, exit code 0. If you see an error about a parameter, fix it before starting. If the -T flag itself isn’t recognized and the binary complains invalid option, you have an older build without that flag. More on that in “Troubleshooting”.

Step 5. Create the proxy in the web interface

Why: the server doesn’t learn about a proxy on its own. Until there’s a matching entry in the interface, the server replies to every connection with “I don’t know this proxy”.

Open the web interface: Administration → Proxies → Create proxy. Fill in the fields:

Field Value Comment
Proxy name zbx-proxy-01 Must match the Hostname in the config letter for letter
Proxy mode Active Matches ProxyMode=0
Proxy address 192.168.50.20 or the external NAT address Optional. If set, the server will only accept this proxy from these addresses
Description Branch office Kazan, rack 2 You’ll thank yourself for this in a year

Leave the “Encryption” tab alone for now, we’ll set up PSK as a separate step once the link is working without it. That way it’s easier to isolate problems: connectivity first, encryption second.

I recommend filling in the “Proxy address” field. It’s a free layer of protection: even if someone learns the proxy name, they won’t be able to connect from a different address. Behind NAT, enter the address the proxy actually exits through, which you can see in the server log.

Step 6. Open the firewall and start the proxy

Why: branch agents will send active checks to the proxy on 10051. The port only needs to be open for your own network.


# On proxy zbx-proxy-01 (Ubuntu/Debian, UFW): SSH and 10051 only from the branch network
sudo ufw allow from 192.168.50.0/24 to any port 22 proto tcp
sudo ufw allow from 192.168.50.0/24 to any port 10051 proto tcp
sudo ufw enable
sudo ufw status numbered

# On proxy zbx-proxy-01 (RHEL 9, firewalld and SELinux)
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.50.0/24" port port="10051" protocol="tcp" accept'
sudo firewall-cmd --reload
sudo setsebool -P zabbix_can_network on

On the server, open 10051 for the address the proxy connects from. If the server has its own firewall, without this rule the proxy will never reach it.


# On server zbx-server (UFW): accept the proxy only from its address
sudo ufw allow from 192.168.50.20 to any port 10051 proto tcp

Now let’s start it and enable autostart.


# On proxy zbx-proxy-01: enable autostart and start
sudo systemctl enable --now zabbix-proxy
sudo systemctl status zabbix-proxy --no-pager

Expected result: status active running. If it says failed, check the journal right away, it’ll show you the exact line with the cause.


# On proxy zbx-proxy-01: last lines of the service journal and the proxy log
sudo journalctl -u zabbix-proxy -n 30 --no-pager
sudo tail -n 30 /var/log/zabbix/zabbix_proxy.log

Step 7. Move hosts onto the proxy

Why: the proxy doesn’t collect anything by itself. It needs hosts assigned to it. Open a host: Data collection → Hosts → the host you need, pick “Proxy” in the “Monitored by” field and point it to zbx-proxy-01. For bulk moves, check the boxes next to hosts and use “Mass update”.

Now the agents. The proxy handles passive checks on its own, but the agent needs to allow connections from the proxy. For active checks, the agent must send data to the proxy, not the server.


# /etc/zabbix/zabbix_agent2.conf on every branch agent
Server=192.168.50.20
ServerActive=192.168.50.20
Hostname=hostname-as-shown-in-interface

# On every branch agent: apply the changes
sudo systemctl restart zabbix-agent2

Don’t mix these up: the agent’s Server setting controls who’s allowed to poll it, ServerActive is where the agent sends its own data. Once a host is moved to a proxy, both should point to that proxy. Classic mistake: the host gets moved, but the agent is left pointing at the central server. The server rejects the active checks because the host now “belongs” to the proxy.

Step 8. Enable PSK encryption

Why: proxy-to-server traffic travels over the internet or through networks you don’t control. Without encryption, anyone along the path can see the configuration and monitoring data, which is basically a map of your infrastructure. PSK is simpler than certificates and more than enough for a proxy-server link.

Generate the key on the proxy:


# On proxy zbx-proxy-01: generate a PSK and lock down permissions
openssl rand -hex 32 | sudo tee /etc/zabbix/zabbix_proxy.psk > /dev/null
sudo chown zabbix:zabbix /etc/zabbix/zabbix_proxy.psk
sudo chmod 640 /etc/zabbix/zabbix_proxy.psk
sudo cat /etc/zabbix/zabbix_proxy.psk

Copy the resulting 64-character hex string, you’ll need it in the web interface. Add the TLS parameters to the config:


# On proxy zbx-proxy-01: add PSK encryption to the config
sudo tee -a /etc/zabbix/zabbix_proxy.conf > /dev/null <<'EOF'

############ ENCRYPTION ############
TLSConnect=psk
TLSAccept=psk
TLSPSKIdentity=PSK-zbx-proxy-01
TLSPSKFile=/etc/zabbix/zabbix_proxy.psk
EOF
sudo -u zabbix zabbix_proxy -T -c /etc/zabbix/zabbix_proxy.conf

TLSConnect controls how the proxy connects to the server. TLSAccept controls which incoming connections the proxy accepts from agents and zabbix_sender. If branch agents aren’t encrypted yet, set TLSAccept=unencrypted,psk, otherwise the proxy will start rejecting their active checks.

Now in the web interface: Administration → Proxies → zbx-proxy-01 → tab “Encryption”. For an active proxy, check “Connections from proxy: PSK”, enter the PSK identity and the key itself. The identity must match TLSPSKIdentity character for character.

Save in the interface first, and only then restart the proxy. The reverse order gives you a minute of log complaints, nothing serious, but why bother.


# On proxy zbx-proxy-01: apply encryption and check the log
sudo systemctl restart zabbix-proxy
sudo tail -f /var/log/zabbix/zabbix_proxy.log

Expected result: no TLS or PSK error lines in the log, just regular messages about receiving configuration. In the interface, a PSK icon shows up in the proxy’s “Encryption” column.

Step 9. Option for large sites: PostgreSQL instead of SQLite

SQLite hits a write bottleneck when the proxy collects thousands of values per second or when the server is unreachable for a long time and the buffer balloons to gigabytes. Rule of thumb: up to a few hundred values per second, SQLite handles it fine, past that, watch disk load and how long it takes to send data. If you hit that wall, move to PostgreSQL.


# On proxy zbx-proxy-01: proxy with PostgreSQL instead of SQLite
sudo apt install -y postgresql zabbix-proxy-pgsql zabbix-sql-scripts
sudo -u postgres createuser --pwprompt zabbix_proxy
sudo -u postgres createdb -O zabbix_proxy zabbix_proxy
psql "postgresql://zabbix_proxy@127.0.0.1/zabbix_proxy" -f /usr/share/zabbix-sql-scripts/postgresql/proxy.sql

A dedicated database user with rights only on its own database is non-negotiable. Don’t give the proxy postgres superuser access, even if “it’s faster that way”. In the proxy config, replace the database block:


# /etc/zabbix/zabbix_proxy.conf on proxy zbx-proxy-01, PostgreSQL variant
DBHost=127.0.0.1
DBName=zabbix_proxy
DBUser=zabbix_proxy
DBPassword=password_from_createuser_here

A plaintext password in the config is a compromise. Lock the file down with 640 permissions and root:zabbix ownership. If your company runs HashiCorp Vault or CyberArk, proxy 7.0 can fetch database credentials from there via Vault parameters, documented in the zabbix_proxy.conf parameter reference.


# On proxy zbx-proxy-01: lock down the config with the password in it
sudo chown root:zabbix /etc/zabbix/zabbix_proxy.conf
sudo chmod 640 /etc/zabbix/zabbix_proxy.conf

Step 10. Proxy groups in Zabbix 7.0: load balancing and high availability

Starting with 7.0, proxies can be grouped together. The server automatically distributes hosts between proxies in a group and, if one goes down, shifts its hosts onto the surviving ones. In the past, people used to build this out of keepalived and a shared IP.

Setup: Administration → Proxy groups → Create proxy group. Set “Minimum number of proxies” needed for the group to be considered healthy, and the “Failover delay”. Then, in each proxy’s card, assign it to the group and set the “Address for active agents”, the address agents will use to connect to it.

For hosts, in the “Monitored by” field, pick “Proxy group” instead of a specific proxy. For agents, list all proxies in the group in ServerActive, separated by semicolons: the agent will get instructions from any of them on which proxy to send data to.


# /etc/zabbix/zabbix_agent2.conf on an agent whose host is served by a proxy group
ServerActive=192.168.50.20;192.168.50.21
Server=192.168.50.20,192.168.50.21

Failover behavior details are covered in the proxy load balancing and high availability section. Without groups, a single proxy at a branch is a single point of failure. That’s fine for a couple hundred hosts, not fine for a critical site.

Setting up a passive proxy, if there’s no way around it

If security policy requires passive mode, there are three differences: ProxyMode=1, Server lists the addresses the server is allowed to connect from, and the server needs spare pollers for the proxy.


# /etc/zabbix/zabbix_proxy.conf on the proxy, passive mode
ProxyMode=1
# In passive mode this is ONLY a comma-separated list of addresses, no cluster ports
Server=10.10.0.10
Hostname=zbx-proxy-01

# /etc/zabbix/zabbix_server.conf on server zbx-server: polling passive proxies
StartProxyPollers=2
ProxyConfigFrequency=10
ProxyDataFrequency=1

In the web interface, set mode to “Passive” and add an interface with the proxy’s address and port. On the proxy, only open port 10051 for the server’s address. Here’s the key detail: in 7.0, validation of the Server value in passive mode got stricter. If you leave in the semicolon-separated cluster syntax used for active mode, the proxy won’t start and will plainly tell you that passive mode only allows a comma-separated list of addresses.

Verification: how to confirm Zabbix proxy is working correctly

“Service is running” doesn’t mean much on its own. A proxy can run for hours without ever getting a single host from the server. Check it layer by layer: process, network, server exchange, data.

Process and port


# On proxy zbx-proxy-01: is the service alive and listening on 10051
systemctl is-active zabbix-proxy
sudo ss -tlnp | grep 10051

Expect: active and a LISTEN line on 0.0.0.0:10051 with the zabbix_proxy process.

Exchange with the server, via the log


# On proxy zbx-proxy-01: look for signs of data exchange and errors
sudo grep -iE 'received configuration|cannot|error|failed' /var/log/zabbix/zabbix_proxy.log | tail -n 20

A good sign: lines about receiving configuration from the server, with a data size. A bad sign: any cannot connect, cannot send, or not found. We’ll break down each of these lines in “Troubleshooting”.

One detail worth noting: by default, an active proxy 7.0 requests configuration every 10 seconds, but the server only sends a full response when something changes. So lines showing large data volumes will be rare, and that’s expected.

Configuration made it to the database


# On proxy zbx-proxy-01: how many hosts and items the proxy received from the server
sudo -u zabbix sqlite3 /var/lib/zabbix/zabbix_proxy.db "select count(*) from hosts;"
sudo -u zabbix sqlite3 /var/lib/zabbix/zabbix_proxy.db "select count(*) from items;"

Numbers above zero mean configuration is coming through. Zero hosts, despite having hosts assigned in the interface, means the proxy either couldn’t reach the server or the server didn’t recognize it.

Don’t worry if the proxy_history table is nearly empty. In hybrid mode, data lives in memory and only hits disk when the buffer fills up or the connection drops for a long time. An empty history table while the connection is alive is actually the expected behavior.

View from the server side

In the web interface, Administration → Proxies, check three columns: “Last seen” should update every few seconds, “Version” should show a version with no warnings, “Number of hosts” should match what’s assigned.

Same thing via the API, handy for scripts and scheduled checks. Create a token in Users → API tokens.


# From any machine with access to the Zabbix web interface: status of all proxies via API
export ZBX_URL="https://zabbix.example.local/api_jsonrpc.php"
export ZBX_TOKEN="paste_api_token_here"
curl -s -X POST "$ZBX_URL" \
  -H 'Content-Type: application/json-rpc' \
  -H "Authorization: Bearer $ZBX_TOKEN" \
  -d '{"jsonrpc":"2.0","method":"proxy.get","params":{"output":["name","operating_mode","lastaccess","version","compatibility"]},"id":1}' \
  | jq '.result[] | {name, operating_mode, version, compatibility, lastaccess: (.lastaccess|tonumber|todate)}'
API field Meaning Normal value
operating_mode 0 active, 1 passive Matches ProxyMode
lastaccess Time of last contact Seconds ago, not minutes
version Proxy version Same branch as the server
compatibility 1 current, 2 outdated, 3 unsupported 1

Data is actually being collected

Last layer. Open Monitoring → Latest data, filter by a host behind the proxy. Values should update at their configured intervals. If everything is grey, check Administration → Queue: it shows how many items are delayed and on which proxy.

For deeper diagnostics, the proxy has a built-in command that writes cache and preprocessing state to the log:


# On proxy zbx-proxy-01: dump history cache and preprocessing diagnostics to the log
sudo zabbix_proxy -R diaginfo
sudo tail -n 40 /var/log/zabbix/zabbix_proxy.log
The proxy is working if
The service is active, port 10051 is listening, “Last seen” in the interface updates every few seconds, the proxy database has hosts and items, and branch hosts in “Latest data” are getting fresh values. If all five signs check out, go get some coffee.

Troubleshooting: Zabbix proxy errors and how to fix them

It’s not as bad as you think. It’s much worse: proxy errors love showing up in pairs. So first, the flow I follow for any “grey proxy” situation, then a breakdown of specific messages.

%%{init: {
  'theme': 'base',
  'themeVariables': {
    'primaryColor': '#ffffff',
    'primaryTextColor': '#1e293b',
    'primaryBorderColor': '#94a3b8',
    'lineColor': '#64748b',
    'fontSize': '15px',
    'fontFamily': 'ui-sans-serif, system-ui, sans-serif'
  },
  'flowchart': {'curve': 'linear', 'nodeSpacing': 50, 'rankSpacing': 50}
}}%%
flowchart TD
    A["Proxy shows grey in interface"] --> B{"Is the service running?"}
    B -->|no| C["Check config with -T flag"]
    B -->|yes| D{"Is server port reachable?"}
    D -->|no| E["Fix firewall or NAT"]
    D -->|yes| F{"Do names match?"}
    F -->|no| G["Fix Hostname"]
    F -->|yes| H{"Does PSK match?"}
    H -->|no| I["Check identity and key"]
    H -->|yes| J["Check proxy and server versions"]
    style A fill:#f8fafc,stroke:#f97316,stroke-width:2px,color:#9a3412
    style B fill:#f8fafc,stroke:#3b82f6,stroke-width:2px,color:#1e40af
    style D fill:#f8fafc,stroke:#3b82f6,stroke-width:2px,color:#1e40af
    style F fill:#f8fafc,stroke:#3b82f6,stroke-width:2px,color:#1e40af
    style H fill:#f8fafc,stroke:#3b82f6,stroke-width:2px,color:#1e40af
    style C fill:#f8fafc,stroke:#22c55e,stroke-width:2px,color:#15803d
    style E fill:#f8fafc,stroke:#22c55e,stroke-width:2px,color:#15803d
    style G fill:#f8fafc,stroke:#22c55e,stroke-width:2px,color:#15803d
    style I fill:#f8fafc,stroke:#22c55e,stroke-width:2px,color:#15803d
    style J fill:#f8fafc,stroke:#22c55e,stroke-width:2px,color:#15803d
Symptom in log or interface Cause Fix
invalid option — ‘X’ at zabbix_proxy startup A command-line flag this version doesn’t recognize Compare flags against zabbix_proxy -h
Proxy won’t start, log mentions an unknown or invalid parameter An outdated parameter or a typo in the config Compare the config against the stock file for your version
proxy “name” not found in the server log No proxy with that name exists in the interface Align Hostname and the proxy name
cannot connect to [[address]:10051] Port is closed, route is broken, server isn’t listening Check with nc, firewall on both sides, NAT
TLS and PSK errors in the log Identity, key, or connection type mismatch Check the “Encryption” tab and TLS parameters
Proxy version shown as outdated in the interface Proxy’s major branch is older than the server’s Upgrade the proxy to match the server’s branch
cannot open or unable to open database file No permissions on the SQLite directory or file Set zabbix ownership on the database directory

zabbix proxy 7 invalid option: what it is and how to fix it

This message is scary because it looks like Zabbix itself is broken. In reality, three different problems hide behind this search phrase. Let’s go through each one.

Variant 1. Invalid command-line flag

A message like invalid option — ‘x’ isn’t coming from Zabbix, it’s from the standard argument parser. It’s saying: “you passed a flag this binary doesn’t have”. Typical causes: an old script or systemd unit calling the proxy with a flag from another version, a case typo like -r instead of -R, or running -T on an old build that doesn’t support it yet.

How to find the culprit
Check what arguments the proxy actually gets started with. Most often the flag is hiding in a systemd unit override someone made years ago and forgot about. Compare it against the current version’s list of flags.

# On proxy zbx-proxy-01: which flags the installed version understands
zabbix_proxy -h

# Same host: how the service starts the proxy, including overrides
systemctl cat zabbix-proxy
ls /etc/systemd/system/zabbix-proxy.service.d/ 2>/dev/null

If the ExecStart or drop-in file has a flag that isn’t in the zabbix_proxy -h output, remove it. In 7.x, the supported flags are -c, -f, -R, -T, -h, and -V. Everything else triggers an error.


# On proxy zbx-proxy-01: after fixing the unit, reload systemd and restart
sudo systemctl daemon-reload
sudo systemctl restart zabbix-proxy

Variant 2. Invalid runtime control option

The -R flag accepts a strictly defined set of commands: config_cache_reload, diaginfo, snmp_cache_reload, housekeeper_execute, log_level_increase, log_level_decrease, and a few more. A typo in the name, say config_reload instead of config_cache_reload, triggers a failure with a message about an invalid runtime control option.


# On proxy zbx-proxy-01: correct runtime control commands
sudo zabbix_proxy -R config_cache_reload
sudo zabbix_proxy -R log_level_increase=poller
sudo zabbix_proxy -R log_level_decrease=poller

Check the full list for your version in the zabbix_proxy -h output or the section on the proxy process in the documentation.

Variant 3. Unknown or invalid parameter in the config

The most common case after an upgrade. Zabbix proxy will flatly refuse to start if the config has a line that isn’t in the parameter=value format, or a parameter this version doesn’t recognize. That’s by design, going back to version 1.8: better to fail at startup than silently run in a way you don’t expect.

Where unknown parameters come from. A config copied from a proxy running a different version. During an upgrade, the package manager kept your old file and dropped the new one next to it as .dpkg-dist or .rpmnew. Someone pasted a server parameter into the proxy config: for example, StartAlerters or report web service parameters don’t belong in a proxy config.

Warning: don't delete lines blindly
Make a copy of the config before editing. Some old parameters weren’t removed, just renamed, and their value needs to be moved under the new name. For instance, ConfigFrequency was replaced by ProxyConfigFrequency. If you just delete the line, the proxy falls back to a default that might not suit your link.

# On proxy zbx-proxy-01: copy the config before editing
sudo cp -a /etc/zabbix/zabbix_proxy.conf /etc/zabbix/zabbix_proxy.conf.bak.$(date +%F)

Next, find every parameter missing from the stock config for the current version. If the package manager left a new file next to it, use that. If not, pull the stock config straight out of the package without reinstalling it.


# On proxy zbx-proxy-01 (Ubuntu/Debian): extract the stock config for the current version from the package
cd /tmp
apt-get download zabbix-proxy-sqlite3
dpkg-deb --fsys-tarfile zabbix-proxy-sqlite3_*.deb | tar -xO ./etc/zabbix/zabbix_proxy.conf > /tmp/zabbix_proxy.conf.default

# Same host: list of parameters this version recognizes
grep -oP '^### Option: \K\S+' /tmp/zabbix_proxy.conf.default | sort -u > /tmp/known.txt

# Same host: parameters actually set in your working config
grep -oP '^\s*\K[A-Za-z0-9]+(?==)' /etc/zabbix/zabbix_proxy.conf | sort -u > /tmp/used.txt

# Same host: parameters this version doesn't recognize
comm -13 /tmp/known.txt /tmp/used.txt

This last command prints exactly the parameters causing the proxy to refuse to start. Empty output means there are no unknown parameters and the problem is with values instead. On RHEL, the new stock file is usually sitting next to it as zabbix_proxy.conf.rpmnew, use that instead of /tmp/zabbix_proxy.conf.default.

If there are no unknown parameters and the proxy still won’t start, look at the values. The most common traps in 7.0 are listed below.

Parameter Error Correct way
ProxyBufferMode=memory or hybrid ProxyMemoryBufferSize is not set Add ProxyMemoryBufferSize, for example 16M
ProxyMemoryBufferAge Value exceeds what’s allowed relative to ProxyOfflineBuffer, proxy reports wrong value Remove the parameter or lower the value
Server in passive mode Cluster syntax with semicolons Only comma-separated addresses
ServerPort Deprecated, logs a warning Set the port in Server with a colon
ConfigFrequency Deprecated name ProxyConfigFrequency
Hostname Spaces or non-Latin characters in the name Latin letters, digits, dot, hyphen, underscore
Any parameter Spaces around the equals sign or quotes in the value Parameter=value, no quotes

# On proxy zbx-proxy-01: after fixing, validate and start
sudo -u zabbix zabbix_proxy -T -c /etc/zabbix/zabbix_proxy.conf && sudo systemctl restart zabbix-proxy
sudo journalctl -u zabbix-proxy -n 20 --no-pager

“proxy not found” error in the server log

Cause: the server got a connection from a proxy, but there’s no proxy with that name in the interface. Almost always a mismatch between Hostname and the name in the interface. Less often, the proxy exists but is set to “Passive” mode.


# On server zbx-server: what name the proxy is sending
sudo grep -i 'not found' /var/log/zabbix/zabbix_server.log | tail -n 5

# On proxy zbx-proxy-01: what name is set in the config
grep -E '^Hostname=' /etc/zabbix/zabbix_proxy.conf

Compare the name from the server log with the one under Administration → Proxies. Fix it in one of the two places so they match exactly. If you edited the config, restart the proxy. If you edited the interface, no restart is needed, the next proxy request will go through.

“cannot connect to [[address]:10051]” error

Cause: the proxy can’t establish a TCP connection to the server. Connection refused means the port is closed on the other end or the server isn’t listening. Timed out means packets are getting dropped along the way, usually by a firewall.


# On proxy zbx-proxy-01: do packets reach the server
nc -zv 10.10.0.10 10051
tracepath -n 10.10.0.10

# On server zbx-server: is the server listening on 10051, and what does the firewall say
sudo ss -tlnp | grep 10051
sudo ufw status | grep 10051

If the server has a rule limiting access to a specific source address, make sure it’s the address the proxy actually exits through. For a proxy behind NAT, that’s the branch router’s external address, not 192.168.50.20. You can spot it using tcpdump on the server.


# On server zbx-server: which address connection attempts to 10051 are coming from
sudo tcpdump -ni any tcp port 10051 and 'tcp[tcpflags] & tcp-syn != 0' -c 10

PSK encryption errors

Cause: the server and proxy failed to agree on TLS. Possible reasons: PSK is enabled in the interface but not in the proxy config, or the other way around. The identity differs by one character. The key was copied with a stray space or line break. The key is shorter than 32 bytes.

Security
Don’t disable encryption on the server “just to get it working” and then forget to turn it back on. A temporary TLS disable that lives for three years is a classic audit finding. If you need to test connectivity without encryption, do it on a test proxy, not production.

# On proxy zbx-proxy-01: check TLS parameters and the key
grep -E '^TLS' /etc/zabbix/zabbix_proxy.conf
sudo wc -c /etc/zabbix/zabbix_proxy.psk
sudo cat /etc/zabbix/zabbix_proxy.psk

# On server zbx-server: TLS errors related to this proxy
sudo grep -iE 'tls|psk' /var/log/zabbix/zabbix_server.log | tail -n 10

A key file of 64 characters plus a trailing newline gives 65 bytes in wc -c, that’s normal. Compare the identity in the config and the interface character by character, better yet, copy it from one place straight into the other. Restart the proxy after fixing it.

Proxy version is outdated

Cause: the server got upgraded, the proxy got forgotten. A 7.0 server accepts data from a proxy on the previous major branch in a degraded mode: data collection and remote commands keep working, but proxy configuration no longer updates, and the interface shows a warning about an outdated version. Anything older than that isn’t supported at all. There’s a compatibility table in the Version compatibility section of the documentation.


# On server zbx-server and proxy zbx-proxy-01: compare versions
zabbix_server -V | head -n 1
zabbix_proxy -V | head -n 1

Fix: upgrade the proxy to match the server’s branch, following the instructions in the “Upgrading” section below.

No permissions on the SQLite database

Cause: the database directory is owned by root, or the database file was created manually as root. The proxy, running as the zabbix user, can’t write to it.


# On proxy zbx-proxy-01: restore permissions on the database directory and file
sudo chown -R zabbix:zabbix /var/lib/zabbix
sudo chmod 750 /var/lib/zabbix
sudo systemctl restart zabbix-proxy

Growing queue, delayed data

Cause: not enough collectors. The proxy is running, but it physically can’t poll all its items within the interval. Symptom: delays for this proxy grow under Administration → Queue, and the proxy health template shows poller utilization sitting above 75%.


# On proxy zbx-proxy-01: temporarily raise poller log verbosity for troubleshooting
sudo zabbix_proxy -R log_level_increase=poller
sudo tail -f /var/log/zabbix/zabbix_proxy.log

Increase the relevant collector type gradually: StartPollers for agents and SNMP, StartPingers for ICMP, StartHTTPPollers for web checks. Every increase costs memory and connections. Don’t set StartPollers=200 “just in case”. A proxy with a hundred idle pollers is like a cargo truck delivering a single letter.

Don’t forget to lower the log level back afterward, otherwise the log will balloon within a couple hours:


# On proxy zbx-proxy-01: restore normal poller log level
sudo zabbix_proxy -R log_level_decrease=poller

Proxy clock has drifted

Cause: time sync isn’t running on the proxy. Data arrives with timestamps from the future or the past, nodata-based triggers fire falsely, graphs look jagged.


# On proxy zbx-proxy-01 and server zbx-server: compare time and sync status
date -u
timedatectl show -p NTPSynchronized

If NTPSynchronized=no, enable chrony from the prep step and check that UDP 123 to the NTP server isn’t being blocked.

Alternatives to Zabbix proxy: when you don’t need one

A proxy isn’t a mandatory component. Sometimes it gets installed out of habit in places where it only adds a point of failure. Here are the options and my criteria for picking one.

Option When it fits Downsides
Agents connecting straight to the server over VPN A few dozen hosts, a stable VPN, no SNMP If the VPN drops, data is lost, no local buffering on site
Active proxy from packages Branches, DMZ, cloud, most cases A separate machine to maintain
Proxy in Docker A Docker host already exists on site, fast setup needed One more layer to troubleshoot, container networking for SNMP traps
Proxy group in 7.0 Critical site, hundreds of hosts At least two machines, configuring agents for multiple proxies

A proxy in Docker spins up with one command. Official images live on Docker Hub zabbix/zabbix-proxy-sqlite3, pick the tag matching your server’s branch.


# On the branch's Docker host: proxy 7.0 on SQLite in a container
docker run -d --name zabbix-proxy \
  --restart unless-stopped \
  -p 10051:10051 \
  -e ZBX_HOSTNAME=zbx-proxy-01 \
  -e ZBX_SERVER_HOST=10.10.0.10 \
  -e ZBX_PROXYMODE=0 \
  -v zbx-proxy-data:/var/lib/zabbix \
  zabbix/zabbix-proxy-sqlite3:alpine-7.0-latest

docker logs -f zabbix-proxy

Why the main recipe uses packages instead of Docker. A proxy is infrastructure, it should come up first and go down last. A package running under systemd is easier to debug at 3 a.m.: one process, one log, no network bridges to think about. Docker is a good fit when the site already has a well-maintained Docker host and a team that understands it.

I go with agents over VPN for small sites, 10-20 machines, with no network equipment. As soon as SNMP, switches, and printers show up, it’s simpler to add a proxy: SNMP traffic over VPN for a hundred devices means both extra load and timeouts.

Prevention: monitoring, backups, security, and upgrading the proxy

A proxy nobody monitors will quietly die someday. And you won’t hear about it from Zabbix, you’ll hear about it from the branch office accountant whose printer went down with no alert. Monitoring your monitoring isn’t paranoia, it’s basic hygiene.

Monitoring the proxy itself

There are two layers here. The proxy’s internal health: poller load, caches, buffer. And the server’s outside view: when the proxy last checked in.

For internal health, create a host in the interface, say zbx-proxy-01-health, assign it to be monitored through this same proxy, and attach the “Zabbix proxy health” template. The template collects internal proxy process metrics: load for each collector type, cache fill level, queue size.

For the outside view, use a server-side internal item for the proxy’s last contact time. Add it to the server’s own host and attach a trigger.


Item on the Zabbix server host
Type: Zabbix internal
Key: zabbix[proxy,zbx-proxy-01,lastaccess]
Interval: 1m

Trigger
Name: Proxy zbx-proxy-01 has not checked in for over 5 minutes
Expression: now()-last(/Zabbix server/zabbix[proxy,zbx-proxy-01,lastaccess])>300
Severity: High

Plus an agent on the proxy machine itself with a basic Linux template: disk space and memory. The SQLite buffer can easily eat up gigabytes during a long outage, and the proxy will crash from running out of disk space exactly when you need it most.

Backups

Good news: the proxy is almost stateless. It gets host configuration from the server, so you don’t have to back up the proxy database. It’s a buffer, not a store. Bad news: anything you set up by hand only exists on this one machine.

What to back up Path How often Why
Proxy config /etc/zabbix/zabbix_proxy.conf On every change, and daily The main file, without it there’s no proxy
PSK key /etc/zabbix/zabbix_proxy.psk On change Without it you’ll need to reissue the key and update the interface
External scripts /usr/lib/zabbix/externalscripts Daily Custom checks nobody else remembers writing
Systemd overrides /etc/systemd/system/zabbix-proxy.service.d On change Startup limits and parameters

A backup script packs everything into an archive and ships it to your monitoring server or any other storage off-site. A backup sitting on the same machine isn’t a backup, it’s a copy for peace of mind that won’t actually help you.


# On proxy zbx-proxy-01: daily config backup script
sudo tee /usr/local/sbin/zbx-proxy-backup.sh > /dev/null <<'EOF'
#!/bin/bash
set -euo pipefail
BACKUP_DIR=/var/backups/zabbix-proxy
STAMP=$(date +%F)
mkdir -p "$BACKUP_DIR"
tar -czf "$BACKUP_DIR/zbx-proxy-$(hostname -s)-$STAMP.tar.gz" \
  /etc/zabbix/zabbix_proxy.conf \
  /etc/zabbix/zabbix_proxy.psk \
  /usr/lib/zabbix/externalscripts \
  /etc/systemd/system/zabbix-proxy.service.d 2>/dev/null || true
find "$BACKUP_DIR" -name 'zbx-proxy-*.tar.gz' -mtime +30 -delete
EOF
sudo chmod 750 /usr/local/sbin/zbx-proxy-backup.sh
sudo /usr/local/sbin/zbx-proxy-backup.sh
ls -lh /var/backups/zabbix-proxy/

# On proxy zbx-proxy-01: run backup daily at 02:30 via cron
echo '30 2 * * * root /usr/local/sbin/zbx-proxy-backup.sh' | sudo tee /etc/cron.d/zbx-proxy-backup

Pull the off-site copy from the central side, so the proxy doesn’t have to hold credentials for accessing the storage:


# On the backup server or zbx-server: pull archives from the proxy
rsync -az backup@192.168.50.20:/var/backups/zabbix-proxy/ /srv/backups/zbx-proxy-01/

Restoring takes about ten minutes. On a new machine, install the same version’s package following steps 1-3, unpack the archive on top, check the config, and start it up. The name and PSK stay the same, so the server recognizes the proxy and sends it host configuration on its own.


# On the new proxy machine: restore configuration from the archive and start
sudo tar -xzf zbx-proxy-zbx-proxy-01-2026-10-20.tar.gz -C /
sudo chown zabbix:zabbix /etc/zabbix/zabbix_proxy.psk
sudo -u zabbix zabbix_proxy -T -c /etc/zabbix/zabbix_proxy.conf
sudo systemctl enable --now zabbix-proxy

Autostart and auto-restart

systemctl enable from step 6 already turned on autostart. Let’s add one more safety net: if the proxy crashes, systemd will bring it back up after 10 seconds. Do this through a drop-in, don’t touch the package’s stock unit, or the next upgrade will overwrite your changes.


# On proxy zbx-proxy-01: auto-restart on crash via a drop-in
sudo mkdir -p /etc/systemd/system/zabbix-proxy.service.d
sudo tee /etc/systemd/system/zabbix-proxy.service.d/restart.conf > /dev/null <<'EOF'
[Service]
Restart=on-failure
RestartSec=10s
EOF
sudo systemctl daemon-reload
systemctl show zabbix-proxy -p Restart -p RestartUSec

Keep in mind: if the proxy is crashing because of a config error, restarting won’t help, it’ll just keep crashing every 10 seconds. That’s why the lastaccess trigger from the monitoring section is essential.

Proxy security

The proxy knows what and how things are monitored in your network, and often sits right at a segment boundary. That makes it an attractive target. Minimum protection checklist:

  • UFW or firewalld with rules scoped to the necessary addresses only: step 6.
  • PSK encryption between proxy and server: step 8.
  • The “Proxy address” field in the interface, so the server only accepts the proxy from a known address.
  • A dedicated database user with rights limited to its own database, if you’re using PostgreSQL or MySQL.
  • fail2ban for SSH.
  • Password login and root SSH login disabled.
  • 640 permissions on the config and the PSK key.

fail2ban and SSH hardening take five minutes to set up. fail2ban scans the journal for failed login attempts and bans the sources on its own.


# On proxy zbx-proxy-01: fail2ban protecting SSH
sudo apt install -y fail2ban
sudo tee /etc/fail2ban/jail.d/sshd.local > /dev/null <<'EOF'
[sshd]
enabled = true
backend = systemd
maxretry = 5
findtime = 10m
bantime = 1h
EOF
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd
Don't lock yourself out
Before disabling password login, make sure key-based login actually works. Keep a second SSH session open until you’ve confirmed a fresh login from a third one. A remote proxy at a branch office with no console access means a road trip or a phone call to the local IT guy, dictating commands over the line.

# On proxy zbx-proxy-01: SSH hardening via a separate file
sudo tee /etc/ssh/sshd_config.d/10-hardening.conf > /dev/null <<'EOF'
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
MaxAuthTries 3
EOF
sudo sshd -t && sudo systemctl reload ssh

On RHEL the service is called sshd, not ssh, adjust the last command accordingly.

Upgrading Zabbix proxy without surprises

The main rule for order of operations: server first, proxy second. A server on a newer branch can work with a proxy on the previous branch in a degraded mode, the reverse doesn’t work. That means after upgrading the server, you have time to upgrade proxies one at a time, without a rush job.

Before upgrading, check three things. Read the upgrade notes for the target version, they list removed and renamed parameters. Back up the config. Make sure the connection to the server is stable, otherwise the buffer won’t have time to flush.

Minor upgrade, say 7.0.20 to 7.0.25, is safe and done with a single command. The proxy database schema is compatible within a branch.


# On proxy zbx-proxy-01: minor upgrade within the same branch
sudo /usr/local/sbin/zbx-proxy-backup.sh
sudo apt update
sudo apt install --only-upgrade zabbix-proxy-sqlite3
zabbix_proxy -V | head -n 1
sudo systemctl status zabbix-proxy --no-pager

Major upgrade, say 6.4 to 7.0, requires switching repositories. For SQLite, the cleanest path is to delete the old database file: the proxy will create a new schema and pull configuration from the server. You’ll only lose whatever was sitting in the buffer and hadn’t been sent yet, so wait for the sending queue to empty before stopping the service.


# On proxy zbx-proxy-01: major upgrade from 6.4 to 7.0, Ubuntu 22.04
sudo /usr/local/sbin/zbx-proxy-backup.sh
sudo systemctl stop zabbix-proxy
cd /tmp
wget https://repo.zabbix.com/zabbix/7.0/ubuntu/pool/main/z/zabbix-release/zabbix-release_latest_7.0+ubuntu22.04_all.deb
sudo dpkg -i zabbix-release_latest_7.0+ubuntu22.04_all.deb
sudo apt update
sudo apt install -y zabbix-proxy-sqlite3
sudo mv /var/lib/zabbix/zabbix_proxy.db /var/lib/zabbix/zabbix_proxy.db.old-6.4
ls /etc/zabbix/ | grep -E 'dpkg-dist|dpkg-old'
sudo -u zabbix zabbix_proxy -T -c /etc/zabbix/zabbix_proxy.conf
sudo systemctl start zabbix-proxy

If ls shows a zabbix_proxy.conf.dpkg-dist file, that’s the new stock config. Run it through the unknown-parameters check from the invalid option section before starting. For a proxy running PostgreSQL or MySQL, don’t delete the database: the proxy will update the schema on startup by itself, but a database backup beforehand is still mandatory.

Rollback. Rolling back a minor version is straightforward: install a specific package version and restore the config. apt-cache shows the available versions.


# On proxy zbx-proxy-01: roll back to the previous minor version
apt-cache policy zabbix-proxy-sqlite3
sudo apt install --allow-downgrades zabbix-proxy-sqlite3=VERSION_FROM_LIST
sudo apt-mark hold zabbix-proxy-sqlite3
sudo systemctl restart zabbix-proxy

Rolling back a proxy’s major version only makes sense together with rolling back the server, which is why you should always upgrade the server with a VM snapshot and a database backup ready. Don’t forget to remove the apt-mark hold once the issue is resolved: sudo apt-mark unhold zabbix-proxy-sqlite3. Otherwise, a year from now, you’ll find a proxy stuck on a version with a known vulnerability. Born in legacy, it fears no refactoring, but it still wouldn’t mind being updated.

FAQ: frequently asked questions about Zabbix proxy

Why doesn’t Zabbix proxy work after setup?

Nine times out of ten, three things are to blame: the Hostname in the config doesn’t match the proxy name in the interface, the mode in the config doesn’t match the mode in the interface, or port 10051 is closed. Check the proxy log and the server log: you’ll see either cannot connect or not found. Work through the troubleshooting flowchart from top to bottom.

How do I confirm Zabbix proxy is working correctly?

Look at four signs. The service is active and listening on 10051. “Last seen” in the interface updates every few seconds. The proxy database has hosts and items. Hosts behind the proxy show fresh values in “Latest data”. For automated checks, use a proxy.get API call with the lastaccess and compatibility fields.

What should I do if zabbix proxy 7 reports invalid option?

Figure out where the error is coming from. If it shows up when the binary starts, the service is passing a flag this version doesn’t recognize: compare systemctl cat zabbix-proxy against the zabbix_proxy -h output. If the proxy fails to start because of a config parameter, find the unknown parameters by comparing against the stock config and validate the file with the -T flag. Commands for both cases are in the “Troubleshooting” section.

What’s the difference between an active and a passive proxy?

The direction of the connection. An active proxy connects to the server itself, pulls configuration, and pushes data, so it works behind NAT without any port forwarding. A passive proxy waits for the server to connect, needs an inbound port, and needs StartProxyPollers set on the server. Choose active by default, passive only when required by security policy.

Can I use a 6.4 proxy with a 7.0 server?

Temporarily and with limitations. A 7.0 server works with a proxy from the previous branch in an “outdated version” mode: data collection and remote commands keep working, but configuration changes don’t reach the proxy. It’s a mode meant for smooth upgrades, not for permanent use. Upgrade the proxy to 7.0 during your next maintenance window.

Which database should I pick for Zabbix proxy: SQLite or PostgreSQL?

SQLite for most branch sites: zero administration, a single file, the proxy creates the schema itself. PostgreSQL or MySQL become necessary when the proxy processes thousands of values per second, or the buffer balloons to gigabytes during outages. Start with SQLite and switch once the proxy health metrics show you’re bottlenecked on disk.

Do I need to back up the Zabbix proxy database?

Usually not. The proxy database is a buffer and a copy of configuration the server will resend anyway. Back up the config, the PSK key, external scripts, and systemd overrides. That’s enough to bring up a proxy on a new machine in ten minutes.

How many hosts can one Zabbix proxy handle?

It depends not on the number of hosts but on values per second and the types of checks involved. A proxy with 2 vCPUs and SQLite comfortably handles hundreds of hosts with typical templates. Watch the “Zabbix proxy health” template: if poller load consistently sits above 75%, add more collectors; if you’re bottlenecked on CPU or disk, add a second proxy and group them together.

Outcome: what works now

We set up an active Zabbix proxy 7.0 with a minimal config where every line has a clear purpose. The connection to the server runs over a single outbound port and is encrypted with PSK. Branch hosts get polled locally, data buffers in hybrid mode, and nothing gets lost when the link drops. The invalid option and unknown parameter errors can now be tracked down in three commands instead of trial and error.

From here, the proxy mostly takes care of itself: systemd brings it back up if it crashes, a lastaccess trigger will tell you if it drops off the grid, config backups ship off-site every night, and the upgrade path is already planned. The next logical step for critical sites is a second proxy and a 7.0 proxy group, so the branch survives the loss of one machine without needing you at 3 a.m.

Still not working?
If the proxy is still grey or won’t start, leave a comment and we’ll figure it out. Include the server and proxy versions, the proxy mode, and the last 20 lines of both the proxy and server logs. Those four things cover the cause nine times out of ten.

Оставайтесь на связи

Рецепты от IT-боли. Без воды, без рекламы, без маркетинговой шелухи.

Подписаться на IT-Аптеку →
Поделитесь:

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top