Skip to main content

Zabbix Multi-Tenant NGINX Docker Ingress

Mong Kok, Hong Kong

I set up a Zabbix server using the official Compose file. The docker container managed by this file are already set up to use SSL certificates to enable you to access the web frontend using HTTPS. But my server already runs other services behind an NGINX proxy and I would like to just add an URL prefix and host the Zabbix frontend on the same URL that is already managed by this proxy.

NGINX Setup

I do have the following NGINX server block that host 3 Node.js web application on different prefix URLs on the same domain - currently this is localhost in my testing environment and will be switched to an external URL with an CA certificate later. All I did below is that I added a fourth location block to the configuration file for my Zabbix frontend running on Port 8080:

server {
listen 80;
listen [::]:80;
server_name localhost;

charset koi8-r;

# Gzip Compression
gzip on;
gzip_disable "MSIE [1-6]\.(?!.*SV1)";
gzip_proxied no-cache no-store private expired;
gzip_buffers 16 8k;
gzip_comp_level 6;
gzip_types text/plain application/javascript application/x-javascript text/javascript text/xml text/css;
gzip_vary on;

location / {
rewrite ^/(.*)$ /en/$1 permanent;
}

root /opt/wiki/wiki-en/public;

location /en/ {
add_header Cache-Control "public, must-revalidate, proxy-revalidate, max-age=0";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto http;
proxy_hide_header X-Frame-Options;
proxy_set_header Accept-Encoding "";
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_max_temp_file_size 0;
proxy_redirect off;
proxy_read_timeout 240s;
proxy_pass http://wiki_en:8888/;
}

location /fr/ {
add_header Cache-Control "public, must-revalidate, proxy-revalidate, max-age=0";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto http;
proxy_hide_header X-Frame-Options;
proxy_set_header Accept-Encoding "";
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_max_temp_file_size 0;
proxy_redirect off;
proxy_read_timeout 240s;
proxy_pass http://wiki_fr:8888/;
root /opt/wiki/wiki-fr/public;
}

location /de/ {
add_header Cache-Control "public, must-revalidate, proxy-revalidate, max-age=0";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto http;
proxy_hide_header X-Frame-Options;
proxy_set_header Accept-Encoding "";
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_max_temp_file_size 0;
proxy_redirect off;
proxy_read_timeout 240s;
proxy_pass http://wiki_de:8888/;
root /opt/wiki/wiki-de/public;
}

location /zabbix/ {
add_header Cache-Control "public, must-revalidate, proxy-revalidate, max-age=0";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto http;
proxy_hide_header X-Frame-Options;
proxy_set_header Accept-Encoding "";
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_max_temp_file_size 0;
proxy_redirect off;
proxy_read_timeout 240s;
proxy_pass http://docker-zabbix_zabbix-web-apache-pgsql_1:8080/;
}

error_page 404 /de/404.html;

# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}

The issue here is that all my apps are running inside virtual network that cannot be accessed from my host system. And at the moment the zabbix frontend is not connected to this network - this means my proxy_pass to docker-zabbix_zabbix-web-apache-pgsql_1:8080 is going to fail.

The Virtual App Network

The virtual network is created with another compose file that is setting up my web applications:

version: '3.8'
services:
wiki_en:
image: my.gitlab.com:12345/wiki/wiki_container:latest
container_name: wiki_en
networks:
- gateway
restart: unless-stopped
volumes:
- /opt/wiki/wiki-en/public:/wiki/public

wiki_fr:
image: my.gitlab.com:12345/wiki/wiki_container:latest
container_name: wiki_fr
networks:
- gateway
restart: unless-stopped
volumes:
- /opt/wiki/wiki-fr/public:/wiki/public

wiki_de:
image: my.gitlab.com:12345/wiki/wiki_container:latest
container_name: wiki_de
networks:
- gateway
restart: unless-stopped
volumes:
- /opt/wiki/wiki-de/public:/wiki/public

ingress:
image: nginx:stable-alpine
container_name: ingress
networks:
- gateway
ports:
- '80:80'
restart: unless-stopped
volumes:
- /opt/wiki/docker_ingress:/etc/nginx/conf.d
- /opt/wiki/wiki-en:/opt/wiki/wiki-en
- /opt/wiki/wiki-fr:/opt/wiki/wiki-fr
- /opt/wiki/wiki-de:/opt/wiki/wiki-de

networks:
gateway: {}

Adding your Zabbix Frontend

To add my Zabbix frontend to this virtual network I need to modify the Zabbix Server Compose file:

zabbix-web-apache-pgsql:
image: zabbix/zabbix-web-apache-pgsql:alpine-5.0-latest
networks:
zbx_net_backend:
ipv4_address: 172.16.239.104
aliases:
- zabbix-web-apache-pgsql
- zabbix-web-apache-alpine-pgsql
- zabbix-web-apache-pgsql-alpine
zbx_net_frontend:
ipv4_address: 172.16.238.104
wiki_gateway:
ipv4_address: 172.20.0.6

I added the wiki_gateway as well as an IPv4 address - to check what IP addresses are available inside an Docker network you can inspect it. I simply added the Zabbix frontend container to my Wiki network manually and ran the inspect command to see what address was assigned to the container.

First run docker ps to find out your frontends Docker Container ID and Container Name:

docker ps
CONTAINER ID IMAGE NAMES
44dfd075af57 zabbix/zabbix-web-apache-pgsql:alpine-5.0-latest docker-zabbix_zabbix-web-apache-pgsql_1

Then add the Container ID to the virtual network and inspect the network to see if it worked:

docker network connect wiki_gateway 44dfd075af57

docker inspect wiki_gateway
[
{
"Name": "wiki_gateway",
"Id": "98f70ca5f7baf4f676029c31c9c68f3b3743521975becef326f97312a41c669b",
"Created": "2020-10-07T09:53:17.531329441Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.20.0.0/16",
"Gateway": "172.20.0.1"
}
]
},
"Internal": false,
"Attachable": true,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"15c50c7d5997e3a7562e3b121cb795e9d22fdb614a869a532ca93a1d92637390": {
"Name": "wiki_de",
"EndpointID": "4eb0596b1cc0aaa046f9077512eb283a1063916e6072d707a97196ad40021e2e",
"MacAddress": "02:42:ac:14:00:03",
"IPv4Address": "172.20.0.3/16",
"IPv6Address": ""
},
"1af00ce71d4da9ccfe9800ebf1fcba5dbfd842d90b0fbe92e27f7bd1dac7c691": {
"Name": "wiki_fr",
"EndpointID": "c888701c3717aa73fcc3ce6b682626b8f31506935d6dd5cb3f9acae4ce62e5a7",
"MacAddress": "02:42:ac:14:00:02",
"IPv4Address": "172.20.0.2/16",
"IPv6Address": ""
},
"44dfd075af5789dab49f9e083d6fbb60ab4f5f74206a9190634675db48354636": {
"Name": "docker-zabbix_zabbix-web-apache-pgsql_1",
"EndpointID": "5c4a8b866d4f584d24d78a41d2aee06035899f0d14825dd698d99ee7689ae7ba",
"MacAddress": "02:42:ac:14:00:06",
"IPv4Address": "172.20.0.6/16",
"IPv6Address": ""
},
"9419eb378185058c9159ac9ec43d9e69725b55b7d454b901b01e815ffd3b7954": {
"Name": "ingress",
"EndpointID": "ca7898a11610bc10b6cd3be8e3de0274b82905998e90af91d333e063f7b75185",
"MacAddress": "02:42:ac:14:00:05",
"IPv4Address": "172.20.0.5/16",
"IPv6Address": ""
},
"d4ef7e3026a15b845e6d7bb2af0a9376d1482b67b3af1fa84ab546f45dc64470": {
"Name": "wiki_en",
"EndpointID": "5bacfc78a7cc4db5e57b33de499809d8b66f0d1198aed11a7c1a26f73663c68d",
"MacAddress": "02:42:ac:14:00:04",
"IPv4Address": "172.20.0.4/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {
"com.docker.compose.network": "gateway",
"com.docker.compose.project": "wiki",
"com.docker.compose.version": "1.26.2"
}
}
]

You can see that the frontend container is now connected to the virtual network and assigned the following IP address (that I already used in the compose file above):

"IPv4Address": "172.20.0.6/16",

Now docker-compose down and docker-compose up -d your Zabbix Server environemt and your frontend will automatically be connected to your virtual network and you should be able to access it with the /zabbix/ URL prefix on Port 80!

I am now able to close the Port that I was previously using to access the Zabbix frontend and use my NGINX ingress on port 80 instead. I am happy with that :)

Complete Zabbix Server Compose File

version: '3.5'
services:
zabbix-server:
image: zabbix/zabbix-server-pgsql:alpine-5.0-latest
ports:
- "10051:10051"
volumes:
- /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro
- ./zbx_env/usr/lib/zabbix/alertscripts:/usr/lib/zabbix/alertscripts:ro
- ./zbx_env/usr/lib/zabbix/externalscripts:/usr/lib/zabbix/externalscripts:ro
- ./zbx_env/var/lib/zabbix/export:/var/lib/zabbix/export:rw
- ./zbx_env/var/lib/zabbix/modules:/var/lib/zabbix/modules:ro
- ./zbx_env/var/lib/zabbix/enc:/var/lib/zabbix/enc:ro
- ./zbx_env/var/lib/zabbix/ssh_keys:/var/lib/zabbix/ssh_keys:ro
- ./zbx_env/var/lib/zabbix/mibs:/var/lib/zabbix/mibs:ro
links:
- postgres-server:postgres-server
- zabbix-java-gateway:zabbix-java-gateway
ulimits:
nproc: 65535
nofile:
soft: 20000
hard: 40000
deploy:
resources:
limits:
cpus: '0.70'
memory: 1G
reservations:
cpus: '0.5'
memory: 512M
env_file:
- .env_db_pgsql
- .env_srv
secrets:
- POSTGRES_USER
- POSTGRES_PASSWORD
depends_on:
- postgres-server
- zabbix-java-gateway
networks:
zbx_net_backend:
ipv4_address: 172.16.239.101
aliases:
- zabbix-server
- zabbix-server-pgsql
- zabbix-server-alpine-pgsql
- zabbix-server-pgsql-alpine
zbx_net_frontend:
ipv4_address: 172.16.238.101
stop_grace_period: 30s
sysctls:
- net.ipv4.ip_local_port_range=1024 65000
- net.ipv4.conf.all.accept_redirects=0
- net.ipv4.conf.all.secure_redirects=0
- net.ipv4.conf.all.send_redirects=0
labels:
com.zabbix.description: "Zabbix server with PostgreSQL database support"
com.zabbix.company: "Zabbix LLC"
com.zabbix.component: "zabbix-server"
com.zabbix.dbtype: "pgsql"
com.zabbix.os: "alpine"

zabbix-proxy-sqlite3:
image: zabbix/zabbix-proxy-sqlite3:alpine-5.0-latest
ports:
- "10061:10051"
volumes:
- /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro
- ./zbx_env/usr/lib/zabbix/externalscripts:/usr/lib/zabbix/externalscripts:ro
- ./zbx_env/var/lib/zabbix/modules:/var/lib/zabbix/modules:ro
- ./zbx_env/var/lib/zabbix/enc:/var/lib/zabbix/enc:ro
- ./zbx_env/var/lib/zabbix/ssh_keys:/var/lib/zabbix/ssh_keys:ro
- ./zbx_env/var/lib/zabbix/mibs:/var/lib/zabbix/mibs:ro
links:
- zabbix-server:zabbix-server
- zabbix-java-gateway:zabbix-java-gateway
ulimits:
nproc: 65535
nofile:
soft: 20000
hard: 40000
deploy:
resources:
limits:
cpus: '0.70'
memory: 512M
reservations:
cpus: '0.3'
memory: 256M
env_file:
- .env_prx
- .env_prx_sqlite3
depends_on:
- zabbix-java-gateway
networks:
zbx_net_backend:
ipv4_address: 172.16.239.102
aliases:
- zabbix-proxy-sqlite3
- zabbix-proxy-alpine-sqlite3
- zabbix-proxy-sqlite3-alpine
zbx_net_frontend:
ipv4_address: 172.16.238.102
stop_grace_period: 30s
labels:
com.zabbix.description: "Zabbix proxy with SQLite3 database support"
com.zabbix.company: "Zabbix LLC"
com.zabbix.component: "zabbix-proxy"
com.zabbix.dbtype: "sqlite3"
com.zabbix.os: "alpine"

zabbix-proxy-mysql:
image: zabbix/zabbix-proxy-mysql:alpine-5.0-latest
ports:
- "10071:10051"
volumes:
- /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro
- ./zbx_env/usr/lib/zabbix/externalscripts:/usr/lib/zabbix/externalscripts:ro
- ./zbx_env/var/lib/zabbix/modules:/var/lib/zabbix/modules:ro
- ./zbx_env/var/lib/zabbix/enc:/var/lib/zabbix/enc:ro
- ./zbx_env/var/lib/zabbix/ssh_keys:/var/lib/zabbix/ssh_keys:ro
- ./zbx_env/var/lib/zabbix/mibs:/var/lib/zabbix/mibs:ro
links:
- zabbix-server:zabbix-server
- zabbix-java-gateway:zabbix-java-gateway
ulimits:
nproc: 65535
nofile:
soft: 20000
hard: 40000
deploy:
resources:
limits:
cpus: '0.70'
memory: 512M
reservations:
cpus: '0.3'
memory: 256M
env_file:
- .env_db_mysql_proxy
- .env_prx
- .env_prx_mysql
secrets:
- MYSQL_USER
- MYSQL_PASSWORD
- MYSQL_ROOT_PASSWORD
depends_on:
- mysql-server
- zabbix-java-gateway
networks:
zbx_net_backend:
ipv4_address: 172.16.239.103
aliases:
- zabbix-proxy-mysql
- zabbix-proxy-alpine-mysql
- zabbix-proxy-mysql-alpine
zbx_net_frontend:
ipv4_address: 172.16.238.103
stop_grace_period: 30s
labels:
com.zabbix.description: "Zabbix proxy with MySQL database support"
com.zabbix.company: "Zabbix LLC"
com.zabbix.component: "zabbix-proxy"
com.zabbix.dbtype: "mysql"
com.zabbix.os: "alpine"

zabbix-web-apache-pgsql:
image: zabbix/zabbix-web-apache-pgsql:alpine-5.0-latest
ports:
- "7777:8080"
- "7778:8443"
links:
- postgres-server:postgres-server
- zabbix-server:zabbix-server
volumes:
- /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro
- ./zbx_env/etc/ssl/apache2:/etc/ssl/apache2:ro
- ./zbx_env/usr/share/zabbix/modules/:/usr/share/zabbix/modules/:ro
deploy:
resources:
limits:
cpus: '0.70'
memory: 512M
reservations:
cpus: '0.5'
memory: 256M
env_file:
- .env_db_pgsql
- .env_web
secrets:
- POSTGRES_USER
- POSTGRES_PASSWORD
depends_on:
- postgres-server
- zabbix-server
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/"]
interval: 10s
timeout: 5s
retries: 3
start_period: 30s
networks:
zbx_net_backend:
ipv4_address: 172.16.239.104
aliases:
- zabbix-web-apache-pgsql
- zabbix-web-apache-alpine-pgsql
- zabbix-web-apache-pgsql-alpine
zbx_net_frontend:
ipv4_address: 172.16.238.104
wiki_gateway:
ipv4_address: 172.20.0.6
stop_grace_period: 10s
sysctls:
- net.core.somaxconn=65535
labels:
com.zabbix.description: "Zabbix frontend on Apache web-server with PostgreSQL database support"
com.zabbix.company: "Zabbix LLC"
com.zabbix.component: "zabbix-frontend"
com.zabbix.webserver: "apache2"
com.zabbix.dbtype: "pgsql"
com.zabbix.os: "alpine"

zabbix-web-nginx-pgsql:
image: zabbix/zabbix-web-nginx-pgsql:alpine-5.0-latest
ports:
- "8081:8080"
- "8443:8443"
links:
- postgres-server:postgres-server
- zabbix-server:zabbix-server
volumes:
- /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro
- ./zbx_env/etc/ssl/nginx:/etc/ssl/nginx:ro
- ./zbx_env/usr/share/zabbix/modules/:/usr/share/zabbix/modules/:ro
deploy:
resources:
limits:
cpus: '0.70'
memory: 512M
reservations:
cpus: '0.5'
memory: 256M
env_file:
- .env_db_pgsql
- .env_web
secrets:
- POSTGRES_USER
- POSTGRES_PASSWORD
depends_on:
- postgres-server
- zabbix-server
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/"]
interval: 10s
timeout: 5s
retries: 3
start_period: 30s
networks:
zbx_net_backend:
ipv4_address: 172.16.239.105
aliases:
- zabbix-web-nginx-pgsql
- zabbix-web-nginx-alpine-pgsql
- zabbix-web-nginx-pgsql-alpine
zbx_net_frontend:
ipv4_address: 172.16.238.105
stop_grace_period: 10s
sysctls:
- net.core.somaxconn=65535
labels:
com.zabbix.description: "Zabbix frontend on Nginx web-server with PostgreSQL database support"
com.zabbix.company: "Zabbix LLC"
com.zabbix.component: "zabbix-frontend"
com.zabbix.webserver: "nginx"
com.zabbix.dbtype: "pgsql"
com.zabbix.os: "alpine"

zabbix-agent:
privileged: true
image: zabbix/zabbix-agent:alpine-5.0-latest
ports:
- "10050:10050"
volumes:
- /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro
- ./zbx_env/etc/zabbix/zabbix_agentd.d:/etc/zabbix/zabbix_agentd.d:ro
- ./zbx_env/var/lib/zabbix/modules:/var/lib/zabbix/modules:ro
- ./zbx_env/var/lib/zabbix/enc:/var/lib/zabbix/enc:ro
- ./zbx_env/var/lib/zabbix/ssh_keys:/var/lib/zabbix/ssh_keys:ro
links:
- zabbix-server:zabbix-server
deploy:
resources:
limits:
cpus: '0.2'
memory: 128M
reservations:
cpus: '0.1'
memory: 64M
mode: global
env_file:
- .env_agent
privileged: true
pid: "host"
networks:
zbx_net_backend:
ipv4_address: 172.16.239.106
aliases:
- zabbix-agent
- zabbix-agent-passive
- zabbix-agent-alpine
stop_grace_period: 5s
labels:
com.zabbix.description: "Zabbix agent"
com.zabbix.company: "Zabbix LLC"
com.zabbix.component: "zabbix-agentd"
com.zabbix.os: "alpine"

zabbix-java-gateway:
image: zabbix/zabbix-java-gateway:alpine-5.0-latest
ports:
- "10052:10052"
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
cpus: '0.25'
memory: 256M
env_file:
- .env_java
networks:
zbx_net_backend:
ipv4_address: 172.16.239.107
aliases:
- zabbix-java-gateway
- zabbix-java-gateway-alpine
stop_grace_period: 5s
labels:
com.zabbix.description: "Zabbix Java Gateway"
com.zabbix.company: "Zabbix LLC"
com.zabbix.component: "java-gateway"
com.zabbix.os: "alpine"

mysql-server:
image: mysql:8.0
command:
- mysqld
- --character-set-server=utf8
- --collation-server=utf8_bin
- --default-authentication-plugin=mysql_native_password
volumes:
- ./zbx_env/var/lib/mysql:/var/lib/mysql:rw
env_file:
- .env_db_mysql
secrets:
- MYSQL_USER
- MYSQL_PASSWORD
- MYSQL_ROOT_PASSWORD
stop_grace_period: 1m
networks:
zbx_net_backend:
ipv4_address: 172.16.239.109
aliases:
- mysql-server
- zabbix-database
- mysql-database

postgres-server:
image: postgres:latest
volumes:
- ./zbx_env/var/lib/postgresql/data:/var/lib/postgresql/data:rw
- ./.ZBX_DB_CA_FILE:/run/secrets/root-ca.pem:ro
- ./.ZBX_DB_CERT_FILE:/run/secrets/server-cert.pem:ro
- ./.ZBX_DB_KEY_FILE:/run/secrets/server-key.pem:ro
env_file:
- .env_db_pgsql
secrets:
- POSTGRES_USER
- POSTGRES_PASSWORD
stop_grace_period: 1m
networks:
zbx_net_backend:
ipv4_address: 172.16.239.110
aliases:
- postgres-server
- pgsql-server
- pgsql-database

db_data_mysql:
image: busybox
volumes:
- ./zbx_env/var/lib/mysql:/var/lib/mysql:rw

db_data_pgsql:
image: busybox
volumes:
- ./zbx_env/var/lib/postgresql/data:/var/lib/postgresql/data:rw

networks:
zbx_net_frontend:
driver: bridge
driver_opts:
com.docker.network.enable_ipv6: "false"
ipam:
driver: default
config:
- subnet: 172.16.238.0/24
zbx_net_backend:
driver: bridge
driver_opts:
com.docker.network.enable_ipv6: "false"
internal: true
ipam:
driver: default
config:
- subnet: 172.16.239.0/24
wiki_gateway:
external: true
name: wiki_gateway

secrets:
MYSQL_USER:
file: ./.MYSQL_USER
MYSQL_PASSWORD:
file: ./.MYSQL_PASSWORD
MYSQL_ROOT_PASSWORD:
file: ./.MYSQL_ROOT_PASSWORD
POSTGRES_USER:
file: ./.POSTGRES_USER
POSTGRES_PASSWORD:
file: ./.POSTGRES_PASSWORD