Why the Frontend Is Its Own Tier
The Zabbix frontend is the only part of the stack a non-engineer ever sees. It is also the part most likely to break in ways that look catastrophic but are operationally minor: when the frontend pod crashes mid-deploy, the on-call alert reads "Zabbix is down", the team panics, the actual server pair is still collecting and alerting normally, and forty minutes later you discover the only thing that failed was a containerised PHP renderer with zero state.
That is the whole reason the frontend deserves to live alone:
- It is stateless. Every page render is a fresh database query. You can kill it, restart it, run two of them behind a load balancer, or deploy it red/black with no migration step. None of that is true for the server tier.
- Its failure mode is loss of visibility, not loss of telemetry. Frontend down means humans cannot see graphs; collectors are still collecting and triggers are still firing. The pager response is "yawn, restart it", not "scramble".
- Its dependencies are different. It needs the database (for HA-state lookup) and HTTP reach to the active server (for API calls). It does not need the proxy or the agents. That makes it easy to put on a different network, behind a different reverse proxy, or in a DMZ.
This post covers two deploy paths. The container version (Docker on the same monitoring VM) is the right choice for most homelabs and small environments. The bare-metal version (Apache + PHP) is what fits when your org disallows containers for whatever compliance reason, or when you want the frontend hosted on a load balancer that already runs Apache.
Zabbix Frontend setup
As I mentioned on my previous post, I'll be covering how to install the frontend using the official Zabbix Alpine Image docker image and on the server itself, in our case Ubuntu 24.04
This guide assumes that you are capable of deploying an ubuntu server on your own. If not, please follow this guide before proceeding.
Docker
If you don't know how to install docker and docker compose, please follow this Guide before moving on. Alternatively, you can skip to Server Install
1. Create a new directory
Before we deploy the container, create a new directory that will store the compose file. On my docker server, I have a dedicated directory /opt/Docker/ for all services I deploy using docker-compose. I'm going to create a folder named ZabbixWeb:
mkdir /opt/Docker/ZabbixWeb
2. Create and configure a docker-compose.yaml file
Create a new file named docker-compose.yaml in the previously created folder.
vim docker-compose.yaml
Modify the compose file to reflect your environment!
- Container Name:
zabbix_web - Ports: The zabbix frontend exposes the port
8080on the container, and I'll be mapping that port to port9015on my host, since port8080is already in use. Feel free to set the port to8080:8080or80:8080to expose port80or8080on your host. - Environment Variables:
DB_SERVER_HOST: IP of the database server, in my case10.0.0.20POSTGRES_USER: The user we created,zabbixwebPOSTGRES_PASSWORD: The password for thezabbixwebuserPHP_TZ: The time zone, in my caseAmerica/Chicago
version: "3.3"
services:
zabbix-web-nginx-pgsql:
container_name: zabbix_web
ports:
- 9015:8080
environment:
- DB_SERVER_HOST=10.0.0.20
- POSTGRES_USER=zabbixweb
- POSTGRES_PASSWORD=zabbix
- PHP_TZ=America/Chicago
image: zabbix/zabbix-web-apache-pgsql:alpine-6.4-latest
networks: {}
3. Deploy the container
From the directory we've created, deploy the container with docker compose
docker compose up -d
Now you should be able to navigate to your hosts IP:Port and access the interface. In my case 10.0.0.250:9015
Done! The frontend should now be up and running!
Server Install
If docker is not for you, you can install the frontend on a standalone server.
Make sure your servers have a static IP address. Below is the /etc/netplan/*.yaml config I'm using
10.0.0.23: Zabbix Web10.0.0.1: Gateway10.0.0.200: Internal DNS server
network:
version: 2
renderer: networkd
ethernets:
eth0:
addresses:
- 10.0.0.23/24
routes:
- to: default
via: 10.0.0.1
nameservers:
addresses: [10.0.0.200]
1. Install the zabbix repository
First, we need to download the repository with wget
wget https://repo.zabbix.com/zabbix/7.4/release/ubuntu/pool/main/z/zabbix-release/zabbix-release_latest_7.4+ubuntu24.04_all.deb
Once the download is done, install the packages using dpkg
sudo dpkg -i zabbix-release_latest_7.4+ubuntu24.04_all.deb
Now we need to update the packages
sudo apt update -y
2. Install the frontend
With the zabbix repository setup, we can install the frontend using apt
sudo apt install -y zabbix-frontend-php php8.3-pgsql zabbix-apache-conf
With the packages installed, we need to enable and start apache2
sudo systemctl enable apache2
sudo systemctl start apache2
It's always good practice to disable the default apache website
sudo a2dissite 000-default.conf
sudo systemctl reload apache2
3. Configure the Frontend
If you go to your server's IP address/zabbix http://10.0.0.23/zabbix you should see the setup screen

If you get an error on this step, check the errors I got during the installation process.
Once you get to the database config, your setup should look like the image below

Next set up the timezone and your preferred theme.
Remember that on this step we don't specify the zabbix server name because we've setup HA

Follow the remaining steps and you should get the congratulations message.

Done! The frontend should now be up and running!
Issues I've encouter
Missing Locale
During the server setup, I got the following error

The locale on the server is not setup properly, let's fix it.
Reconfigure Locale
If you don't have the locales tools installed, run
sudo apt clean && sudo apt update && sudo apt install -y locales
To start the configuration, run the command:
sudo dpkg-reconfigure locales
The output will look like the image below

In my case, I need en_US, which is the option 97 from the image above

We need to select the default locale, which in my case is the option 3 for en_US

Last thing to do is to restart apache2
sudo systemctl restart apache2

Done! The locale has been reconfigured, and you should be able to reload the page and continue with the configuration
What You Have Now
A working Zabbix frontend that can render the dashboard, walk the host inventory, and fail over with the server pair without you reconfiguring it. The HA-aware behaviour is the part that pays for itself: if the active server is currently zabbix02, the frontend reads that from the ha_node table on every API call, so you never have to manually point the frontend at "the new active server" after a failover.
Verify It Before You Move On
Three checks are worth doing before you build the proxy on top:
- Confirm both servers appear in the frontend. Reports → System information → High availability cluster. You should see both
HANodeNames, one as Active, one as Standby. If only one shows, the standby never registered, the database connection from that server is broken. - Test failover from the frontend's point of view. Stop
zabbix-serveron the active node (as the server post describes). Refresh the dashboard. After 60 seconds, the system-information page should show the standby promoted to Active and the dashboard should keep rendering normally. - Lock the locale in image config, not by manual
dpkg-reconfigure. If you hit the locale error documented above, fix it once in your base image (or Dockerfile, or cloud-init), not interactively. Manual fixes don't survive the next rebuild.
Next in the Series
The proxy post builds the collection layer that buffers data from agents and ships it to the active server. After that, the agent post installs the collectors on the hosts you actually want to monitor. With those two in place, the build from the overview post is complete.
![Zabbix Log File Monitoring with log[] and logrt[]](/Images/Posts/zabbix-log-monitoring.webp)

