Compare commits

...

3 Commits

12 changed files with 4818 additions and 472 deletions

81
extract_nginx_config.py Normal file
View File

@ -0,0 +1,81 @@
import yaml
import uuid
import sys
def extract_nginx_config(input_file, output_file):
print(f"Reading {input_file}...")
with open(input_file, 'r', encoding='utf-8') as f:
data = yaml.safe_load(f)
if 'zabbix_export' not in data or 'hosts' not in data['zabbix_export']:
print("No hosts found in export file (checked under zabbix_export['hosts']).")
return
# We assume we are extracting from the first host or all hosts,
# but usually an export has one specific host of interest.
# The user mentioned "srvproxy001".
extracted_discovery_rules = []
extracted_items = []
for host in data['zabbix_export']['hosts']:
print(f"Processing host: {host['host']}")
# Extract Discovery Rules related to Nginx
if 'discovery_rules' in host:
for dr in host['discovery_rules']:
# Filter by name or key containing 'nginx'
if 'nginx' in dr['key'].lower() or 'nginx' in dr['name'].lower() or 'insight' in dr['name'].lower():
print(f" Found Discovery Rule: {dr['name']} ({dr['key']})")
extracted_discovery_rules.append(dr)
# Extract Items related to Nginx (directly attached to host, not in LLD)
if 'items' in host:
for item in host['items']:
if 'nginx' in item['key'].lower() or 'nginx' in item['name'].lower():
print(f" Found Item: {item['name']} ({item['key']})")
extracted_items.append(item)
if not extracted_discovery_rules and not extracted_items:
print("No Nginx configurations found.")
return
# Create Template Structure
template_uuid = str(uuid.uuid4())
group_uuid = "7df96b18c230490a9a0a9e2307226338" # Generic uuid for Templates group
template_export = {
'zabbix_export': {
'version': data['zabbix_export']['version'],
'template_groups': [
{
'uuid': group_uuid,
'name': 'Templates/Applications'
}
],
'templates': [
{
'uuid': template_uuid,
'template': 'Template Nginx Custom Insight',
'name': 'Template Nginx Custom Insight',
'description': 'Template extracted from host configuration containing custom Nginx Insight rules.',
'groups': [
{'name': 'Templates/Applications'}
],
'items': extracted_items,
'discovery_rules': extracted_discovery_rules
}
]
}
}
print(f"Writing to {output_file}...")
with open(output_file, 'w', encoding='utf-8') as f:
yaml.dump(template_export, f, sort_keys=False, allow_unicode=True)
print("Done.")
if __name__ == "__main__":
if len(sys.argv) < 3:
print("Usage: python extract_nginx_config.py <input_yaml> <output_yaml>")
else:
extract_nginx_config(sys.argv[1], sys.argv[2])

69
merge_nginx_templates.py Normal file
View File

@ -0,0 +1,69 @@
import yaml
import sys
def merge_templates(base_file, custom_file, output_file):
print(f"Loading base template: {base_file}")
with open(base_file, 'r', encoding='utf-8') as f:
base_data = yaml.safe_load(f)
print(f"Loading custom template: {custom_file}")
with open(custom_file, 'r', encoding='utf-8') as f:
custom_data = yaml.safe_load(f)
# Assume standard Zabbix 6.0+ YAML export structure
# zabbix_export -> templates -> [list]
if 'zabbix_export' not in base_data or 'templates' not in base_data['zabbix_export']:
print("Invalid base template structure.")
return
base_template = base_data['zabbix_export']['templates'][0]
if 'zabbix_export' in custom_data and 'templates' in custom_data['zabbix_export']:
custom_template = custom_data['zabbix_export']['templates'][0]
else:
print("Invalid custom template structure.")
return
print("Merging Discovery Rules...")
if 'discovery_rules' in custom_template:
if 'discovery_rules' not in base_template:
base_template['discovery_rules'] = []
# Check for duplicates by name or key to avoid collision
existing_keys = {dr['key'] for dr in base_template['discovery_rules']}
for dr in custom_template['discovery_rules']:
if dr['key'] in existing_keys:
print(f" Skipping duplicate key: {dr['key']}")
else:
print(f" Adding rule: {dr['name']}")
base_template['discovery_rules'].append(dr)
print("Merging Items...")
if 'items' in custom_template:
if 'items' not in base_template:
base_template['items'] = []
existing_item_keys = {item['key'] for item in base_template['items']}
for item in custom_template['items']:
if item['key'] in existing_item_keys:
print(f" Skipping duplicate item key: {item['key']}")
else:
print(f" Adding item: {item['name']}")
base_template['items'].append(item)
# Update Template Name
base_template['name'] = "Nginx by Zabbix agent (Gold)"
print(f"Writing merged template to {output_file}")
with open(output_file, 'w', encoding='utf-8') as f:
yaml.dump(base_data, f, sort_keys=False, allow_unicode=True)
print("Merge Complete.")
if __name__ == "__main__":
if len(sys.argv) < 4:
print("Usage: python merge_nginx_templates.py <base_yaml> <custom_yaml> <output_yaml>")
else:
merge_templates(sys.argv[1], sys.argv[2], sys.argv[3])

View File

@ -0,0 +1,749 @@
zabbix_export:
version: '7.4'
template_groups:
- uuid: 7df96b18c230490a9a0a9e2307226338
name: Templates/Applications
templates:
- uuid: cb591855-1b11-4789-9cdd-9f9aaeea5edb
template: Template Nginx Custom Insight
name: Template Nginx Custom Insight
description: Template extracted from host configuration containing custom Nginx
Insight rules.
groups:
- name: Templates/Applications
items: []
discovery_rules:
- name: 'Insight: Log de Acesso'
type: ZABBIX_ACTIVE
key: nginx.access.logs.list
delay: 1s
enabled_lifetime_type: DISABLE_AFTER
enabled_lifetime: 1h
item_prototypes:
- name: 'Insight: Acesso {#HOST_SITE}'
type: ZABBIX_ACTIVE
key: log[/var/log/nginx/{#HOST_SITE}.access.log]
delay: 1s
history: 91d
value_type: LOG
timeout: 120s
tags:
- tag: Insight
value: access log
- name: 'Insight: Bad-Bot {#HOST_SITE}'
type: ZABBIX_ACTIVE
key: log[/var/log/nginx/{#HOST_SITE}.bad-bot.log]
delay: 1s
value_type: LOG
timeout: 120s
tags:
- tag: Insight
value: bad-bot
- name: 'Insight: Erros {#HOST_SITE}'
type: ZABBIX_ACTIVE
key: log[/var/log/nginx/{#HOST_SITE}.error.log]
delay: 1s
value_type: LOG
timeout: 120s
tags:
- tag: Insight
value: error log
- name: 'Nginx: Cache HITs Flag for {#HOST_SITE}'
type: DEPENDENT
key: nginx.cache.hit.flag.[{#HOST_SITE}]
preprocessing:
- type: REGEX
parameters:
- upstream_cache_status":"HIT"
- '1'
error_handler: CUSTOM_VALUE
error_handler_params: '0'
master_item:
key: log[/var/log/nginx/{#HOST_SITE}.access.log]
tags:
- tag: Insight
value: performance
- name: 'Insight: Cache Hit Ratio (Ultimo 1m) (%) {#HOST_SITE}'
type: CALCULATED
key: nginx.cache.hit.ratio.1m.[{#HOST_SITE}]
value_type: FLOAT
units: '%'
params: (last(//nginx.cache.hits.1m.[{#HOST_SITE}]) * 100) / (last(//nginx.cache.hits.1m.[{#HOST_SITE}])
+ last(//nginx.cache.miss.1m.[{#HOST_SITE}]) + (last(//nginx.cache.hits.1m.[{#HOST_SITE}])
+ last(//nginx.cache.miss.1m.[{#HOST_SITE}]) = 0))
tags:
- tag: Insight
value: carga
- name: 'Insight: Cache HITs no Ultimo minuto {#HOST_SITE}'
type: CALCULATED
key: nginx.cache.hits.1m.[{#HOST_SITE}]
units: hits
params: sum(//nginx.cache.hit.flag.[{#HOST_SITE}],1m)
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Insight: Cache HITs nos Ultimos 5 minuto {#HOST_SITE}'
type: CALCULATED
key: nginx.cache.hits.5m.[{#HOST_SITE}]
delay: 4m
units: hits
params: sum(//nginx.cache.hit.flag.[{#HOST_SITE}],5m)
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Insight: Cache HITs nos Ultimos 15 minuto {#HOST_SITE}'
type: CALCULATED
key: nginx.cache.hits.15m.[{#HOST_SITE}]
delay: 14m
units: hits
params: sum(//nginx.cache.hit.flag.[{#HOST_SITE}],15m)
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Insight: Cache HITs nos Ultimos 24 hrs {#HOST_SITE}'
type: CALCULATED
key: nginx.cache.hits.24h.[{#HOST_SITE}]
delay: 1h
units: hits
params: sum(//nginx.cache.hit.flag.[{#HOST_SITE}],24h)
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Insight: Cache MISS no Ultimo minuto {#HOST_SITE}'
type: CALCULATED
key: nginx.cache.miss.1m.[{#HOST_SITE}]
units: miss
params: sum(//nginx.cache.miss.flag.[{#HOST_SITE}],1m)
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Insight: Cache MISS no Ultimos 5 minuto {#HOST_SITE}'
type: CALCULATED
key: nginx.cache.miss.5m.[{#HOST_SITE}]
delay: 4m
units: miss
params: sum(//nginx.cache.miss.flag.[{#HOST_SITE}],5m)
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Insight: Cache MISS no Ultimos 15 minuto {#HOST_SITE}'
type: CALCULATED
key: nginx.cache.miss.15m.[{#HOST_SITE}]
delay: 14m
units: miss
params: sum(//nginx.cache.miss.flag.[{#HOST_SITE}],15m)
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Insight: Cache MISS no Ultimos 24 horas {#HOST_SITE}'
type: CALCULATED
key: nginx.cache.miss.24h.[{#HOST_SITE}]
delay: 1h
units: miss
params: sum(//nginx.cache.miss.flag.[{#HOST_SITE}],24h)
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Nginx: Cache MISS Flag for {#HOST_SITE}'
type: DEPENDENT
key: nginx.cache.miss.flag.[{#HOST_SITE}]
preprocessing:
- type: REGEX
parameters:
- upstream_cache_status":"MISS"
- '1'
error_handler: DISCARD_VALUE
master_item:
key: log[/var/log/nginx/{#HOST_SITE}.access.log]
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Insight: Cache Miss Ratio (Ultimo 1m) (%) {#HOST_SITE}'
type: CALCULATED
key: nginx.cache.miss.ratio.1m.[{#HOST_SITE}]
value_type: FLOAT
units: '%'
params: (last(//nginx.cache.miss.1m.[{#HOST_SITE}]) * 100) / (last(//nginx.cache.hits.1m.[{#HOST_SITE}])
+ last(//nginx.cache.miss.1m.[{#HOST_SITE}]) + (last(//nginx.cache.hits.1m.[{#HOST_SITE}])
+ last(//nginx.cache.miss.1m.[{#HOST_SITE}]) = 0))
tags:
- tag: Insight
value: carga
- name: 'Insight: {#HOST_SITE} Marcações Usuario Online'
type: DEPENDENT
key: nginx.log.user_status.list[{#HOST_SITE}}]
value_type: TEXT
preprocessing:
- type: JAVASCRIPT
parameters:
- "// Versão compatível com JavaScript antigo (ES5) - Saída em Texto Puro\n\
\ // Usamos um objeto para garantir que cada usuário seja único.\n\
\ var uniqueUsers = {};\n\n var remoteUserRegex = /\"remote_user\"\
:\"([a-zA-Z0-9._-]+)\"/g;\n var cookieUserRegex = /nc_username=([a-zA-Z0-9._-]+);/g;\n\
\ var urlUserRegex = /\\/remote\\.php\\/dav\\/files\\/([a-zA-Z0-9._-]+)\\\
//g;\n\n var lines = value.split('\\n');\n\n for (var i = 0; i <\
\ lines.length; i++) {\n var line = lines[i];\n var match;\n\
\n // Função auxiliar para adicionar usuários ao nosso objeto de\
\ unicidade\n function findAndAdd(regex) {\n while ((match\
\ = regex.exec(line)) !== null) {\n if (match[1] && match[1].length\
\ > 0) {\n // Adiciona o usuário completo como uma\
\ chave do objeto.\n uniqueUsers[match[1]] = true;\n\
\ }\n }\n }\n \n findAndAdd(remoteUserRegex);\n\
\ findAndAdd(cookieUserRegex);\n findAndAdd(urlUserRegex);\n\
\ }\n\n // Pega todas as chaves do objeto para formar o array final\
\ de usuários únicos.\n var userArray = Object.keys(uniqueUsers);\n\
\n // --- LINHA ALTERADA ---\n // Une todos os elementos do array\
\ em uma única string,\n // separando cada um com um caractere de quebra\
\ de linha ('\\n').\n return userArray.join('\\n');\n"
master_item:
key: log[/var/log/nginx/{#HOST_SITE}.access.log]
tags:
- tag: Insight
value: performance
- name: 'Nginx: Requests Excelentes por minuto {#HOST_SITE}'
type: CALCULATED
key: nginx.requests.excellent.count.1m.[{#HOST_SITE}]
units: reqs/min
params: "last(//nginx.request_time.count.0-20ms.1m.[{#HOST_SITE}]) + \nlast(//nginx.request_time.count.21-50ms.1m.[{#HOST_SITE}])\
\ + \nlast(//nginx.request_time.count.51-100ms.1m.[{#HOST_SITE}]) + \nlast(//nginx.request_time.count.101-200ms.1m.[{#HOST_SITE}])\n"
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Insight: Requisição nos Ultimos 5 Minuto em {#HOST_SITE}'
type: CALCULATED
key: nginx.requests.per_5minute[{#HOST_SITE}]
delay: 4m
units: requests
params: count(//log[/var/log/nginx/{#HOST_SITE}.access.log],5m)
tags:
- tag: Insight
value: carga
- name: 'Insight: Requisição nos Ultimos 15 Minuto em {#HOST_SITE}'
type: CALCULATED
key: nginx.requests.per_15minute[{#HOST_SITE}]
delay: 14m
units: requests
params: count(//log[/var/log/nginx/{#HOST_SITE}.access.log],15m)
tags:
- tag: Insight
value: carga
- name: 'Insight: Requisição nos Ultimos 24 horas em {#HOST_SITE}'
type: CALCULATED
key: nginx.requests.per_24h[{#HOST_SITE}]
delay: 1h
units: requests
params: count(//log[/var/log/nginx/{#HOST_SITE}.access.log],24h)
tags:
- tag: Insight
value: carga
- name: 'Insight: Requisição no Ultimo 1 Minuto em {#HOST_SITE}'
type: CALCULATED
key: nginx.requests.per_minute[{#HOST_SITE}]
units: requests
params: count(//log[/var/log/nginx/{#HOST_SITE}.access.log],1m)
tags:
- tag: Insight
value: carga
- name: 'Insight: Média de Tempo de Resposta (1m) {#HOST_SITE}'
type: CALCULATED
key: nginx.request_time.avg.1m.[{#HOST_SITE}]
value_type: FLOAT
units: ms
params: avg(//nginx.request_time.[{#HOST_SITE}],1m)
tags:
- tag: Insight
value: carga
- name: 'Insight: Média de Tempo de Resposta (5m) {#HOST_SITE}'
type: CALCULATED
key: nginx.request_time.avg.5m.[{#HOST_SITE}]
delay: 4m
value_type: FLOAT
units: ms
params: avg(//nginx.request_time.[{#HOST_SITE}],5m)
tags:
- tag: Insight
value: carga
- name: 'Insight: Média de Tempo de Resposta (15m) {#HOST_SITE}'
type: CALCULATED
key: nginx.request_time.avg.15m.[{#HOST_SITE}]
value_type: FLOAT
units: ms
params: avg(//nginx.request_time.[{#HOST_SITE}],15m)
tags:
- tag: Insight
value: carga
- name: 'Nginx: RTime Flag (0-20ms) {#HOST_SITE}'
type: DEPENDENT
key: nginx.request_time.flag.0-20ms.[{#HOST_SITE}]
preprocessing:
- type: JAVASCRIPT
parameters:
- "try {\n // O valor chega em segundos (ex: 0.015), convertemos para\
\ milissegundos.\n var value_ms = parseFloat(value) * 1000;\n\n \
\ // Verifica se o valor está na faixa de 0 a 20ms.\n if (value_ms\
\ >= 0 && value_ms <= 20) {\n return 1;\n }\n\n // Se não\
\ estiver na faixa, retorna null para o Zabbix descartar.\n return\
\ 0;\n} catch (e) {\n // Se der qualquer erro, também descarta.\n \
\ return 0;\n}\n"
master_item:
key: nginx.request_time.[{#HOST_SITE}]
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Nginx: RTime Flag (21-50ms) {#HOST_SITE}'
type: DEPENDENT
key: nginx.request_time.flag.21-50ms.[{#HOST_SITE}]
preprocessing:
- type: JAVASCRIPT
parameters:
- "try {\n // O valor chega em segundos (ex: 0.015), convertemos para\
\ milissegundos.\n var value_ms = parseFloat(value) * 1000;\n\n \
\ // Verifica se o valor está na faixa de 0 a 20ms.\n if (value_ms\
\ >= 21 && value_ms <= 50) {\n return 1;\n }\n\n // Se não\
\ estiver na faixa, retorna null para o Zabbix descartar.\n return\
\ 0;\n} catch (e) {\n // Se der qualquer erro, também descarta.\n \
\ return 0;\n}\n"
master_item:
key: nginx.request_time.[{#HOST_SITE}]
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Nginx: RTime Flag (51-100ms) {#HOST_SITE}'
type: DEPENDENT
key: nginx.request_time.flag.51-100ms.[{#HOST_SITE}]
preprocessing:
- type: JAVASCRIPT
parameters:
- "try {\n // O valor chega em segundos (ex: 0.015), convertemos para\
\ milissegundos.\n var value_ms = parseFloat(value) * 1000;\n\n \
\ // Verifica se o valor está na faixa de 0 a 20ms.\n if (value_ms\
\ >= 51 && value_ms <= 100) {\n return 1;\n }\n\n // Se não\
\ estiver na faixa, retorna null para o Zabbix descartar.\n return\
\ 0;\n} catch (e) {\n // Se der qualquer erro, também descarta.\n \
\ return 0;\n}\n"
master_item:
key: nginx.request_time.[{#HOST_SITE}]
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Nginx: RTime Flag (201-300ms) {#HOST_SITE}'
type: DEPENDENT
key: nginx.request_time.flag.201-300ms.[{#HOST_SITE}]
preprocessing:
- type: JAVASCRIPT
parameters:
- "try {\n // O valor chega em segundos (ex: 0.015), convertemos para\
\ milissegundos.\n var value_ms = parseFloat(value) * 1000;\n\n \
\ // Verifica se o valor está na faixa de 0 a 20ms.\n if (value_ms\
\ >= 201 && value_ms <= 300) {\n return 1;\n }\n\n // Se\
\ não estiver na faixa, retorna null para o Zabbix descartar.\n return\
\ 0;\n} catch (e) {\n // Se der qualquer erro, também descarta.\n \
\ return 0;\n}\n"
master_item:
key: nginx.request_time.[{#HOST_SITE}]
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Nginx: RTime Flag (301-400ms) {#HOST_SITE}'
type: DEPENDENT
key: nginx.request_time.flag.301-400ms.[{#HOST_SITE}]
preprocessing:
- type: JAVASCRIPT
parameters:
- "try {\n // O valor chega em segundos (ex: 0.015), convertemos para\
\ milissegundos.\n var value_ms = parseFloat(value) * 1000;\n\n \
\ // Verifica se o valor está na faixa de 0 a 20ms.\n if (value_ms\
\ >= 301 && value_ms <= 400) {\n return 1;\n }\n\n // Se\
\ não estiver na faixa, retorna null para o Zabbix descartar.\n return\
\ 0;\n} catch (e) {\n // Se der qualquer erro, também descarta.\n \
\ return 0;\n}\n"
master_item:
key: nginx.request_time.[{#HOST_SITE}]
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Nginx: RTime Flag (401-500ms) {#HOST_SITE}'
type: DEPENDENT
key: nginx.request_time.flag.401-500ms.[{#HOST_SITE}]
preprocessing:
- type: JAVASCRIPT
parameters:
- "try {\n // O valor chega em segundos (ex: 0.015), convertemos para\
\ milissegundos.\n var value_ms = parseFloat(value) * 1000;\n\n \
\ // Verifica se o valor está na faixa de 0 a 20ms.\n if (value_ms\
\ >= 401 && value_ms <= 500) {\n return 1;\n }\n\n // Se\
\ não estiver na faixa, retorna null para o Zabbix descartar.\n return\
\ 0;\n} catch (e) {\n // Se der qualquer erro, também descarta.\n \
\ return 0;\n}\n"
master_item:
key: nginx.request_time.[{#HOST_SITE}]
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Nginx: RTime Flag (501-600ms) {#HOST_SITE}'
type: DEPENDENT
key: nginx.request_time.flag.501-600ms.[{#HOST_SITE}]
preprocessing:
- type: JAVASCRIPT
parameters:
- "try {\n // O valor chega em segundos (ex: 0.015), convertemos para\
\ milissegundos.\n var value_ms = parseFloat(value) * 1000;\n\n \
\ // Verifica se o valor está na faixa de 0 a 20ms.\n if (value_ms\
\ >= 501 && value_ms <= 600) {\n return 1;\n }\n\n // Se\
\ não estiver na faixa, retorna null para o Zabbix descartar.\n return\
\ 0;\n} catch (e) {\n // Se der qualquer erro, também descarta.\n \
\ return 0;\n}\n"
master_item:
key: nginx.request_time.[{#HOST_SITE}]
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Nginx: RTime Flag (601-700ms) {#HOST_SITE}'
type: DEPENDENT
key: nginx.request_time.flag.601-700ms.[{#HOST_SITE}]
preprocessing:
- type: JAVASCRIPT
parameters:
- "try {\n // O valor chega em segundos (ex: 0.015), convertemos para\
\ milissegundos.\n var value_ms = parseFloat(value) * 1000;\n\n \
\ // Verifica se o valor está na faixa de 0 a 20ms.\n if (value_ms\
\ >= 601 && value_ms <= 700) {\n return 1;\n }\n\n // Se\
\ não estiver na faixa, retorna null para o Zabbix descartar.\n return\
\ 0;\n} catch (e) {\n // Se der qualquer erro, também descarta.\n \
\ return 0;\n}\n"
master_item:
key: nginx.request_time.[{#HOST_SITE}]
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Nginx: RTime Flag (701-800ms) {#HOST_SITE}'
type: DEPENDENT
key: nginx.request_time.flag.701-800ms.[{#HOST_SITE}]
preprocessing:
- type: JAVASCRIPT
parameters:
- "try {\n // O valor chega em segundos (ex: 0.015), convertemos para\
\ milissegundos.\n var value_ms = parseFloat(value) * 1000;\n\n \
\ // Verifica se o valor está na faixa de 0 a 20ms.\n if (value_ms\
\ >= 701 && value_ms <= 800) {\n return 1;\n }\n\n // Se\
\ não estiver na faixa, retorna null para o Zabbix descartar.\n return\
\ 0;\n} catch (e) {\n // Se der qualquer erro, também descarta.\n \
\ return 0;\n}\n"
master_item:
key: nginx.request_time.[{#HOST_SITE}]
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Nginx: RTime Flag (801-900ms) {#HOST_SITE}'
type: DEPENDENT
key: nginx.request_time.flag.801-900ms.[{#HOST_SITE}]
preprocessing:
- type: JAVASCRIPT
parameters:
- "try {\n // O valor chega em segundos (ex: 0.015), convertemos para\
\ milissegundos.\n var value_ms = parseFloat(value) * 1000;\n\n \
\ // Verifica se o valor está na faixa de 0 a 20ms.\n if (value_ms\
\ >= 801 && value_ms <= 900) {\n return 1;\n }\n\n // Se\
\ não estiver na faixa, retorna null para o Zabbix descartar.\n return\
\ 0;\n} catch (e) {\n // Se der qualquer erro, também descarta.\n \
\ return 0;\n}\n"
master_item:
key: nginx.request_time.[{#HOST_SITE}]
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Nginx: RTime Flag (1001-2000ms) {#HOST_SITE}'
type: DEPENDENT
key: nginx.request_time.flag.1001-2000ms.[{#HOST_SITE}]
preprocessing:
- type: JAVASCRIPT
parameters:
- "try {\n // O valor chega em segundos (ex: 0.015), convertemos para\
\ milissegundos.\n var value_ms = parseFloat(value) * 1000;\n\n \
\ // Verifica se o valor está na faixa de 0 a 20ms.\n if (value_ms\
\ >= 1001 && value_ms <= 2000) {\n return 1;\n }\n\n // Se\
\ não estiver na faixa, retorna null para o Zabbix descartar.\n return\
\ 0;\n} catch (e) {\n // Se der qualquer erro, também descarta.\n \
\ return 0;\n}\n"
master_item:
key: nginx.request_time.[{#HOST_SITE}]
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Nginx: RTime Flag (>3001ms) {#HOST_SITE}'
type: DEPENDENT
key: nginx.request_time.flag.3001ms.[{#HOST_SITE}]
preprocessing:
- type: JAVASCRIPT
parameters:
- "try {\n // O valor chega em segundos (ex: 0.015), convertemos para\
\ milissegundos.\n var value_ms = parseFloat(value) * 1000;\n\n \
\ // Verifica se o valor está na faixa de 0 a 20ms.\n if (value_ms\
\ >= 3001) {\n return 1;\n }\n\n // Se não estiver na faixa,\
\ retorna null para o Zabbix descartar.\n return 0;\n} catch (e) {\n\
\ // Se der qualquer erro, também descarta.\n return 0;\n}\n"
master_item:
key: nginx.request_time.[{#HOST_SITE}]
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Insight: Tempo de Resposta Total {#HOST_SITE}'
type: DEPENDENT
key: nginx.request_time.[{#HOST_SITE}]
value_type: FLOAT
units: s
preprocessing:
- type: JAVASCRIPT
parameters:
- "try {\n // A variável 'value' contém a linha de log completa.\n \
\ // A regex procura por \"request_time\": e captura o número que vem\
\ depois.\n var regex = /\"request_time\":(\\d+\\.?\\d*)/;\n var\
\ match = value.match(regex);\n\n // Se encontrar, match[1] conterá\
\ apenas o número (ex: \"0.282\").\n if (match && match[1]) {\n \
\ return match[1];\n }\n\n // Se não encontrar, descarta o valor.\n\
\ return null;\n} catch (e) {\n // Se houver qualquer erro, também\
\ descarta.\n return null;\n}\n"
master_item:
key: log[/var/log/nginx/{#HOST_SITE}.access.log]
tags:
- tag: Insight
value: access log
- name: 'Nginx: URI da Requisição {#HOST_SITE}'
type: DEPENDENT
key: nginx.request_uri.[{#HOST_SITE}]
value_type: TEXT
preprocessing:
- type: JAVASCRIPT
parameters:
- "try {\n var regex = /\"request_uri\":\"([^\"]+)\"/;\n var match\
\ = value.match(regex);\n if (match && match[1]) {\n return\
\ match[1];\n }\n return null;\n} catch (e) {\n return null;\n\
}\n"
master_item:
key: log[/var/log/nginx/{#HOST_SITE}.access.log]
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
graph_prototypes:
- name: 'Insight: Cache HITS {#HOST_SITE}'
yaxismax: '0'
percent_right: '20'
ymin_type_1: FIXED
graph_items:
- color: 199C0D
calc_fnc: ALL
item:
host: srvproxy001
key: nginx.cache.hits.5m.[{#HOST_SITE}]
- sortorder: '1'
color: F63100
calc_fnc: ALL
item:
host: srvproxy001
key: nginx.cache.hits.15m.[{#HOST_SITE}]
- sortorder: '2'
color: 2774A4
calc_fnc: ALL
item:
host: srvproxy001
key: nginx.cache.hits.24h.[{#HOST_SITE}]
- sortorder: '3'
color: F7941D
calc_fnc: ALL
item:
host: srvproxy001
key: nginx.cache.hits.1m.[{#HOST_SITE}]
- name: 'Insight: Cache HIT vs MISS {#HOST_SITE}'
show_work_period: 'NO'
show_triggers: 'NO'
type: PIE
graph_items:
- color: F63100
item:
host: srvproxy001
key: nginx.cache.miss.ratio.1m.[{#HOST_SITE}]
- sortorder: '1'
color: 199C0D
item:
host: srvproxy001
key: nginx.cache.hit.ratio.1m.[{#HOST_SITE}]
- name: 'Insight: Cache MISS {#HOST_SITE}'
yaxismax: '0'
percent_right: '20'
ymin_type_1: FIXED
graph_items:
- color: 199C0D
calc_fnc: ALL
item:
host: srvproxy001
key: nginx.cache.miss.1m.[{#HOST_SITE}]
- sortorder: '1'
color: F63100
calc_fnc: ALL
item:
host: srvproxy001
key: nginx.cache.miss.5m.[{#HOST_SITE}]
- sortorder: '2'
color: 2774A4
calc_fnc: ALL
item:
host: srvproxy001
key: nginx.cache.miss.15m.[{#HOST_SITE}]
- sortorder: '3'
color: F7941D
calc_fnc: ALL
item:
host: srvproxy001
key: nginx.cache.miss.24h.[{#HOST_SITE}]
- name: 'Insight: Requisições {#HOST_SITE}'
yaxismax: '0'
ymin_type_1: FIXED
graph_items:
- color: F63100
yaxisside: RIGHT
calc_fnc: ALL
item:
host: srvproxy001
key: nginx.requests.per_minute[{#HOST_SITE}]
- sortorder: '1'
color: 199C0D
calc_fnc: ALL
item:
host: srvproxy001
key: nginx.requests.per_5minute[{#HOST_SITE}]
- sortorder: '2'
color: 2774A4
calc_fnc: ALL
item:
host: srvproxy001
key: nginx.requests.per_15minute[{#HOST_SITE}]
- sortorder: '3'
color: F7941D
calc_fnc: ALL
item:
host: srvproxy001
key: nginx.requests.per_24h[{#HOST_SITE}]
- name: 'Insight: Saúde do Site {#HOST_SITE}'
show_work_period: 'NO'
graph_items:
- color: 199C0D
calc_fnc: ALL
item:
host: srvproxy001
key: net.tcp.service[http,"{$NGINX.STUB_STATUS.HOST}","{$NGINX.STUB_STATUS.PORT}"]
- sortorder: '1'
color: F63100
calc_fnc: ALL
item:
host: srvproxy001
key: nginx.cache.hit.ratio.1m.[{#HOST_SITE}]
- sortorder: '2'
color: F7941D
calc_fnc: ALL
item:
host: srvproxy001
key: nginx.request_time.avg.1m.[{#HOST_SITE}]
- name: 'Insight: Tempo de Resposta vs Requisições {#HOST_SITE}'
ymin_type_1: FIXED
graph_items:
- sortorder: '1'
color: F63100
yaxisside: RIGHT
calc_fnc: ALL
item:
host: srvproxy001
key: nginx.requests.per_minute[{#HOST_SITE}]
- sortorder: '2'
drawtype: FILLED_REGION
color: 199C0D
calc_fnc: ALL
item:
host: srvproxy001
key: nginx.request_time.[{#HOST_SITE}]
- name: 'Insight: Tempos de Resposta {#HOST_SITE}'
percent_right: '20'
ymin_type_1: FIXED
graph_items:
- color: 199C0D
calc_fnc: ALL
item:
host: srvproxy001
key: nginx.request_time.avg.1m.[{#HOST_SITE}]
- sortorder: '1'
color: F63100
calc_fnc: ALL
item:
host: srvproxy001
key: nginx.request_time.avg.5m.[{#HOST_SITE}]
- sortorder: '2'
color: 2774A4
calc_fnc: ALL
item:
host: srvproxy001
key: nginx.request_time.avg.15m.[{#HOST_SITE}]
preprocessing:
- type: JAVASCRIPT
parameters:
- "// A variável 'value' é a string completa do UserParameter, contendo caminhos\n\
// separados por vírgula, espaço e/ou quebra de linha.\n // A Regex /[\\\
s,]+/ divide a string em:\n // - Vírgulas (,)\n // - Espaços (incluindo\
\ múltiplos)\n // - Quebras de linha (\\n, \\r)\n // O filter(Boolean)\
\ remove quaisquer entradas vazias que o split possa gerar.\n var full_paths\
\ = value.trim().split(/[\\s,]+/).filter(Boolean);\n \n var lld_data\
\ = [];\n \n // Regex para extrair o nome do site:\n // ^ -> Início\
\ do item (após o split)\n // (.+) -> Captura o nome do site (o que for\
\ que esteja lá)\n var regex = /^\\/var\\/log\\/nginx\\/(.+)\\.access\\\
.log$/;\n \n // Itera sobre todos os caminhos.\n for (var i = 0;\
\ i < full_paths.length; i++) {\n var path = full_paths[i];\n \
\ \n // Aplica a regex em cada item.\n var match = path.match(regex);\n\
\ \n // match[1] contém o nome do site capturado em (.+).\n\
\ if (match && match[1]) { \n lld_data.push({\n \
\ \"{#HOST_SITE}\": match[1]\n });\n }\n }\n\
\ \n // Retorna o JSON LLD final.\n return JSON.stringify({ \"\
data\": lld_data });\n"

View File

@ -0,0 +1,75 @@
# Protocolo de Execução AI: Nginx Intelligence Suite (Clean Version)
**Destino:** `templates_gold/nginx_agent/`
**Objetivo:** Instruções diretivas para geração de código Zabbix 7.0 YAML.
---
## 🏗️ 1. Definição de Artefatos
O Agente deve gerar exatamente **três arquivos** com as especificações abaixo.
### 1.1 `template_nginx_manager_gold.yaml`
**Função:** Monitoramento do Serviço Global (Pad), Discovery de Sites e Auditoria de Config.
**Grupo:** `Templates/Applications`
| Item Key | Tipo | Trigger/Lógica |
| :--- | :--- | :--- |
| `nginx.workers.utilization` | Calculated | `(Active Conn / (Workers * Limit)) * 100`. Alerta > 80%. |
| `proc.num[nginx,files_open]` | Agent | Trigger se próximo do `ulimit -n` do sistema. |
| `nginx.uptime` | Agent | Trigger "Reload Storm" se uptime resetar > 3x/hora. |
| `proc.cpu.util[nginx,user/system]` | Agent | Monitorar overhead de sistema (Context Switch). |
| `nginx.requests.400` | Simple Check | Spike Detection (Indício de Fuzzing/Exploit). |
| `vfs.file.cksum[/etc/nginx/nginx.conf]` | Agent | Trigger "Global Config Changed". |
| `system.run[nginx -t 2>&1]` | Agent | Trigger "Configuração Inválida" (Retorno != successful). |
| **Discovery Rules:** | | |
| `nginx.site.discovery` | Script/UserParam | Lista arquivos em `/etc/nginx/sites-enabled/`. Cria Hosts. |
| `nginx.compliance.audit` | `vfs.file.regexp` | Valida regras do `nginx_best_practices.md` em cada .conf. |
### 1.2 `template_nginx_site_satellite_gold.yaml`
**Função:** Monitoramento detalhado por Site (Virtual Host). Vinculado via Discovery do Manager.
**Grupo:** `Templates/Nginx Satellites`
#### A. Log Analytics (Passivo)
**Item Mestre:** `log[{#SITE_LOG}]` (Type: Zabbix Active, Format: JSON).
| Feature | Métricas Derivadas (Dependent Items) |
| :--- | :--- |
| **Performance** | `request_time`, `upstream_response_time`, `hits`, `bytes_sent`. |
| **Marketing** | Conversão Funil (`{$MATCH_START}` vs `{$MATCH_GOAL}`), Top Browsers. |
| **Segurança** | Hits em Honeytokens (`/admin.bak`), WAF Blocks, Data Leak (>Avg Bytes). |
| **Forensics** | Cache Status (HIT/MISS), GeoIP. |
#### B. Web Scenarios (Ativo)
**Conceito:** O Zabbix Agent (ou Server) acessa a URL externamente.
1. **Health Check:** GET `http://{#SITE_NAME}/`. Espera CODE=200 e String="html".
2. **Security Probe:** GET `http://{#SITE_NAME}/.env`. Espera CODE=403/404. Se 200 => CRITICAL.
#### C. Route Discovery (Crawler)
**Regra LLD:** `nginx.route.discovery[{#SITE_CONF}]`.
**Lógica:** Regex que extrai `location /path {` do arquivo de config.
**Protótipos:**
1. **Log Check:** % Erro 5xx na rota específica.
2. **Web Check:** `web.page.get` na rota para validar disponibilidade.
### 1.3 `deploy_instructions.md`
**Conteúdo Obrigatório:**
1. **Log Format:** O snippet exato do `log_format structured_json` para colocar no `nginx.conf`.
2. **UserParameters:** Os comandos bash para descoberta de sites e rotas.
3. **Permissões:** Comandos `chmod/chown` para garantir leitura dos logs (`adm` group).
4. **Macros:** Lista de macros obrigatórias (`{$NGINX.LOG.PATH}`, etc).
---
## 🧪 2. Validação & Gold Standard
O código gerado **DEVE** obedecer:
1. **Nomes em PT-BR:** "Latência do Backend" (Não "Upstream Time").
2. **Descrições Ricas:** Explicar O QUE é e O QUE FAZER na descrição da Trigger.
3. **Tags:** Todo item deve ter Tags (`Component: Security`, `Layer: App`, etc).
4. **UUIDs:** Gerar UUIDs v4 estáticos para evitar duplicação na importação.
5. **Sem Scripts Externos desnecessários:** Usar funcionalidades nativas onde possível.
---
**Status:** Pronto para Execução.

View File

@ -0,0 +1,138 @@
import yaml
import uuid
import sys
# Schema based on the user's 'detailed_proxy' log_format
LOG_FIELDS = [
# Group, Key, Type, Description, JSONPath
("Timestamps", "timestamp", "TEXT", "Time ISO8601", "$.@timestamp"),
("Timestamps", "request_id", "TEXT", "Unique Request ID", "$.request_id"),
("Network", "remote_addr", "TEXT", "Client IP", "$.remote_addr"),
("Network", "real_ip", "TEXT", "Real IP (X-Forwarded-For)", "$.real_ip"),
("Network", "remote_user", "TEXT", "Authenticated User", "$.remote_user"),
("Request", "request_method", "TEXT", "HTTP Method", "$.request_method"),
("Request", "host_header", "TEXT", "Host Header", "$.host_header"),
("Request", "uri", "TEXT", "URI", "$.uri"),
("Request", "request_length", "UNSIGNED", "Request Length (bytes)", "$.request_length"),
("Response", "status", "UNSIGNED", "HTTP Status Code", "$.status"),
("Response", "body_bytes_sent", "UNSIGNED", "Body Bytes Sent", "$.body_bytes_sent"),
("Response", "bytes_sent", "UNSIGNED", "Total Bytes Sent", "$.bytes_sent"),
("Performance", "request_time", "FLOAT", "Request Time (Total)", "$.request_time"),
("Performance", "upstream_connect_time", "FLOAT", "Upstream Connect Time", "$.upstream_connect_time"),
("Performance", "upstream_header_time", "FLOAT", "Upstream Header Time", "$.upstream_header_time"),
("Performance", "upstream_response_time", "FLOAT", "Upstream Response Time", "$.upstream_response_time"),
("Performance", "upstream_cache_status", "TEXT", "Cache Status", "$.upstream_cache_status"),
("GeoIP", "geoip_country_code", "TEXT", "GeoIP Country Code", "$.geoip_country_code"),
("GeoIP", "geoip_city_name", "TEXT", "GeoIP City Name", "$.geoip_city_name"),
("GeoIP", "geoip_isp", "TEXT", "GeoIP ISP", "$.geoip_isp"),
("Security", "is_bad_bot", "TEXT", "Bad Bot Flag", "$.is_bad_bot"),
("Security", "block_request", "TEXT", "WAF Block Flag", "$.block_request"),
("Security", "ssl_protocol", "TEXT", "SSL Protocol", "$.ssl_protocol"),
("Security", "ssl_cipher", "TEXT", "SSL Cipher", "$.ssl_cipher"),
]
def generate_satellite_template(output_file):
template_uuid = "sat00000-0000-0000-0000-000000000001" # Fixed UUID for consistency
group_uuid = "7df96b18c230490a9a0a9e2307226338" # Templates/Applications group
items = []
# MASTER ITEM
# We assume the host is the site itself, so we might need a macro for the log path or
# assume a standard path based on the host name.
# The user said: "encontrar todos os arquivos .conf... e usar este nome para criar um novo host"
# And "o caminho sempre vai ser o padrao".
# We will use {$NGINX.SITE.LOG} macro which will be populated by the Discovery rule on the Manager level.
master_item_uuid = str(uuid.uuid4())
master_item = {
'uuid': master_item_uuid,
'name': 'Access Log Stream',
'type': 'ZABBIX_ACTIVE',
'key': 'log[{$NGINX.SITE.LOG}]',
'delay': '1s',
'value_type': 'LOG',
'history': '7d',
'tags': [{'tag': 'component', 'value': 'log_stream'}]
}
items.append(master_item)
# DEPENDENT ITEMS
for group, key_suffix, value_type, desc, path in LOG_FIELDS:
# Some items might be strings in JSON but we want Numbers in Zabbix
# If value_type is FLOAT/UNSIGNED, we should ensure preprocessing handles it correctly.
# Determine strict type
zabbix_type = 'TEXT'
if value_type == 'FLOAT':
zabbix_type = 'FLOAT'
elif value_type == 'UNSIGNED':
zabbix_type = 'FLOAT' # Use Float for safety with numbers, standardizing
item = {
'uuid': str(uuid.uuid4()),
'name': f'Nginx Site: {desc}',
'type': 'DEPENDENT',
'key': f'nginx.site.{key_suffix}',
'delay': '0',
'value_type': zabbix_type,
'description': desc,
'history': '30d',
'preprocessing': [
{
'type': 'JSONPATH',
'parameters': [path],
'error_handler': 'DISCARD_VALUE' # Discard if field missing
}
],
'master_item': {'key': master_item['key']},
'tags': [{'tag': 'component', 'value': group.lower()}]
}
items.append(item)
# Add calculated/special items (Trigger-based)
# Example: Cache Hit Ratio calculation is best done in Grafana or via Calculated Item if we have aggregate data.
# Since these are log-based, 'DEPENDENT' items are per-line.
# To get "Ratio per minute", we need aggregate items (Calculated from Discovery rules on the Manager, OR separate calculated items here).
# BUT, dependent items only fire on each log line. You can't calculate "Ratio of last minute" easily from a stream of dependent items without using "Trend/History" functions in Calculated Items.
# We will add simple Calculated Items for Stats.
# 5XX Errors Rate
items.append({
'uuid': str(uuid.uuid4()),
'name': 'Nginx Site: HTTP 5xx Rate',
'type': 'CALCULATED',
'key': 'nginx.site.status.5xx.rate',
'params': 'count(//nginx.site.status, 1m, "ge", 500)',
'value_type': 'FLOAT',
'units': 'rps',
'delay': '1m',
'tags': [{'tag': 'component', 'value': 'availability'}]
})
template = {
'zabbix_export': {
'version': '7.0',
'template_groups': [{'uuid': group_uuid, 'name': 'Templates/Applications'}],
'templates': [{
'uuid': template_uuid,
'template': 'Template Nginx Custom Site Analysis',
'name': 'Template Nginx Custom Site Analysis',
'description': 'Analyzes JSON logs for a specific Nginx site host.',
'groups': [{'name': 'Templates/Applications'}],
'items': items,
}]
}
}
with open(output_file, 'w', encoding='utf-8') as f:
yaml.dump(template, f, sort_keys=False, allow_unicode=True)
print(f"Generated {output_file}")
if __name__ == "__main__":
generate_satellite_template("template_nginx_site_analysis.yaml")

View File

@ -0,0 +1,316 @@
# Guia Definitivo de Configuração e Boas Práticas NGINX
**Autor:** Gemini (AI Specialist)
**Data:** 04 de Janeiro de 2026
**Contexto:** Padrões de segurança, performance e manutenção para infraestrutura web.
---
## 1. Princípios Fundamentais
Antes de qualquer configuração, estas são as regras de ouro que devem ser aplicadas a **todos** os arquivos `.conf`.
### 1.1 Organização e Formatação
* **Sem Snippets:** Evite `include snippets/ssl-params.conf;`. Todas as diretivas devem ser declaradas explicitamente no arquivo do site (`/etc/nginx/sites-available/exemplo.conf`). Isso facilita a auditoria e evita que uma alteração global quebre sites específicos.
* **Cabeçalho Obrigatório:** Todo arquivo deve começar com comentários explicando o propósito, autor e data da última alteração.
* **Indentação:** Use 4 espaços (ou consistência total com tabs). Nunca misture.
* **Comentários:** Use comentários para separar blocos lógicos (`# Segurança`, `# Cache`, `# Upstream`).
### 1.2 Logs e Auditoria
* **Isolamento:** Cada site/app deve ter seus próprios logs. Nunca use o `access.log` global.
* **Caminho:** `/var/log/nginx/dominio_access.log` e `/var/log/nginx/dominio_error.log`.
* **Retenção:** Configure o `logrotate` (sistema operacional) para manter 30 dias de histórico e compactar o dia anterior automaticamente (`delaycompress`).
* **Fail2Ban:** As regras do Fail2Ban devem apontar para esses logs exclusivos.
### 1.3 Segurança (SSL/TLS e Headers)
* **Protocolos:** Suporte a TLSv1.2 e TLSv1.3.
* **Compatibilidade Apple:** Garantir ciphers que funcionem bem com dispositivos Apple antigos e novos, sem comprometer a segurança.
* **HSTS:** Sempre habilitar `Strict-Transport-Security` em produção.
* **Ocultação:** `server_tokens off;` para não revelar a versão do NGINX.
---
## 2. Configuração Base (Modelo SSL e Headers)
*Copie e adapte este bloco para dentro de cada `server { ... }` listado nos exemplos abaixo.*
```nginx
# =========================================
# CONFIGURAÇÃO SSL/TLS (Diretiva Direta)
# =========================================
ssl_certificate /caminho/para/certificado/fullchain.pem;
ssl_certificate_key /caminho/para/certificado/privkey.pem;
# Otimização baseada no guia Mozilla/SSLLabs
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
# Performance SSL
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m; # Aprox 40k sessões
ssl_session_tickets off;
# OCSP Stapling (Melhora performance e privacidade)
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 1.1.1.1 valid=300s;
resolver_timeout 5s;
# =========================================
# HEADERS DE SEGURANÇA (Hardening)
# =========================================
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Frame-Options SAMEORIGIN always;
add_header X-Content-Type-Options nosniff always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy no-referrer-when-downgrade always;
# Content-Security-Policy (CSP) deve ser ajustada por aplicação
```
---
## 3. Exemplos de Configuração por Categoria
### 3.1 Site Estático HTML
Foco: Cache agressivo para assets, compressão Gzip/Brotli.
```nginx
server {
listen 443 ssl http2;
server_name www.meusiteestatico.com;
root /var/www/meusiteestatico;
index index.html;
# Logs Exclusivos
access_log /var/log/nginx/meusiteestatico_access.log;
error_log /var/log/nginx/meusiteestatico_error.log;
# [INSERIR AQUI O BLOCO SSL E HEADERS DA SEÇÃO 2]
# Compressão
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
location / {
try_files $uri $uri/ =404;
}
# Cache de Arquivos Estáticos (Longa duração)
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ {
expires 365d;
add_header Cache-Control "public, no-transform";
}
}
```
### 3.2 WordPress / CMS
Foco: Processamento PHP (FastCGI), segurança contra acesso direto a arquivos sensíveis.
```nginx
server {
listen 443 ssl http2;
server_name blog.meusite.com;
root /var/www/wordpress;
index index.php index.html;
# Logs Exclusivos
access_log /var/log/nginx/wordpress_access.log;
error_log /var/log/nginx/wordpress_error.log;
# [INSERIR AQUI O BLOCO SSL E HEADERS DA SEÇÃO 2]
# Segurança WP: Bloquear acesso a arquivos ocultos e uploads de scripts
location ~ /\. { deny all; }
location ~* /(?:uploads|files)/.*\.php$ { deny all; }
location / {
try_files $uri $uri/ /index.php?$args;
}
# Processamento PHP
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass unix:/run/php/php8.2-fpm.sock; # Ajustar versão do PHP
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_intercept_errors on;
}
}
```
### 3.3 Microsoft Exchange Server (Reverse Proxy)
Foco: Headers específicos da MS, timeout alto, suporte a grandes uploads.
```nginx
server {
listen 443 ssl http2;
server_name mail.empresa.com;
# Logs Exclusivos
access_log /var/log/nginx/exchange_access.log;
error_log /var/log/nginx/exchange_error.log;
# [INSERIR AQUI O BLOCO SSL E HEADERS DA SEÇÃO 2]
# Ajustes Exchange
client_max_body_size 2G;
proxy_read_timeout 3600;
proxy_http_version 1.1;
proxy_request_buffering off; # Importante para RPC over HTTP
location / {
proxy_pass https://ip_do_servidor_exchange;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Headers Específicos Exchange
proxy_set_header Front-End-Https On;
}
# Redirecionamento raiz para OWA
location = / {
return 301 https://mail.empresa.com/owa;
}
}
```
### 3.4 Plex Media Server
Foco: Websockets, streaming contínuo, evitar buffering do proxy.
```nginx
server {
listen 443 ssl http2;
server_name plex.meudominio.com;
# Logs Exclusivos
access_log /var/log/nginx/plex_access.log;
error_log /var/log/nginx/plex_error.log;
# [INSERIR AQUI O BLOCO SSL E HEADERS DA SEÇÃO 2]
# Otimização para Streaming
client_max_body_size 100M;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# Desabilitar buffering para streaming em tempo real
proxy_buffering off;
location / {
proxy_pass http://127.0.0.1:32400; # Porta padrão Plex
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Headers Plex
proxy_set_header X-Plex-Client-Identifier $http_x_plex_client_identifier;
proxy_set_header X-Plex-Device $http_x_plex_device;
proxy_set_header X-Plex-Device-Name $http_x_plex_device_name;
proxy_set_header X-Plex-Platform $http_x_plex_platform;
}
}
```
### 3.5 Zammad (Helpdesk)
Foco: Websockets (obrigatório para atualizações em tempo real) e Upstream.
```nginx
upstream zammad-railsserver {
server 127.0.0.1:3000;
}
upstream zammad-websocket {
server 127.0.0.1:6042;
}
server {
listen 443 ssl http2;
server_name suporte.empresa.com;
# Logs Exclusivos
access_log /var/log/nginx/zammad_access.log;
error_log /var/log/nginx/zammad_error.log;
# [INSERIR AQUI O BLOCO SSL E HEADERS DA SEÇÃO 2]
root /opt/zammad/public;
client_max_body_size 50M;
location /ws {
proxy_pass http://zammad-websocket;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location / {
proxy_pass http://zammad-railsserver;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
```
### 3.6 Zabbix
Foco: PHP Frontend, geralmente roda em subdiretório ou raiz.
```nginx
server {
listen 443 ssl http2;
server_name monitoramento.empresa.com;
root /usr/share/zabbix; # Caminho padrão comum no Linux
index index.php;
# Logs Exclusivos
access_log /var/log/nginx/zabbix_access.log;
error_log /var/log/nginx/zabbix_error.log;
# [INSERIR AQUI O BLOCO SSL E HEADERS DA SEÇÃO 2]
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass unix:/run/php/php8.2-fpm.sock; # Verificar versão PHP
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
}
# Previne acesso a arquivos sensíveis do Zabbix
location ~ ^/(conf|app|include|local)/ {
deny all;
return 404;
}
}
```
## 4. Validação e Testes Finais
Não considere o trabalho concluído apenas ao salvar o arquivo. Siga este ritual:
1. **Validação de Sintaxe:**
```bash
nginx -t
```
2. **Recarregar Serviço (Sem Downtime):**
```bash
systemctl reload nginx
```
3. **Checklist de Testes Externos:** Utilize as ferramentas abaixo para validar sua configuração:
* **SSL Labs:** Avaliar TLS/SSL e compatibilidade (Busque nota A+).
* **CryptCheck:** Segunda opinião focada em ciphers modernos.
* **Hardenize:** Diagnóstico de infraestrutura (DNSSEC, HSTS).
* **HSTS Preload:** Verifica se o domínio pode ser pré-carregado nos navegadores.
* **ImmuniWeb SSL:** Avaliação de compliance (PCI DSS, HIPAA).
* **SecurityHeaders:** Verifica CSP, X-Frame-Options, etc.
* **Mozilla Observatory:** Nota global de boas práticas web.
* **GTmetrix:** Performance e Waterfall.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,466 @@
zabbix_export:
version: '7.0'
template_groups:
- uuid: 7df96b18c230490a9a0a9e2307226338
name: Templates/Applications
templates:
- uuid: sat00000-0000-0000-0000-000000000001
template: Template Nginx Custom Site Analysis
name: Template Nginx Custom Site Analysis
description: Analyzes JSON logs for a specific Nginx site host.
groups:
- name: Templates/Applications
items:
- uuid: ab0f217e-2203-44b3-90ea-47b3eeebb80a
name: Access Log Stream
type: ZABBIX_ACTIVE
key: log[{$NGINX.SITE.LOG}]
delay: 1s
value_type: LOG
history: 7d
tags:
- tag: component
value: log_stream
- uuid: 6cecf19b-845b-4158-a90f-3c67af72f2fa
name: 'Nginx Site: Time ISO8601'
type: DEPENDENT
key: nginx.site.timestamp
delay: '0'
value_type: TEXT
description: Time ISO8601
history: 30d
preprocessing:
- type: JSONPATH
parameters:
- $.@timestamp
error_handler: DISCARD_VALUE
master_item:
key: log[{$NGINX.SITE.LOG}]
tags:
- tag: component
value: timestamps
- uuid: d55e36ba-c7c7-4e80-98aa-725b3935ae71
name: 'Nginx Site: Unique Request ID'
type: DEPENDENT
key: nginx.site.request_id
delay: '0'
value_type: TEXT
description: Unique Request ID
history: 30d
preprocessing:
- type: JSONPATH
parameters:
- $.request_id
error_handler: DISCARD_VALUE
master_item:
key: log[{$NGINX.SITE.LOG}]
tags:
- tag: component
value: timestamps
- uuid: bc5b35db-700b-4e2c-9925-e1c03aad24e3
name: 'Nginx Site: Client IP'
type: DEPENDENT
key: nginx.site.remote_addr
delay: '0'
value_type: TEXT
description: Client IP
history: 30d
preprocessing:
- type: JSONPATH
parameters:
- $.remote_addr
error_handler: DISCARD_VALUE
master_item:
key: log[{$NGINX.SITE.LOG}]
tags:
- tag: component
value: network
- uuid: c81de241-e241-452c-8287-c00c74fcc95b
name: 'Nginx Site: Real IP (X-Forwarded-For)'
type: DEPENDENT
key: nginx.site.real_ip
delay: '0'
value_type: TEXT
description: Real IP (X-Forwarded-For)
history: 30d
preprocessing:
- type: JSONPATH
parameters:
- $.real_ip
error_handler: DISCARD_VALUE
master_item:
key: log[{$NGINX.SITE.LOG}]
tags:
- tag: component
value: network
- uuid: f5fd7a97-6578-44c9-8731-ef3c6cfd9a30
name: 'Nginx Site: Authenticated User'
type: DEPENDENT
key: nginx.site.remote_user
delay: '0'
value_type: TEXT
description: Authenticated User
history: 30d
preprocessing:
- type: JSONPATH
parameters:
- $.remote_user
error_handler: DISCARD_VALUE
master_item:
key: log[{$NGINX.SITE.LOG}]
tags:
- tag: component
value: network
- uuid: 2792452d-6c55-4bfa-8e37-fd134d0bf76b
name: 'Nginx Site: HTTP Method'
type: DEPENDENT
key: nginx.site.request_method
delay: '0'
value_type: TEXT
description: HTTP Method
history: 30d
preprocessing:
- type: JSONPATH
parameters:
- $.request_method
error_handler: DISCARD_VALUE
master_item:
key: log[{$NGINX.SITE.LOG}]
tags:
- tag: component
value: request
- uuid: c32f7902-1683-4a99-8832-4d190f02ca81
name: 'Nginx Site: Host Header'
type: DEPENDENT
key: nginx.site.host_header
delay: '0'
value_type: TEXT
description: Host Header
history: 30d
preprocessing:
- type: JSONPATH
parameters:
- $.host_header
error_handler: DISCARD_VALUE
master_item:
key: log[{$NGINX.SITE.LOG}]
tags:
- tag: component
value: request
- uuid: 8e156772-27be-45df-afff-4cc7214aa838
name: 'Nginx Site: URI'
type: DEPENDENT
key: nginx.site.uri
delay: '0'
value_type: TEXT
description: URI
history: 30d
preprocessing:
- type: JSONPATH
parameters:
- $.uri
error_handler: DISCARD_VALUE
master_item:
key: log[{$NGINX.SITE.LOG}]
tags:
- tag: component
value: request
- uuid: 4febe104-a59a-4204-bf42-f21cb550d625
name: 'Nginx Site: Request Length (bytes)'
type: DEPENDENT
key: nginx.site.request_length
delay: '0'
value_type: FLOAT
description: Request Length (bytes)
history: 30d
preprocessing:
- type: JSONPATH
parameters:
- $.request_length
error_handler: DISCARD_VALUE
master_item:
key: log[{$NGINX.SITE.LOG}]
tags:
- tag: component
value: request
- uuid: 6ab853fb-2b27-4185-be8c-65c06bd02d4a
name: 'Nginx Site: HTTP Status Code'
type: DEPENDENT
key: nginx.site.status
delay: '0'
value_type: FLOAT
description: HTTP Status Code
history: 30d
preprocessing:
- type: JSONPATH
parameters:
- $.status
error_handler: DISCARD_VALUE
master_item:
key: log[{$NGINX.SITE.LOG}]
tags:
- tag: component
value: response
- uuid: 91c8ed8e-1631-435d-9114-9a2f21eaa152
name: 'Nginx Site: Body Bytes Sent'
type: DEPENDENT
key: nginx.site.body_bytes_sent
delay: '0'
value_type: FLOAT
description: Body Bytes Sent
history: 30d
preprocessing:
- type: JSONPATH
parameters:
- $.body_bytes_sent
error_handler: DISCARD_VALUE
master_item:
key: log[{$NGINX.SITE.LOG}]
tags:
- tag: component
value: response
- uuid: 803bf915-8366-4c0b-ba79-eba29496f69f
name: 'Nginx Site: Total Bytes Sent'
type: DEPENDENT
key: nginx.site.bytes_sent
delay: '0'
value_type: FLOAT
description: Total Bytes Sent
history: 30d
preprocessing:
- type: JSONPATH
parameters:
- $.bytes_sent
error_handler: DISCARD_VALUE
master_item:
key: log[{$NGINX.SITE.LOG}]
tags:
- tag: component
value: response
- uuid: 82a7d2fd-1e09-4976-9b29-12551791029f
name: 'Nginx Site: Request Time (Total)'
type: DEPENDENT
key: nginx.site.request_time
delay: '0'
value_type: FLOAT
description: Request Time (Total)
history: 30d
preprocessing:
- type: JSONPATH
parameters:
- $.request_time
error_handler: DISCARD_VALUE
master_item:
key: log[{$NGINX.SITE.LOG}]
tags:
- tag: component
value: performance
- uuid: f65cdff7-b3d9-428a-98a6-d0ccbe557589
name: 'Nginx Site: Upstream Connect Time'
type: DEPENDENT
key: nginx.site.upstream_connect_time
delay: '0'
value_type: FLOAT
description: Upstream Connect Time
history: 30d
preprocessing:
- type: JSONPATH
parameters:
- $.upstream_connect_time
error_handler: DISCARD_VALUE
master_item:
key: log[{$NGINX.SITE.LOG}]
tags:
- tag: component
value: performance
- uuid: 8c7e5f38-9865-41b3-b22c-f5e7b51bfcfe
name: 'Nginx Site: Upstream Header Time'
type: DEPENDENT
key: nginx.site.upstream_header_time
delay: '0'
value_type: FLOAT
description: Upstream Header Time
history: 30d
preprocessing:
- type: JSONPATH
parameters:
- $.upstream_header_time
error_handler: DISCARD_VALUE
master_item:
key: log[{$NGINX.SITE.LOG}]
tags:
- tag: component
value: performance
- uuid: 20f65169-9c54-4fe1-9468-3df9de93f8e4
name: 'Nginx Site: Upstream Response Time'
type: DEPENDENT
key: nginx.site.upstream_response_time
delay: '0'
value_type: FLOAT
description: Upstream Response Time
history: 30d
preprocessing:
- type: JSONPATH
parameters:
- $.upstream_response_time
error_handler: DISCARD_VALUE
master_item:
key: log[{$NGINX.SITE.LOG}]
tags:
- tag: component
value: performance
- uuid: 943cce09-54a4-42c2-8c17-81eff8d4069f
name: 'Nginx Site: Cache Status'
type: DEPENDENT
key: nginx.site.upstream_cache_status
delay: '0'
value_type: TEXT
description: Cache Status
history: 30d
preprocessing:
- type: JSONPATH
parameters:
- $.upstream_cache_status
error_handler: DISCARD_VALUE
master_item:
key: log[{$NGINX.SITE.LOG}]
tags:
- tag: component
value: performance
- uuid: 9ccc7f5e-e8d0-47ba-8e4a-92b6cad62879
name: 'Nginx Site: GeoIP Country Code'
type: DEPENDENT
key: nginx.site.geoip_country_code
delay: '0'
value_type: TEXT
description: GeoIP Country Code
history: 30d
preprocessing:
- type: JSONPATH
parameters:
- $.geoip_country_code
error_handler: DISCARD_VALUE
master_item:
key: log[{$NGINX.SITE.LOG}]
tags:
- tag: component
value: geoip
- uuid: c6cfd5f9-dd0e-495d-bca9-300b9d9c5c96
name: 'Nginx Site: GeoIP City Name'
type: DEPENDENT
key: nginx.site.geoip_city_name
delay: '0'
value_type: TEXT
description: GeoIP City Name
history: 30d
preprocessing:
- type: JSONPATH
parameters:
- $.geoip_city_name
error_handler: DISCARD_VALUE
master_item:
key: log[{$NGINX.SITE.LOG}]
tags:
- tag: component
value: geoip
- uuid: 24b4d01c-ce56-4bf8-84b3-a2b54ba0bc08
name: 'Nginx Site: GeoIP ISP'
type: DEPENDENT
key: nginx.site.geoip_isp
delay: '0'
value_type: TEXT
description: GeoIP ISP
history: 30d
preprocessing:
- type: JSONPATH
parameters:
- $.geoip_isp
error_handler: DISCARD_VALUE
master_item:
key: log[{$NGINX.SITE.LOG}]
tags:
- tag: component
value: geoip
- uuid: 52fde988-999a-4b54-8f6f-042c5e83e46f
name: 'Nginx Site: Bad Bot Flag'
type: DEPENDENT
key: nginx.site.is_bad_bot
delay: '0'
value_type: TEXT
description: Bad Bot Flag
history: 30d
preprocessing:
- type: JSONPATH
parameters:
- $.is_bad_bot
error_handler: DISCARD_VALUE
master_item:
key: log[{$NGINX.SITE.LOG}]
tags:
- tag: component
value: security
- uuid: abd94490-38f1-4672-a5ec-4a62ab04870b
name: 'Nginx Site: WAF Block Flag'
type: DEPENDENT
key: nginx.site.block_request
delay: '0'
value_type: TEXT
description: WAF Block Flag
history: 30d
preprocessing:
- type: JSONPATH
parameters:
- $.block_request
error_handler: DISCARD_VALUE
master_item:
key: log[{$NGINX.SITE.LOG}]
tags:
- tag: component
value: security
- uuid: 2d75c9e6-ef88-4205-aa6c-440037fcacb4
name: 'Nginx Site: SSL Protocol'
type: DEPENDENT
key: nginx.site.ssl_protocol
delay: '0'
value_type: TEXT
description: SSL Protocol
history: 30d
preprocessing:
- type: JSONPATH
parameters:
- $.ssl_protocol
error_handler: DISCARD_VALUE
master_item:
key: log[{$NGINX.SITE.LOG}]
tags:
- tag: component
value: security
- uuid: 827b7c96-1994-49f1-a476-7f2036ae9075
name: 'Nginx Site: SSL Cipher'
type: DEPENDENT
key: nginx.site.ssl_cipher
delay: '0'
value_type: TEXT
description: SSL Cipher
history: 30d
preprocessing:
- type: JSONPATH
parameters:
- $.ssl_cipher
error_handler: DISCARD_VALUE
master_item:
key: log[{$NGINX.SITE.LOG}]
tags:
- tag: component
value: security
- uuid: 42766b9a-5bb3-4b0e-816f-c250c00a6f00
name: 'Nginx Site: HTTP 5xx Rate'
type: CALCULATED
key: nginx.site.status.5xx.rate
params: count(//nginx.site.status, 1m, "ge", 500)
value_type: FLOAT
units: rps
delay: 1m
tags:
- tag: component
value: availability

View File

@ -1,199 +0,0 @@
# AI Agent Execution Plan: OpenVPN Hybrid Integration
**Objective**: transform the `pfsense_hybrid_snmp_agent` folder into a production-ready Hybrid solution.
**Context**: The files `C:\Users\joao.goncalves\Desktop\zabbix-itguys\templates_gold\pfsense_hybrid_snmp_agent\files\openvpn-discovery.sh` and `C:\Users\joao.goncalves\Desktop\zabbix-itguys\templates_gold\pfsense_hybrid_snmp_agent\files\userparameter_openvpn.conf` are currently raw copies. The YAML template is the original SNMP version located at `C:\Users\joao.goncalves\Desktop\zabbix-itguys\templates_gold\pfsense_hybrid_snmp_agent\template_app_pfsense_snmp.yaml`.
## Execution Strategy & Safety Context
**Goal**: We are building a "Hybrid" Zabbix Template for pfSense that combines standard SNMP monitoring with advanced OpenVPN metrics collected via Zabbix Agent Custom UserParameters.
**Key Features**:
1. **Dynamic Grouping**: Group VPN users by "Company" (Server Name) derived from log filenames.
2. **Security Triggers**: Detect Exfiltration (>10GB/h), Zombie Sessions (>24h), and Session Hijacking (IP Change).
3. **S2S vs User**: Distinguish Site-to-Site tunnels from human users to apply different alert rules via Macros and Discovery Overrides.
**CRITICAL INSTRUCTION**: If any step in this runbook is ambiguous, fails validation, or if you encounter unexpected file structures, **STOP IMMEDIATELY**. Do not guess. Ask the user for clarification before proceeding to the next step.
---
## Phase 1: Script & Agent Configuration
### 1.1. Rewrite `files/openvpn-discovery.sh`
**Path**: `C:\Users\joao.goncalves\Desktop\zabbix-itguys\templates_gold\pfsense_hybrid_snmp_agent\files\openvpn-discovery.sh`
**Logic**:
- Scan `/var/log/openvpn/status*.log`.
- Extract `{#VPN.SERVER}` from filename (Regex: `status_(.*).log` -> Group 1).
- Extract Users, Real IP, Byte Counts from content.
- **Critical**: Output JSON standard for Zabbix LLD.
```bash
#!/bin/sh
# OpenVPN Discovery Script (Arthur's Gold Standard)
# Outputs: {#VPN.USER}, {#VPN.SERVER}, {#VPN.REAL_IP}
JSON_OUTPUT="{\"data\":["
FIRST_ITEM=1
# Loop through all status logs
for logfile in /var/log/openvpn/status*.log; do
[ -e "$logfile" ] || continue
# Extract Server Name from Filename "status_SERVERNAME.log"
# Note: Busybox filename parsing
filename=$(basename "$logfile")
# Remove prefix "status_" and suffix ".log"
server_name=$(echo "$filename" | sed -e 's/^status_//' -e 's/\.log$//')
# Read the file and parse "CLIENT_LIST" lines
# Format: CLIENT_LIST,CommonName,RealAddress,VirtualAddress,BytesReceived,BytesSent,Since,Since(time_t),Username,ClientID,PeerID
while IFS=, read -r type common_name real_address virtual_address bytes_rx bytes_tx since since_unix username client_id peer_id; do
if [ "$type" = "CLIENT_LIST" ] && [ "$common_name" != "Common Name" ]; then
# Extract IP only from RealAddress (IP:PORT)
real_ip=$(echo "$real_address" | cut -d: -f1)
# Append to JSON
if [ $FIRST_ITEM -eq 0 ]; then JSON_OUTPUT="$JSON_OUTPUT,"; fi
JSON_OUTPUT="$JSON_OUTPUT{\"{#VPN.USER}\":\"$common_name\",\"{#VPN.SERVER}\":\"$server_name\",\"{#VPN.REAL_IP}\":\"$real_ip\"}"
FIRST_ITEM=0
fi
done < "$logfile"
done
JSON_OUTPUT="$JSON_OUTPUT]}"
echo "$JSON_OUTPUT"
```
### 1.2. Update `files/userparameter_openvpn.conf`
**Path**: `C:\Users\joao.goncalves\Desktop\zabbix-itguys\templates_gold\pfsense_hybrid_snmp_agent\files\userparameter_openvpn.conf`
**Logic**:
- Simplify. The discovery script now does the heavy lifting of finding users.
- The Items need to fetch data. Since we have multiple files, `grep` needs to search ALL of them.
- **Optimization**: `grep -h` (no filename) to search all generic status logs.
```conf
UserParameter=openvpn.discovery,/opt/zabbix/openvpn-discovery.sh
# Fetch raw metrics for a specific user (Usernames must be unique across servers or we grab the first match)
UserParameter=openvpn.user.bytes_received.total[*],grep -h "^CLIENT_LIST,$1," /var/log/openvpn/status*.log 2>/dev/null | head -1 | cut -d, -f6
UserParameter=openvpn.user.bytes_sent.total[*],grep -h "^CLIENT_LIST,$1," /var/log/openvpn/status*.log 2>/dev/null | head -1 | cut -d, -f7
UserParameter=openvpn.user.connected_since[*],grep -h "^CLIENT_LIST,$1," /var/log/openvpn/status*.log 2>/dev/null | head -1 | cut -d, -f9
UserParameter=openvpn.user.real_address.new[*],grep -h "^CLIENT_LIST,$1," /var/log/openvpn/status*.log 2>/dev/null | head -1 | cut -d, -f3 | cut -d: -f1
UserParameter=openvpn.user.status[*],if grep -q "^CLIENT_LIST,$1," /var/log/openvpn/status*.log 2>/dev/null; then echo 1; else echo 0; fi
UserParameter=openvpn.version,openvpn --version 2>&1 | head -1 | awk '{print $2}'
```
---
## Phase 2: Template Configuration (YAML)
**Target**: `templates_gold/pfsense_hybrid_snmp_agent/template_pfsense_hybrid_gold.yaml`
### 2.1. Add Macros
Append to `macros` section:
```yaml
- macro: '{$VPN.S2S.PATTERN}'
value: '^S2S_'
description: 'Regex para identificar túneis Site-to-Site.'
- macro: '{$VPN.DATA.LIMIT}'
value: '10737418240'
description: 'Limite de Download (10GB) para alerta de Exfiltração.'
- macro: '{$VPN.WORK.START}'
value: '080000'
- macro: '{$VPN.WORK.END}'
value: '180000'
- macro: '{$VPN.ZOMBIE.LIMIT}'
value: '86400'
description: 'Tempo máximo (24h) para considerar sessão zumbi.'
```
### 2.2. Add Discovery Rule
**Name**: `Descoberta de Usuários OpenVPN`
**Key**: `openvpn.discovery`
**Type**: `ZABBIX_ACTIVE` (Preferred for Agents behind NAT/Firewall)
**Overrides**:
```yaml
overrides:
- name: 'Site-to-Site (S2S)'
step: '1'
filter:
conditions:
- macro: '{#VPN.USER}'
value: '{$VPN.S2S.PATTERN}'
operator: REGEXP
operations:
- operationobject: ITEM_PROTOTYPE
operator: REGEXP
value: 'Stats Year|Forecast'
status: ENABLED
- operationobject: TRIGGER_PROTOTYPE
operator: REGEXP
value: 'Exfiltração|Horário|Zombie|IP Change'
status: DISABLED
- operationobject: ITEM_PROTOTYPE
operator: LIKE
value: ''
tags:
- tag: Type
value: S2S
- name: 'User (Colaborador)'
step: '2'
filter:
conditions:
- macro: '{#VPN.USER}'
value: '{$VPN.S2S.PATTERN}'
operator: NOT_REGEXP
operations:
- operationobject: ITEM_PROTOTYPE
operator: REGEXP
value: 'Stats Year|Forecast'
status: DISABLED
- operationobject: TRIGGER_PROTOTYPE
operator: REGEXP
value: 'Exfiltração|Horário|Zombie|IP Change'
status: ENABLED
- operationobject: ITEM_PROTOTYPE
operator: LIKE
value: ''
tags:
- tag: Type
value: User
```
### 2.3. Add Item Prototypes (Selected)
**Common Tags**: `Company: {{#VPN.SERVER}.regsub("(?:CLIENT_|S2S_)?(.*)", "\1")}`
1. **Download Total (Raw)**
- Key: `openvpn.user.bytes_received.total[{#VPN.USER}]`
- Type: ZABBIX_ACTIVE
- Units: B
2. **Download Rate (Calculated/Dependent?)**
- Actually, simpler to let Zabbix standard "Simple Change" preprocessing handle rate on a Dependent Item, or just use `Change per Second` preprocessing.
- **Decision**: Create `openvpn.user.bytes_received.rate[{#VPN.USER}]` dependent on Total, with `Change per Second`.
3. **Real IP (Inventory)**
- Key: `openvpn.user.real_address.new[{#VPN.USER}]`
- Populates Host Inventory field? No, this is an item prototype. Just keep as value.
**Reporting Metrics (Calculated)**
- **Stats Week**: `trendsum(//openvpn.user.bytes_received.total[{#VPN.USER}], 1w:now/w)`
- **Stats Month**: `trendsum(..., 1M:now/M)`
- **Forecast**: `(last(Month) / dayat()) * dayofmonth(end)` (Simplified)
### 2.4. Add Triggers
1. **Exfiltração**: `(last(Total) - last(Total, 1h)) > {$VPN.DATA.LIMIT}`
2. **IP Change**: `diff(RealIP)=1 and last(Status)=1`
3. **Zombie**: `last(ConnectedSince) < now() - {$VPN.ZOMBIE.LIMIT}`
### 2.5. Add Dashboard
Insert `dashboards:` block at root (or modify existing if any).
- Use `type: svggraph` for Trends.
- Use `type: tophosts` for Tables (Columns: Name, Latest Value of Metric).
---
## Phase 3: Validation
1. **Lint**: `validate_zabbix_template.py`.
2. **Docs**: `generate_template_docs.py`.

View File

@ -0,0 +1,110 @@
# 🚀 Agent Execution Plan: Zabbix Speedtest & Strategic Intelligence (v10)
**Status:** APPROVED
**Target Directory:** `c:\Users\joao.goncalves\Desktop\zabbix-itguys\templates_gold\pfsense_hybrid_snmp_agent`
**Objective:** Implement a robust, multi-WAN speedtest solution with Business Intelligence dashboards in the Gold Template.
---
## 🏗️ 1. File Structure & Scripts (Fase 1)
These files must be created in the `files/` subdirectory.
### A. `files/speedtest_discovery.py` (Python 3.11)
- **Goal:** Native pfSense Discovery without external dependencies.
- **Logic:**
1. Parse `/cf/conf/config.xml` using `xml.etree.ElementTree`.
2. Identify interfaces with a `<gateway>` tag (WANs).
3. Extract `descr` (Name), `if` (Interface ID like igb0), `ipaddr`.
- **Output (LLD JSON):**
```json
[{"{#IFNAME}": "igb0", "{#WAN_ALIAS}": "VIVO", "{#WAN_IP}": "x.x.x.x"}]
```
### B. `files/speedtest_worker.sh` (Bash)
- **Goal:** Execute speedtest ensuring no timeouts + Telemetry.
- **Arguments:** `--interface <IF>`
- **Logic:**
1. Start a background CPU monitor (`top -P 0` or `vmstat 1`) to capture `idle/interrupt` %.
2. Execute `speedtest --interface <IP_FROM_IF> --format json`.
3. Stop CPU monitor. Calculate average CPU Load during test.
4. Inject `cpu_load_during_test` and `interrupts` into the Speedtest JSON.
5. Send to Zabbix via `zabbix_sender` (Trappers).
### C. `files/install_speedtest.sh`
- Helper to install `pkg install -y speedtest`.
---
## 🧠 2. Template Intelligence (Fase 2)
Modify `template_pfsense_hybrid_gold.yaml` (Monolithic Approach).
### A. Discovery Rule
- **Key:** `speedtest.discovery`
- **Type:** Zabbix Agent (UserParameter calling the Python script).
### B. Item Prototypes (Trappers)
- **Master:** `speedtest.json[{#IFNAME}]`
- **Dependent Items:**
- `speedtest.download`, `speedtest.upload`, `speedtest.latency`
- `speedtest.cpu_load` (New)
- `speedtest.bufferbloat` (Calculated: `speedtest.latency - icmppingsec`)
### C. Calculated Items (Business Logic)
1. **Forecasting (Saturação):**
- `business.bandwidth.saturation_date`: Forecast when `net.if.in` reaches `{$WAN_CONTRACT_DOWN}`.
2. **Financeiro (Risco):**
- `business.downtime.cost`: `(100 - sla.uptime) * {$COMPANY.HOURLY_COST}`.
3. **Efficiency:**
- `business.link.efficiency`: `avg(net.if.in, 30d) / {$WAN_CONTRACT_DOWN} * 100`.
### D. Triggers (Cross-Correlation)
1. **Hardware Bottleneck:**
- `speedtest.download < Expected` AND `speedtest.cpu_load > 90%`.
- Msg: "🔥 Hardware Limiting Speed (Not ISP)".
2. **ISP Quality (Bufferbloat):**
- `speedtest.bufferbloat > 100ms`.
- Msg: "⚠️ ISP Latency Spike under Load".
3. **Financial Opportunity:**
- `business.downtime.cost > {$LINK.SECONDARY.COST}`.
- Msg: "💰 Downtime costs exceed Secondary Link price."
---
## 📊 3. Dashboards (Fase 3)
Create a Dashboard Resource in the YAML: "Speedtest & Strategic Planning".
**Widgets:**
1. **Executive Summary:** Markdown widget showing Financial Loss & Efficiency.
2. **Forecasting:** Graph showing Traffic Growth vs Contract Limit (Projected).
3. **Technical Correlation:** Graph with 3 Y-axes (Speed, CPU, Latency).
---
## 📝 4. Documentation (Fase 4)
Update `INSTRUCOES_AGENTE.txt`:
- Add "Step 5: Setup Speedtest".
- Instructions for `pkg install` and `cron` setup.
---
## ✅ 5. Validation & Auto-Documentation (MANDATORY)
Once the modifications are complete, the Agent **MUST** run the project's QA tools to ensure quality and compliance.
### A. Validate Template Structure
Run the validation script to check for UUID conflicts, schema errors, or duplicate keys.
```powershell
python c:\Users\joao.goncalves\Desktop\zabbix-itguys\validate_zabbix_template.py c:\Users\joao.goncalves\Desktop\zabbix-itguys\templates_gold\pfsense_hybrid_snmp_agent\template_pfsense_hybrid_gold.yaml
```
- **Constraint:** If this script returns ANY error, the Agent must fix it immediately before finishing the task.
### B. Generate Documentation
Run the documentation generator to automatically update the markdown documentation for the template.
```powershell
python c:\Users\joao.goncalves\Desktop\zabbix-itguys\generate_template_docs.py c:\Users\joao.goncalves\Desktop\zabbix-itguys\templates_gold\pfsense_hybrid_snmp_agent\template_pfsense_hybrid_gold.yaml
```
- **Output:** This will generate/update `template_pfsense_hybrid_gold_generated.md`.

932
zbx_export_hosts.yaml Normal file
View File

@ -0,0 +1,932 @@
zabbix_export:
version: '7.4'
host_groups:
- uuid: 7fd3a689a3874d0b9212a8f11af9f356
name: 'IT GUYS'
- uuid: 5b5d7aa968304e2191657b4d0b0e5a4b
name: LINUX
- uuid: 137f19e6e2dc4219b33553b812627bc2
name: 'VM / MAQUINA VIRTUAL'
hosts:
- host: srvproxy001
name: 'iT Guys - Debian 12 - Pathfinder (Nginx Proxy)'
templates:
- name: Fail2ban
- name: 'Linux via Agente Zabbix'
- name: 'Nginx por Zabbix agent'
groups:
- name: 'IT GUYS'
- name: LINUX
- name: 'VM / MAQUINA VIRTUAL'
interfaces:
- ip: 172.16.254.1
interface_ref: if1
discovery_rules:
- name: 'Insight: Log de Acesso'
type: ZABBIX_ACTIVE
key: nginx.access.logs.list
delay: 1s
enabled_lifetime_type: DISABLE_AFTER
enabled_lifetime: 1h
item_prototypes:
- name: 'Insight: Acesso {#HOST_SITE}'
type: ZABBIX_ACTIVE
key: 'log[/var/log/nginx/{#HOST_SITE}.access.log]'
delay: 1s
history: 91d
value_type: LOG
timeout: 120s
tags:
- tag: Insight
value: 'access log'
- name: 'Insight: Bad-Bot {#HOST_SITE}'
type: ZABBIX_ACTIVE
key: 'log[/var/log/nginx/{#HOST_SITE}.bad-bot.log]'
delay: 1s
value_type: LOG
timeout: 120s
tags:
- tag: Insight
value: bad-bot
- name: 'Insight: Erros {#HOST_SITE}'
type: ZABBIX_ACTIVE
key: 'log[/var/log/nginx/{#HOST_SITE}.error.log]'
delay: 1s
value_type: LOG
timeout: 120s
tags:
- tag: Insight
value: 'error log'
- name: 'Nginx: Cache HITs Flag for {#HOST_SITE}'
type: DEPENDENT
key: 'nginx.cache.hit.flag.[{#HOST_SITE}]'
preprocessing:
- type: REGEX
parameters:
- 'upstream_cache_status":"HIT"'
- '1'
error_handler: CUSTOM_VALUE
error_handler_params: '0'
master_item:
key: 'log[/var/log/nginx/{#HOST_SITE}.access.log]'
tags:
- tag: Insight
value: performance
- name: 'Insight: Cache Hit Ratio (Ultimo 1m) (%) {#HOST_SITE}'
type: CALCULATED
key: 'nginx.cache.hit.ratio.1m.[{#HOST_SITE}]'
value_type: FLOAT
units: '%'
params: '(last(//nginx.cache.hits.1m.[{#HOST_SITE}]) * 100) / (last(//nginx.cache.hits.1m.[{#HOST_SITE}]) + last(//nginx.cache.miss.1m.[{#HOST_SITE}]) + (last(//nginx.cache.hits.1m.[{#HOST_SITE}]) + last(//nginx.cache.miss.1m.[{#HOST_SITE}]) = 0))'
tags:
- tag: Insight
value: carga
- name: 'Insight: Cache HITs no Ultimo minuto {#HOST_SITE}'
type: CALCULATED
key: 'nginx.cache.hits.1m.[{#HOST_SITE}]'
units: hits
params: 'sum(//nginx.cache.hit.flag.[{#HOST_SITE}],1m)'
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Insight: Cache HITs nos Ultimos 5 minuto {#HOST_SITE}'
type: CALCULATED
key: 'nginx.cache.hits.5m.[{#HOST_SITE}]'
delay: 4m
units: hits
params: 'sum(//nginx.cache.hit.flag.[{#HOST_SITE}],5m)'
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Insight: Cache HITs nos Ultimos 15 minuto {#HOST_SITE}'
type: CALCULATED
key: 'nginx.cache.hits.15m.[{#HOST_SITE}]'
delay: 14m
units: hits
params: 'sum(//nginx.cache.hit.flag.[{#HOST_SITE}],15m)'
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Insight: Cache HITs nos Ultimos 24 hrs {#HOST_SITE}'
type: CALCULATED
key: 'nginx.cache.hits.24h.[{#HOST_SITE}]'
delay: 1h
units: hits
params: 'sum(//nginx.cache.hit.flag.[{#HOST_SITE}],24h)'
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Insight: Cache MISS no Ultimo minuto {#HOST_SITE}'
type: CALCULATED
key: 'nginx.cache.miss.1m.[{#HOST_SITE}]'
units: miss
params: 'sum(//nginx.cache.miss.flag.[{#HOST_SITE}],1m)'
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Insight: Cache MISS no Ultimos 5 minuto {#HOST_SITE}'
type: CALCULATED
key: 'nginx.cache.miss.5m.[{#HOST_SITE}]'
delay: 4m
units: miss
params: 'sum(//nginx.cache.miss.flag.[{#HOST_SITE}],5m)'
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Insight: Cache MISS no Ultimos 15 minuto {#HOST_SITE}'
type: CALCULATED
key: 'nginx.cache.miss.15m.[{#HOST_SITE}]'
delay: 14m
units: miss
params: 'sum(//nginx.cache.miss.flag.[{#HOST_SITE}],15m)'
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Insight: Cache MISS no Ultimos 24 horas {#HOST_SITE}'
type: CALCULATED
key: 'nginx.cache.miss.24h.[{#HOST_SITE}]'
delay: 1h
units: miss
params: 'sum(//nginx.cache.miss.flag.[{#HOST_SITE}],24h)'
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Nginx: Cache MISS Flag for {#HOST_SITE}'
type: DEPENDENT
key: 'nginx.cache.miss.flag.[{#HOST_SITE}]'
preprocessing:
- type: REGEX
parameters:
- 'upstream_cache_status":"MISS"'
- '1'
error_handler: DISCARD_VALUE
master_item:
key: 'log[/var/log/nginx/{#HOST_SITE}.access.log]'
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Insight: Cache Miss Ratio (Ultimo 1m) (%) {#HOST_SITE}'
type: CALCULATED
key: 'nginx.cache.miss.ratio.1m.[{#HOST_SITE}]'
value_type: FLOAT
units: '%'
params: '(last(//nginx.cache.miss.1m.[{#HOST_SITE}]) * 100) / (last(//nginx.cache.hits.1m.[{#HOST_SITE}]) + last(//nginx.cache.miss.1m.[{#HOST_SITE}]) + (last(//nginx.cache.hits.1m.[{#HOST_SITE}]) + last(//nginx.cache.miss.1m.[{#HOST_SITE}]) = 0))'
tags:
- tag: Insight
value: carga
- name: 'Insight: {#HOST_SITE} Marcações Usuario Online'
type: DEPENDENT
key: 'nginx.log.user_status.list[{#HOST_SITE}}]'
value_type: TEXT
preprocessing:
- type: JAVASCRIPT
parameters:
- |
// Versão compatível com JavaScript antigo (ES5) - Saída em Texto Puro
// Usamos um objeto para garantir que cada usuário seja único.
var uniqueUsers = {};
var remoteUserRegex = /"remote_user":"([a-zA-Z0-9._-]+)"/g;
var cookieUserRegex = /nc_username=([a-zA-Z0-9._-]+);/g;
var urlUserRegex = /\/remote\.php\/dav\/files\/([a-zA-Z0-9._-]+)\//g;
var lines = value.split('\n');
for (var i = 0; i < lines.length; i++) {
var line = lines[i];
var match;
// Função auxiliar para adicionar usuários ao nosso objeto de unicidade
function findAndAdd(regex) {
while ((match = regex.exec(line)) !== null) {
if (match[1] && match[1].length > 0) {
// Adiciona o usuário completo como uma chave do objeto.
uniqueUsers[match[1]] = true;
}
}
}
findAndAdd(remoteUserRegex);
findAndAdd(cookieUserRegex);
findAndAdd(urlUserRegex);
}
// Pega todas as chaves do objeto para formar o array final de usuários únicos.
var userArray = Object.keys(uniqueUsers);
// --- LINHA ALTERADA ---
// Une todos os elementos do array em uma única string,
// separando cada um com um caractere de quebra de linha ('\n').
return userArray.join('\n');
master_item:
key: 'log[/var/log/nginx/{#HOST_SITE}.access.log]'
tags:
- tag: Insight
value: performance
- name: 'Nginx: Requests Excelentes por minuto {#HOST_SITE}'
type: CALCULATED
key: 'nginx.requests.excellent.count.1m.[{#HOST_SITE}]'
units: reqs/min
params: |
last(//nginx.request_time.count.0-20ms.1m.[{#HOST_SITE}]) +
last(//nginx.request_time.count.21-50ms.1m.[{#HOST_SITE}]) +
last(//nginx.request_time.count.51-100ms.1m.[{#HOST_SITE}]) +
last(//nginx.request_time.count.101-200ms.1m.[{#HOST_SITE}])
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Insight: Requisição nos Ultimos 5 Minuto em {#HOST_SITE}'
type: CALCULATED
key: 'nginx.requests.per_5minute[{#HOST_SITE}]'
delay: 4m
units: requests
params: 'count(//log[/var/log/nginx/{#HOST_SITE}.access.log],5m)'
tags:
- tag: Insight
value: carga
- name: 'Insight: Requisição nos Ultimos 15 Minuto em {#HOST_SITE}'
type: CALCULATED
key: 'nginx.requests.per_15minute[{#HOST_SITE}]'
delay: 14m
units: requests
params: 'count(//log[/var/log/nginx/{#HOST_SITE}.access.log],15m)'
tags:
- tag: Insight
value: carga
- name: 'Insight: Requisição nos Ultimos 24 horas em {#HOST_SITE}'
type: CALCULATED
key: 'nginx.requests.per_24h[{#HOST_SITE}]'
delay: 1h
units: requests
params: 'count(//log[/var/log/nginx/{#HOST_SITE}.access.log],24h)'
tags:
- tag: Insight
value: carga
- name: 'Insight: Requisição no Ultimo 1 Minuto em {#HOST_SITE}'
type: CALCULATED
key: 'nginx.requests.per_minute[{#HOST_SITE}]'
units: requests
params: 'count(//log[/var/log/nginx/{#HOST_SITE}.access.log],1m)'
tags:
- tag: Insight
value: carga
- name: 'Insight: Média de Tempo de Resposta (1m) {#HOST_SITE}'
type: CALCULATED
key: 'nginx.request_time.avg.1m.[{#HOST_SITE}]'
value_type: FLOAT
units: ms
params: 'avg(//nginx.request_time.[{#HOST_SITE}],1m)'
tags:
- tag: Insight
value: carga
- name: 'Insight: Média de Tempo de Resposta (5m) {#HOST_SITE}'
type: CALCULATED
key: 'nginx.request_time.avg.5m.[{#HOST_SITE}]'
delay: 4m
value_type: FLOAT
units: ms
params: 'avg(//nginx.request_time.[{#HOST_SITE}],5m)'
tags:
- tag: Insight
value: carga
- name: 'Insight: Média de Tempo de Resposta (15m) {#HOST_SITE}'
type: CALCULATED
key: 'nginx.request_time.avg.15m.[{#HOST_SITE}]'
value_type: FLOAT
units: ms
params: 'avg(//nginx.request_time.[{#HOST_SITE}],15m)'
tags:
- tag: Insight
value: carga
- name: 'Nginx: RTime Flag (0-20ms) {#HOST_SITE}'
type: DEPENDENT
key: 'nginx.request_time.flag.0-20ms.[{#HOST_SITE}]'
preprocessing:
- type: JAVASCRIPT
parameters:
- |
try {
// O valor chega em segundos (ex: 0.015), convertemos para milissegundos.
var value_ms = parseFloat(value) * 1000;
// Verifica se o valor está na faixa de 0 a 20ms.
if (value_ms >= 0 && value_ms <= 20) {
return 1;
}
// Se não estiver na faixa, retorna null para o Zabbix descartar.
return 0;
} catch (e) {
// Se der qualquer erro, também descarta.
return 0;
}
master_item:
key: 'nginx.request_time.[{#HOST_SITE}]'
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Nginx: RTime Flag (21-50ms) {#HOST_SITE}'
type: DEPENDENT
key: 'nginx.request_time.flag.21-50ms.[{#HOST_SITE}]'
preprocessing:
- type: JAVASCRIPT
parameters:
- |
try {
// O valor chega em segundos (ex: 0.015), convertemos para milissegundos.
var value_ms = parseFloat(value) * 1000;
// Verifica se o valor está na faixa de 0 a 20ms.
if (value_ms >= 21 && value_ms <= 50) {
return 1;
}
// Se não estiver na faixa, retorna null para o Zabbix descartar.
return 0;
} catch (e) {
// Se der qualquer erro, também descarta.
return 0;
}
master_item:
key: 'nginx.request_time.[{#HOST_SITE}]'
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Nginx: RTime Flag (51-100ms) {#HOST_SITE}'
type: DEPENDENT
key: 'nginx.request_time.flag.51-100ms.[{#HOST_SITE}]'
preprocessing:
- type: JAVASCRIPT
parameters:
- |
try {
// O valor chega em segundos (ex: 0.015), convertemos para milissegundos.
var value_ms = parseFloat(value) * 1000;
// Verifica se o valor está na faixa de 0 a 20ms.
if (value_ms >= 51 && value_ms <= 100) {
return 1;
}
// Se não estiver na faixa, retorna null para o Zabbix descartar.
return 0;
} catch (e) {
// Se der qualquer erro, também descarta.
return 0;
}
master_item:
key: 'nginx.request_time.[{#HOST_SITE}]'
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Nginx: RTime Flag (201-300ms) {#HOST_SITE}'
type: DEPENDENT
key: 'nginx.request_time.flag.201-300ms.[{#HOST_SITE}]'
preprocessing:
- type: JAVASCRIPT
parameters:
- |
try {
// O valor chega em segundos (ex: 0.015), convertemos para milissegundos.
var value_ms = parseFloat(value) * 1000;
// Verifica se o valor está na faixa de 0 a 20ms.
if (value_ms >= 201 && value_ms <= 300) {
return 1;
}
// Se não estiver na faixa, retorna null para o Zabbix descartar.
return 0;
} catch (e) {
// Se der qualquer erro, também descarta.
return 0;
}
master_item:
key: 'nginx.request_time.[{#HOST_SITE}]'
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Nginx: RTime Flag (301-400ms) {#HOST_SITE}'
type: DEPENDENT
key: 'nginx.request_time.flag.301-400ms.[{#HOST_SITE}]'
preprocessing:
- type: JAVASCRIPT
parameters:
- |
try {
// O valor chega em segundos (ex: 0.015), convertemos para milissegundos.
var value_ms = parseFloat(value) * 1000;
// Verifica se o valor está na faixa de 0 a 20ms.
if (value_ms >= 301 && value_ms <= 400) {
return 1;
}
// Se não estiver na faixa, retorna null para o Zabbix descartar.
return 0;
} catch (e) {
// Se der qualquer erro, também descarta.
return 0;
}
master_item:
key: 'nginx.request_time.[{#HOST_SITE}]'
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Nginx: RTime Flag (401-500ms) {#HOST_SITE}'
type: DEPENDENT
key: 'nginx.request_time.flag.401-500ms.[{#HOST_SITE}]'
preprocessing:
- type: JAVASCRIPT
parameters:
- |
try {
// O valor chega em segundos (ex: 0.015), convertemos para milissegundos.
var value_ms = parseFloat(value) * 1000;
// Verifica se o valor está na faixa de 0 a 20ms.
if (value_ms >= 401 && value_ms <= 500) {
return 1;
}
// Se não estiver na faixa, retorna null para o Zabbix descartar.
return 0;
} catch (e) {
// Se der qualquer erro, também descarta.
return 0;
}
master_item:
key: 'nginx.request_time.[{#HOST_SITE}]'
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Nginx: RTime Flag (501-600ms) {#HOST_SITE}'
type: DEPENDENT
key: 'nginx.request_time.flag.501-600ms.[{#HOST_SITE}]'
preprocessing:
- type: JAVASCRIPT
parameters:
- |
try {
// O valor chega em segundos (ex: 0.015), convertemos para milissegundos.
var value_ms = parseFloat(value) * 1000;
// Verifica se o valor está na faixa de 0 a 20ms.
if (value_ms >= 501 && value_ms <= 600) {
return 1;
}
// Se não estiver na faixa, retorna null para o Zabbix descartar.
return 0;
} catch (e) {
// Se der qualquer erro, também descarta.
return 0;
}
master_item:
key: 'nginx.request_time.[{#HOST_SITE}]'
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Nginx: RTime Flag (601-700ms) {#HOST_SITE}'
type: DEPENDENT
key: 'nginx.request_time.flag.601-700ms.[{#HOST_SITE}]'
preprocessing:
- type: JAVASCRIPT
parameters:
- |
try {
// O valor chega em segundos (ex: 0.015), convertemos para milissegundos.
var value_ms = parseFloat(value) * 1000;
// Verifica se o valor está na faixa de 0 a 20ms.
if (value_ms >= 601 && value_ms <= 700) {
return 1;
}
// Se não estiver na faixa, retorna null para o Zabbix descartar.
return 0;
} catch (e) {
// Se der qualquer erro, também descarta.
return 0;
}
master_item:
key: 'nginx.request_time.[{#HOST_SITE}]'
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Nginx: RTime Flag (701-800ms) {#HOST_SITE}'
type: DEPENDENT
key: 'nginx.request_time.flag.701-800ms.[{#HOST_SITE}]'
preprocessing:
- type: JAVASCRIPT
parameters:
- |
try {
// O valor chega em segundos (ex: 0.015), convertemos para milissegundos.
var value_ms = parseFloat(value) * 1000;
// Verifica se o valor está na faixa de 0 a 20ms.
if (value_ms >= 701 && value_ms <= 800) {
return 1;
}
// Se não estiver na faixa, retorna null para o Zabbix descartar.
return 0;
} catch (e) {
// Se der qualquer erro, também descarta.
return 0;
}
master_item:
key: 'nginx.request_time.[{#HOST_SITE}]'
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Nginx: RTime Flag (801-900ms) {#HOST_SITE}'
type: DEPENDENT
key: 'nginx.request_time.flag.801-900ms.[{#HOST_SITE}]'
preprocessing:
- type: JAVASCRIPT
parameters:
- |
try {
// O valor chega em segundos (ex: 0.015), convertemos para milissegundos.
var value_ms = parseFloat(value) * 1000;
// Verifica se o valor está na faixa de 0 a 20ms.
if (value_ms >= 801 && value_ms <= 900) {
return 1;
}
// Se não estiver na faixa, retorna null para o Zabbix descartar.
return 0;
} catch (e) {
// Se der qualquer erro, também descarta.
return 0;
}
master_item:
key: 'nginx.request_time.[{#HOST_SITE}]'
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Nginx: RTime Flag (1001-2000ms) {#HOST_SITE}'
type: DEPENDENT
key: 'nginx.request_time.flag.1001-2000ms.[{#HOST_SITE}]'
preprocessing:
- type: JAVASCRIPT
parameters:
- |
try {
// O valor chega em segundos (ex: 0.015), convertemos para milissegundos.
var value_ms = parseFloat(value) * 1000;
// Verifica se o valor está na faixa de 0 a 20ms.
if (value_ms >= 1001 && value_ms <= 2000) {
return 1;
}
// Se não estiver na faixa, retorna null para o Zabbix descartar.
return 0;
} catch (e) {
// Se der qualquer erro, também descarta.
return 0;
}
master_item:
key: 'nginx.request_time.[{#HOST_SITE}]'
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Nginx: RTime Flag (>3001ms) {#HOST_SITE}'
type: DEPENDENT
key: 'nginx.request_time.flag.3001ms.[{#HOST_SITE}]'
preprocessing:
- type: JAVASCRIPT
parameters:
- |
try {
// O valor chega em segundos (ex: 0.015), convertemos para milissegundos.
var value_ms = parseFloat(value) * 1000;
// Verifica se o valor está na faixa de 0 a 20ms.
if (value_ms >= 3001) {
return 1;
}
// Se não estiver na faixa, retorna null para o Zabbix descartar.
return 0;
} catch (e) {
// Se der qualquer erro, também descarta.
return 0;
}
master_item:
key: 'nginx.request_time.[{#HOST_SITE}]'
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
- name: 'Insight: Tempo de Resposta Total {#HOST_SITE}'
type: DEPENDENT
key: 'nginx.request_time.[{#HOST_SITE}]'
value_type: FLOAT
units: s
preprocessing:
- type: JAVASCRIPT
parameters:
- |
try {
// A variável 'value' contém a linha de log completa.
// A regex procura por "request_time": e captura o número que vem depois.
var regex = /"request_time":(\d+\.?\d*)/;
var match = value.match(regex);
// Se encontrar, match[1] conterá apenas o número (ex: "0.282").
if (match && match[1]) {
return match[1];
}
// Se não encontrar, descarta o valor.
return null;
} catch (e) {
// Se houver qualquer erro, também descarta.
return null;
}
master_item:
key: 'log[/var/log/nginx/{#HOST_SITE}.access.log]'
tags:
- tag: Insight
value: 'access log'
- name: 'Nginx: URI da Requisição {#HOST_SITE}'
type: DEPENDENT
key: 'nginx.request_uri.[{#HOST_SITE}]'
value_type: TEXT
preprocessing:
- type: JAVASCRIPT
parameters:
- |
try {
var regex = /"request_uri":"([^"]+)"/;
var match = value.match(regex);
if (match && match[1]) {
return match[1];
}
return null;
} catch (e) {
return null;
}
master_item:
key: 'log[/var/log/nginx/{#HOST_SITE}.access.log]'
tags:
- tag: Insight
value: cache
- tag: Insight
value: performance
graph_prototypes:
- name: 'Insight: Cache HITS {#HOST_SITE}'
yaxismax: '0'
percent_right: '20'
ymin_type_1: FIXED
graph_items:
- color: 199C0D
calc_fnc: ALL
item:
host: srvproxy001
key: 'nginx.cache.hits.5m.[{#HOST_SITE}]'
- sortorder: '1'
color: F63100
calc_fnc: ALL
item:
host: srvproxy001
key: 'nginx.cache.hits.15m.[{#HOST_SITE}]'
- sortorder: '2'
color: 2774A4
calc_fnc: ALL
item:
host: srvproxy001
key: 'nginx.cache.hits.24h.[{#HOST_SITE}]'
- sortorder: '3'
color: F7941D
calc_fnc: ALL
item:
host: srvproxy001
key: 'nginx.cache.hits.1m.[{#HOST_SITE}]'
- name: 'Insight: Cache HIT vs MISS {#HOST_SITE}'
show_work_period: 'NO'
show_triggers: 'NO'
type: PIE
graph_items:
- color: F63100
item:
host: srvproxy001
key: 'nginx.cache.miss.ratio.1m.[{#HOST_SITE}]'
- sortorder: '1'
color: 199C0D
item:
host: srvproxy001
key: 'nginx.cache.hit.ratio.1m.[{#HOST_SITE}]'
- name: 'Insight: Cache MISS {#HOST_SITE}'
yaxismax: '0'
percent_right: '20'
ymin_type_1: FIXED
graph_items:
- color: 199C0D
calc_fnc: ALL
item:
host: srvproxy001
key: 'nginx.cache.miss.1m.[{#HOST_SITE}]'
- sortorder: '1'
color: F63100
calc_fnc: ALL
item:
host: srvproxy001
key: 'nginx.cache.miss.5m.[{#HOST_SITE}]'
- sortorder: '2'
color: 2774A4
calc_fnc: ALL
item:
host: srvproxy001
key: 'nginx.cache.miss.15m.[{#HOST_SITE}]'
- sortorder: '3'
color: F7941D
calc_fnc: ALL
item:
host: srvproxy001
key: 'nginx.cache.miss.24h.[{#HOST_SITE}]'
- name: 'Insight: Requisições {#HOST_SITE}'
yaxismax: '0'
ymin_type_1: FIXED
graph_items:
- color: F63100
yaxisside: RIGHT
calc_fnc: ALL
item:
host: srvproxy001
key: 'nginx.requests.per_minute[{#HOST_SITE}]'
- sortorder: '1'
color: 199C0D
calc_fnc: ALL
item:
host: srvproxy001
key: 'nginx.requests.per_5minute[{#HOST_SITE}]'
- sortorder: '2'
color: 2774A4
calc_fnc: ALL
item:
host: srvproxy001
key: 'nginx.requests.per_15minute[{#HOST_SITE}]'
- sortorder: '3'
color: F7941D
calc_fnc: ALL
item:
host: srvproxy001
key: 'nginx.requests.per_24h[{#HOST_SITE}]'
- name: 'Insight: Saúde do Site {#HOST_SITE}'
show_work_period: 'NO'
graph_items:
- color: 199C0D
calc_fnc: ALL
item:
host: srvproxy001
key: 'net.tcp.service[http,"{$NGINX.STUB_STATUS.HOST}","{$NGINX.STUB_STATUS.PORT}"]'
- sortorder: '1'
color: F63100
calc_fnc: ALL
item:
host: srvproxy001
key: 'nginx.cache.hit.ratio.1m.[{#HOST_SITE}]'
- sortorder: '2'
color: F7941D
calc_fnc: ALL
item:
host: srvproxy001
key: 'nginx.request_time.avg.1m.[{#HOST_SITE}]'
- name: 'Insight: Tempo de Resposta vs Requisições {#HOST_SITE}'
ymin_type_1: FIXED
graph_items:
- sortorder: '1'
color: F63100
yaxisside: RIGHT
calc_fnc: ALL
item:
host: srvproxy001
key: 'nginx.requests.per_minute[{#HOST_SITE}]'
- sortorder: '2'
drawtype: FILLED_REGION
color: 199C0D
calc_fnc: ALL
item:
host: srvproxy001
key: 'nginx.request_time.[{#HOST_SITE}]'
- name: 'Insight: Tempos de Resposta {#HOST_SITE}'
percent_right: '20'
ymin_type_1: FIXED
graph_items:
- color: 199C0D
calc_fnc: ALL
item:
host: srvproxy001
key: 'nginx.request_time.avg.1m.[{#HOST_SITE}]'
- sortorder: '1'
color: F63100
calc_fnc: ALL
item:
host: srvproxy001
key: 'nginx.request_time.avg.5m.[{#HOST_SITE}]'
- sortorder: '2'
color: 2774A4
calc_fnc: ALL
item:
host: srvproxy001
key: 'nginx.request_time.avg.15m.[{#HOST_SITE}]'
preprocessing:
- type: JAVASCRIPT
parameters:
- |
// A variável 'value' é a string completa do UserParameter, contendo caminhos
// separados por vírgula, espaço e/ou quebra de linha.
// A Regex /[\s,]+/ divide a string em:
// - Vírgulas (,)
// - Espaços (incluindo múltiplos)
// - Quebras de linha (\n, \r)
// O filter(Boolean) remove quaisquer entradas vazias que o split possa gerar.
var full_paths = value.trim().split(/[\s,]+/).filter(Boolean);
var lld_data = [];
// Regex para extrair o nome do site:
// ^ -> Início do item (após o split)
// (.+) -> Captura o nome do site (o que for que esteja lá)
var regex = /^\/var\/log\/nginx\/(.+)\.access\.log$/;
// Itera sobre todos os caminhos.
for (var i = 0; i < full_paths.length; i++) {
var path = full_paths[i];
// Aplica a regex em cada item.
var match = path.match(regex);
// match[1] contém o nome do site capturado em (.+).
if (match && match[1]) {
lld_data.push({
"{#HOST_SITE}": match[1]
});
}
}
// Retorna o JSON LLD final.
return JSON.stringify({ "data": lld_data });
macros:
- macro: '{$NGINX.STUB_STATUS.HOST}'
value: 172.16.254.1
description: 'O hostname ou endereço IP do host Nginx ou do contêiner Nginx com `stub_status`.'
- macro: '{$NGINX.STUB_STATUS.PATH}'
value: nginx_status
description: 'The path of the `Nginx stub_status` page.'
- macro: '{$NGINX.STUB_STATUS.PORT}'
value: '8080'
description: 'The port of the `Nginx stub_status` host or container.'
inventory_mode: AUTOMATIC
inventory:
name: srvproxy001
os: 'Linux version 6.1.0-39-amd64 (debian-kernel@lists.debian.org) (gcc-12 (Debian 12.2.0-14+deb12u1) 12.2.0, GNU ld (GNU Binutils fo'