Zabbix 7.0 is the long-term support line, and it is the one to run on a monitoring server you expect to keep for years. This guide installs it on Ubuntu with MariaDB and Apache, puts the frontend behind HTTPS, and connects a second server through Zabbix agent 2 so you finish with real graphs, not an empty dashboard.
The same commands install Zabbix on Ubuntu 26.04 and Ubuntu 24.04. The one place they differ is Apache: the 26.04 packages serve the frontend through PHP-FPM and refuse to start until you enable one module, which is covered where it bites. If you prefer PostgreSQL and Nginx, the PostgreSQL and Nginx variant follows the same flow. Every command below was run on Ubuntu 26.04.1 and 24.04.5 with Zabbix 7.0.31, MariaDB 11.8 and 10.11, and I went back over the guide in November 2026 once Zabbix 8.0 LTS was out.
How the pieces fit together
One server, zbx01, runs the Zabbix server daemon, the PHP frontend behind Apache, and MariaDB. A second host, web01, runs only Zabbix agent 2. The server polls the agent on TCP 10050, the agent pushes active checks to the server on TCP 10051, and you reach the frontend over HTTPS.

MariaDB listens on 127.0.0.1 only. It is never exposed, and nothing outside the box talks to the database, so the firewall opens SSH, 80, 443 and 10051 and nothing else.
Prerequisites and sizing
Zabbix sizing is driven by the number of monitored metrics and how long you keep history, not by the host count. A metric is roughly one item plus its trigger and graph. The database does most of the work, so RAM for the InnoDB buffer pool and fast disk matter more than CPU. Zabbix publishes these starting points:
| Installation size | Monitored metrics | vCPU | RAM |
|---|---|---|---|
| Small | 1,000 | 2 | 8 GB |
| Medium | 10,000 | 4 | 16 GB |
| Large | 100,000 | 16 | 64 GB |
| Very large | 1,000,000 | 32 | 96 GB |
Source: the Zabbix 7.0 requirements page. Disk is history plus trends plus headroom. Our lab server held two hosts and about 200 items, and a full database dump was 4.1 MB after its first half hour. Plan for gigabytes once you add real hosts and keep 90 days of history.
The lab ran on 2 vCPU, 4 GB RAM and a 30 GB disk. That is a floor for following along, not a production recommendation. You also need:
- A fresh Ubuntu 26.04 or 24.04 server with sudo access.
- A DNS A record such as
zabbix.example.compointing at the server, with port 80 reachable for the Let’s Encrypt HTTP-01 check. Any DNS provider works. - Optionally a second Ubuntu host to monitor. The agent section covers it on its own.
Set the variables
Three values repeat through the install. Export them once on the Zabbix server and the rest of the commands paste as they are:
export ZBX_DB_PASS='Change-Me-Zbx-2026'
export ZBX_DOMAIN='zabbix.example.com'
export ADMIN_EMAIL='[email protected]'
Pick a real database password, but avoid /, &, \ and quotes: it goes into a sed expression and an SQL string below. The exports do not survive a logout: they live only in the current shell, so run them again if you reconnect or switch to a new session.
Install MariaDB
The Ubuntu archive version is fine, and the MariaDB on Ubuntu 26.04 guide covers tuning if you need it later. Zabbix 7.0 supports MariaDB 10.5 through 12.3, which covers 11.8 on 26.04 and 10.11 on 24.04.
sudo apt update
sudo apt install -y mariadb-server
Confirm the service is up and note the version:
systemctl is-active mariadb
mariadb --version
On Ubuntu 26.04 the server reports MariaDB 11.8:
active
mariadb from 11.8.6-MariaDB, client 15.2 for debian-linux-gnu (x86_64) using EditLine wrapper
On Ubuntu 24.04 you’ll see MariaDB 10.11 here instead, and everything that follows is the same on both releases.
Add the Zabbix 7.0 repository
Zabbix publishes a release package per Ubuntu version. Reading VERSION_ID from /etc/os-release picks the right one, so the same lines work on 26.04 and 24.04:
. /etc/os-release
wget "https://repo.zabbix.com/zabbix/7.0/ubuntu/pool/main/z/zabbix-release/zabbix-release_latest_7.0+ubuntu${VERSION_ID}_all.deb"
sudo dpkg -i "zabbix-release_latest_7.0+ubuntu${VERSION_ID}_all.deb"
sudo apt update
The latest_7.0 package tracks the 7.0 LTS line. apt upgrade moves you through 7.0 point releases, and it will not jump to 8.0 on its own.
Install the Zabbix server, frontend and agent 2
One line pulls in the server built for MySQL/MariaDB, the PHP frontend, its Apache config, the SQL schema and the local agent:
sudo apt install -y zabbix-server-mysql zabbix-frontend-php zabbix-apache-conf zabbix-sql-scripts zabbix-agent2
Apache and PHP come in as dependencies. On 26.04 that means PHP 8.5 with PHP-FPM. On 24.04 it is PHP 8.3 through libapache2-mod-php. Check which build apt installed:
apt-cache policy zabbix-server-mysql | head -3
The installed and candidate versions match, and the suffix names your Ubuntu release:
zabbix-server-mysql:
Installed: 1:7.0.31-1+ubuntu26.04
Candidate: 1:7.0.31-1+ubuntu26.04
With the packages in place, the server still has nowhere to write, so the database comes next.
Create the database and import the schema
Zabbix needs a utf8mb4_bin database. The schema import also creates triggers and functions, which MariaDB blocks for non-SUPER users while binary logging is possible, so log_bin_trust_function_creators is switched on for the import and back off afterwards:
sudo mariadb -e "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;"
Import the schema and initial data. It took 37 seconds on the 26.04 VM and 16 on 24.04, with no output when it succeeds:
zcat /usr/share/zabbix-sql-scripts/mysql/server.sql.gz | mariadb --default-character-set=utf8mb4 -uzabbix -p"${ZBX_DB_PASS}" zabbix
Turn the setting back off:
sudo mariadb -e "SET GLOBAL log_bin_trust_function_creators = 0;"
You now have the schema loaded and MariaDB back on its default trust setting.
Point the server at the database
DBName and DBUser already default to zabbix. Only the password is missing, and it ships commented out:
sudo sed -i "s/^# DBPassword=.*/DBPassword=${ZBX_DB_PASS}/" /etc/zabbix/zabbix_server.conf
sudo grep -E '^DB(Name|User|Password)=' /etc/zabbix/zabbix_server.conf
All three lines should print, with your password on the last one:
DBName=zabbix
DBUser=zabbix
DBPassword=Change-Me-Zbx-2026
That’s the only edit you need in zabbix_server.conf on a single-box install.
Start the services
On Ubuntu 26.04, enable the Apache FastCGI proxy first. The 26.04 zabbix-apache-conf hands PHP to a dedicated FPM pool over proxy_fcgi but does not enable the module. Skip this on 24.04, where the frontend runs through mod_php:
sudo a2enmod proxy_fcgi
Restart everything and enable it at boot:
sudo systemctl restart zabbix-server zabbix-agent2 apache2
sudo systemctl enable zabbix-server zabbix-agent2 apache2
systemctl is-active zabbix-server zabbix-agent2 apache2
Three active lines mean the stack is up:
active
active
active
If Apache shows failed on Ubuntu 26.04 instead, the error below is almost always why.
Error: “Invalid command ‘ProxyTimeout’, perhaps misspelled or defined by a module not included in the server configuration”
This is what Ubuntu 26.04 prints when proxy_fcgi was skipped. Apache fails to start and systemctl is-active returns failed for apache2. sudo journalctl -u apache2 names the Zabbix config:
Oct 07 15:50:27 zbx01 apachectl[18835]: AH00526: Syntax error on line 7 of /etc/apache2/conf-enabled/zabbix.conf:
Oct 07 15:50:27 zbx01 apachectl[18835]: Invalid command 'ProxyTimeout', perhaps misspelled or defined by a module not included in the server configuration
Oct 07 15:50:27 zbx01 systemd[1]: apache2.service: Main process exited, code=exited, status=1/FAILURE
Oct 07 15:50:27 zbx01 systemd[1]: apache2.service: Failed with result 'exit-code'.
Oct 07 15:50:27 zbx01 systemd[1]: Failed to start apache2.service - The Apache HTTP Server.
The fix is sudo a2enmod proxy_fcgi (it pulls in mod_proxy) followed by sudo systemctl restart apache2. The frontend then answers on /zabbix/.
Open the firewall
Allow SSH before enabling UFW, otherwise you lock yourself out of a remote server. Then open the web ports and the trapper port that agents use for active checks. Our UFW guide covers the rest of the rule syntax.
sudo ufw allow OpenSSH
sudo ufw allow 'Apache Full'
sudo ufw allow 10051/tcp
sudo ufw --force enable
sudo ufw status
The status lists the three rules for IPv4 and IPv6:
Status: active
To Action From
-- ------ ----
OpenSSH ALLOW Anywhere
Apache Full ALLOW Anywhere
10051/tcp ALLOW Anywhere
OpenSSH (v6) ALLOW Anywhere (v6)
Apache Full (v6) ALLOW Anywhere (v6)
10051/tcp (v6) ALLOW Anywhere (v6)
Apache Full opens both 80 and 443, and certbot needs port 80 in the next section.
Enable HTTPS with Let’s Encrypt
The Zabbix login form sends the Admin password. It is not something to send over plain HTTP. Install certbot with its Apache plugin:
sudo apt install -y certbot python3-certbot-apache
Certbot finds the virtual host by its ServerName. The default Ubuntu site has none. Without it certbot gets the certificate but cannot install it (the error is in the troubleshooting section). Set it on the default site:
sudo sed -i "s/#ServerName www.example.com/ServerName ${ZBX_DOMAIN}/" /etc/apache2/sites-available/000-default.conf
grep -n '^\s*ServerName' /etc/apache2/sites-available/000-default.conf
Now request the certificate. --redirect makes Apache send every HTTP request to HTTPS:
sudo certbot --apache -d "${ZBX_DOMAIN}" --non-interactive --agree-tos --redirect -m "${ADMIN_EMAIL}"
Certbot copies the default site into a new SSL site and enables it:
Deploying certificate
Successfully deployed certificate for zabbix.example.com to /etc/apache2/sites-available/000-default-le-ssl.conf
Congratulations! You have successfully enabled HTTPS on https://zabbix.example.com
Plain HTTP now answers with a permanent redirect:
curl -sI "http://${ZBX_DOMAIN}/zabbix/" | head -4
The Location header points at the HTTPS frontend:
HTTP/1.1 301 Moved Permanently
Date: Wed, 07 Oct 2026 15:04:59 GMT
Server: Apache/2.4.66 (Ubuntu)
Location: https://zabbix.example.com/zabbix/
The certbot package installs certbot.timer, which checks twice a day and renews the certificate when it nears expiry. No cron entry is needed.
No public port 80? Use a DNS-01 challenge instead
A Zabbix server on a private network cannot pass the HTTP-01 check. Prove ownership through a DNS TXT record instead, with the certbot plugin for your DNS provider: python3-certbot-dns-cloudflare, python3-certbot-dns-route53, python3-certbot-dns-digitalocean, python3-certbot-dns-google and python3-certbot-dns-rfc2136 for your own BIND are all in the Ubuntu archive. Each needs an API credential file. With Cloudflare and a token limited to DNS edit on the zone, it looks like this:
sudo apt install -y python3-certbot-dns-cloudflare
echo "dns_cloudflare_api_token = your-token-here" | sudo tee /root/cloudflare.ini > /dev/null
sudo chmod 600 /root/cloudflare.ini
sudo certbot certonly --dns-cloudflare --dns-cloudflare-credentials /root/cloudflare.ini -d "${ZBX_DOMAIN}" --non-interactive --agree-tos -m "${ADMIN_EMAIL}" --deploy-hook "systemctl reload apache2"
sudo certbot install --apache --cert-name "${ZBX_DOMAIN}" --redirect --non-interactive
Swap the plugin and its credential file for your provider. Do not drop --deploy-hook. A certificate issued with certonly has no installer in its renewal config, and certbot install does not add one, so without the hook the timer renews the files while Apache keeps serving the old certificate until it expires. The hook is saved as renew_hook in /etc/letsencrypt/renewal/, and a forced renewal of a test certificate in the lab reloaded Apache as expected. On Ubuntu 26.04 the Cloudflare plugin prints a long python-cloudflare deprecation banner on every run. It is noise: the plugin still loaded and reached the Cloudflare API in our test.
Run the web installer
Open https://zabbix.example.com/zabbix/ with your own domain. The installer opens on the language screen. Click Next step to reach the pre-requisites check, where every row should read OK. PHP 8.5 on 26.04 passes the 7.0 frontend’s checks without changes:

On Configure DB connection, leave the type as MySQL, host localhost, port 0 and database zabbix. Enter user zabbix and the password from ZBX_DB_PASS:

On Settings, give the server a name (it shows in the top left of every page), pick your time zone and theme, then step through the summary to Finish. The installer writes /etc/zabbix/web/zabbix.conf.php and drops you at the login page.
Log in and change the Admin password
The first login is Admin with password zabbix. The username is case sensitive, so admin does not work. Change the password before anything else: open User settings > Profile, click Change password, enter the current one and the new one twice, then Update.

The Global view dashboard loads next. Within a minute the local agent is green under Host availability and System information confirms the server is running. Yours shows one host at this point. This capture was taken after the second host was added later in the guide:

From a shell, the same health check is three commands. The listener list confirms MariaDB stays on loopback while 10051 and 443 face the network:
zabbix_server -V | head -1
systemctl is-active zabbix-server zabbix-agent2 apache2 mariadb
ss -tln '( sport = :10051 or sport = :443 or sport = :3306 )'
Output from the 26.04 server:

That is the core install done: server, frontend, HTTPS and local monitoring. The next section is only for adding other machines.
Monitor another server with Zabbix agent 2
Run this part on the host you want to monitor, here web01 on Ubuntu 24.04. Set the address of the Zabbix server first. It goes into the agent config and the firewall rule:
export ZBX_SERVER_IP='10.0.1.50'
Add the same 7.0 repository and install only the agent:
. /etc/os-release
wget "https://repo.zabbix.com/zabbix/7.0/ubuntu/pool/main/z/zabbix-release/zabbix-release_latest_7.0+ubuntu${VERSION_ID}_all.deb"
sudo dpkg -i "zabbix-release_latest_7.0+ubuntu${VERSION_ID}_all.deb"
sudo apt update
sudo apt install -y zabbix-agent2
Three settings matter. Server is who may poll this agent, ServerActive is where it sends active checks, and Hostname must match the host name you type into the frontend exactly:
sudo sed -i -e "s/^Server=127.0.0.1/Server=${ZBX_SERVER_IP}/" -e "s/^ServerActive=127.0.0.1/ServerActive=${ZBX_SERVER_IP}/" -e "s/^Hostname=Zabbix server/Hostname=$(hostname)/" /etc/zabbix/zabbix_agent2.conf
grep -E '^(Server|ServerActive|Hostname)=' /etc/zabbix/zabbix_agent2.conf
The agent now trusts only the Zabbix server and reports under the hostname of the machine:
Server=10.0.1.50
ServerActive=10.0.1.50
Hostname=web01
Restart the agent, enable it, and open 10050 to the Zabbix server only. Check sudo ufw status first. If UFW is already active, you only need the 10050 rule. If it is inactive and this host serves a website or other ports, allow those before ufw --force enable, or they stop answering:
sudo systemctl restart zabbix-agent2
sudo systemctl enable zabbix-agent2
sudo ufw allow OpenSSH
sudo ufw allow from "${ZBX_SERVER_IP}" to any port 10050 proto tcp
sudo ufw --force enable
Back on the Zabbix server, zabbix_get queries the agent the way the server will. Install it and ask for the agent version:
sudo apt install -y zabbix-get
zabbix_get -s 10.0.1.51 -k agent.version
Replace 10.0.1.51 with the address of your agent host (hostname -I on that host prints it). A version string back means the network path, the firewall and the Server= setting are all right:
7.0.31
In the frontend, go to Data collection > Hosts > Create host. Enter web01 as the host name, add the Linux by Zabbix agent template and the Linux servers group, then under Interfaces click Add > Agent and enter the same address you used with zabbix_get. Port 10050 is filled in for you:

Click Add. The ZBX badge under Availability turns green after the first successful poll, usually within a minute. Monitoring > Hosts shows both machines with their item and graph counts:

Click Graphs on the web01 row to see the data. The template ships CPU, memory, disk and network graphs. These are the first 15 minutes of memory data from web01:

A filling graph means the agent, the server and the database are all doing their part.
Install Zabbix on Ubuntu 26.04 vs 24.04: what differs
The Zabbix packages are the same 7.0 build on both releases. What comes from the Ubuntu archive is not, and that is where the two installs differ:
| Item | Ubuntu 26.04 | Ubuntu 24.04 |
|---|---|---|
| MariaDB | 11.8 | 10.11 |
| PHP | 8.5 via PHP-FPM (pool zabbix-php-fpm.conf) | 8.3 via mod_php |
| Apache | 2.4.66 | 2.4.58 |
| Extra Apache step | a2enmod proxy_fcgi required | None |
| Schema import time (lab VM) | 37 s | 16 s |
| Frontend config | /etc/zabbix/web/zabbix.conf.php on both | |
Troubleshooting
“Get value error: cannot read from socket: [104] Connection reset by peer”
The agent is reachable, but it does not accept the server. We reproduced it by setting Server= on web01 to the wrong address. zabbix_get on the server failed like this:
zabbix_get [18095]: Get value error: cannot read from socket: [104] Connection reset by peer
The agent log on web01 says exactly why:
2026/10/07 15:25:46.335627 connection from "10.0.1.50" rejected, allowed hosts: "10.0.1.99"
Put the address the server actually connects from into Server= in /etc/zabbix/zabbix_agent2.conf and restart zabbix-agent2. On a server with several interfaces, that is the source address on the route to the agent, which is not always the one you think. If you get a timeout instead of a reset, the agent is not the problem: check the firewall on the agent host.
“Encountered vhost ambiguity when trying to find a vhost” from certbot
Certbot issued the certificate but no Apache virtual host carried the domain as ServerName or ServerAlias, so it could not choose where to install it:
Encountered vhost ambiguity when trying to find a vhost for mon.example.com but was unable to ask for user guidance in non-interactive mode. Certbot may need vhosts to be explicitly labelled with ServerName or ServerAlias directives.
Could not install certificate
Add the name to the site that serves Zabbix (the sed in the HTTPS section does this for 000-default.conf), then finish without requesting a new certificate: sudo certbot install --apache --cert-name "${ZBX_DOMAIN}" --redirect --non-interactive.
Before you add more hosts
A single-server Zabbix carries a few hundred hosts comfortably if the database is looked after. In production, you will want these in place before the host list grows:
- Backups. Dump the database and keep
/etc/zabbixwith it.sudo mariadb-dump --single-transaction --routines zabbix | gzipproduced a 4.1 MB file on the lab server; add it to a nightly timer and copy it off the box. - History retention. Item history drives database size. Shorten history to 7 to 14 days under Administration > Housekeeping once you rely on trends for long-term graphs.
- Agent encryption. Traffic on 10050 and 10051 is plain text by default. Set a PSK on each agent (
TLSConnect=psk,TLSAccept=psk,TLSPSKIdentity,TLSPSKFile) and match it on the Encryption tab of the host in the frontend. - Upgrades. Point releases arrive through
apt upgrade. Zabbix 8.0 LTS shipped on 5 November 2026, and 7.0 is still a supported LTS line, so this server doesn’t have to move yet. For a new 8.0 box, use Zabbix 8.0 on Ubuntu 26.04 or the Zabbix 8.0 install on Ubuntu 24.04. To take an existing 7.0 server across, follow the 7.0 to 8.0 upgrade guide on a snapshot first.
Zabbix covers infrastructure and alerting well. For metrics-heavy dashboards, many teams put Grafana on top with the Zabbix data source, and some run Prometheus next to it for container workloads.
Noma sana! Thanks man, very conscise guide!