Este é o guia de instalação, configuração e manutenção do Arcivéo Monitor. As secções estão agrupadas: visão geral, implementação do painel, ligação de ferramentas de segurança, módulos integrados e diagnóstico. Pode copiar os comandos com o botão à direita.
A instalação do painel está em páginas dedicadas, passo a passo. Escolha o método:
Arcivéo Monitor — o painel de segurança do servidor. Recolhe dados das ferramentas instaladas (Fail2ban, UFW, Lynis, ModSecurity, AIDE, ClamAV, Auditd, CrowdSec, Suricata, Falco, etc.) e apresenta-os numa interface única, com dashboard, mapa de ataques e páginas detalhadas para cada ferramenta.
O Monitor não é um meio de proteção ativo — não bloqueia ataques por si só. A sua função é agregar a informação das ferramentas já em funcionamento e apresentá-la de forma prática.
O monitor funciona apenas localmente — tem de ser instalado no mesmo servidor que monitoriza. Não existe qualquer SSH nem API remota.
Todos os comandos (fail2ban-client, ufw status, ipset list, etc.) são executados pelo painel em nome do utilizador do servidor web (normalmente www-data, nos painéis de alojamento — a conta do site) com um conjunto restrito de permissões sudo — apenas para utilitários específicos, sem acesso root geral. Os resultados são analisados e apresentados no navegador.
A pontuação começa no máximo e diminui por cada problema detetado:
PermitRootLogin yes) — −20Resultado: 80+ = Protegido, 60–79 = Atenção, <60 = Em risco.
WebAuthn — norma de autenticação sem palavra-passe através de uma chave física. Suporta YubiKey, Touch ID, Face ID, Windows Hello e Passkey.
Após iniciar sessão com a palavra-passe, o sistema pede a confirmação através da chave registada. Mesmo que a palavra-passe seja divulgada, sem a chave física ou a biometria é impossível iniciar sessão.
Para configurar, abra Chaves WebAuthn no menu lateral e clique em «Registar chave». Registe logo duas chaves: se a única chave se perder ou avariar, o acesso ao painel através dela será impossível.
O painel pode enviar o relatório de segurança para o Telegram e por email (com um botão ou de forma agendada). Configura-se na secção «Definições».
Telegram. São necessários o token do bot e o chat id:
@BotFather → /newbot → obtenha o token do tipo 123456:ABC....@userinfobot ou abra https://api.telegram.org/bot<TOKEN>/getUpdates e procure "chat":{"id":...}.Email. Duas opções em «Definições» → Email:
re_...) e um domínio de remetente confirmado.Estado do relatório: «ATENÇÃO» ou «OK». O título passa a «ATENÇÃO» apenas perante um problema real ou uma ação pendente: ameaça detetada pelo ClamAV, alterações de ficheiros no AIDE, eventos críticos do Falco (Emergency/Alert/Critical nas últimas 24 h), serviço em falha no Monit, reinício necessário, SSL a expirar (≤14 dias) ou atualizações de segurança pendentes. O ruído de fundo — tentativas de força bruta de bots por SSH, IP banidos pelo fail2ban, alertas do Suricata, avisos do Lynis e pedidos já bloqueados pelo ModSecurity — não eleva o estado, por isso esses números no relatório não significam «ATENÇÃO» por si só.
Os módulos de monitorização detalhados (Lynis, UFW, ModSecurity, mapa de ataques, AIDE, ClamAV, etc.) ficam disponíveis com uma licença válida. Sem ela, o dashboard, as definições e a conta funcionam, mas os módulos mostram o cartão «Licença necessária».
Após a compra na área pessoal, tem um código de ativação no formato ARCIVEO-XXXX-XXXX-XXXX-XXXX. É preciso «ativá-lo» para o domínio do seu painel — isto transforma o código num ficheiro de licença assinado (bloco [license]), que insere no painel.
Como ativar (3 passos):
my.arciveo.com → secção «Licenças» / «Ativação de licença» — copie o código ARCIVEO-….monitor.example.com). Clique em ativar — o sistema gera um ficheiro de licença associado a esse domínio e mostra-o num campo com o botão «Copiar».O painel verifica a chave criptograficamente: a assinatura, a associação ao domínio e a validade.
APP_URL em config.php e introduza apenas o nome do host — sem https:// e sem o prefixo www. A ativação é única: o código transforma-se numa licença para o domínio introduzido e não volta a ser ativado — se errar o domínio, a chave não servirá ao seu painel e o código ficará gasto. Por isso, introduza o domínio com atenção.
Todos os parâmetros principais do painel estão definidos num único ficheiro config.php na raiz (junto à pasta public/), através de constantes define() normais. O ficheiro é criado durante a instalação; raramente é necessário editá-lo manualmente — sobretudo ao mudar de domínio, na migração ou ao ligar a outra base de dados. Após qualquer alteração, reinicie o PHP-FPM (caso contrário, devido ao OPcache, as alterações não serão aplicadas).
Introduza os seus valores nos locais realçados; deixe o resto como está:
Base de dados. Dados de ligação ao MySQL/MariaDB:
DB_HOST — anfitrião do SGBD, quase sempre localhost;DB_NAME — nome da base de dados do painel;DB_USER — utilizador da BD (acesso apenas à sua própria base);DB_PASS — palavra-passe deste utilizador;DB_CHARSET — codificação da ligação, deixe utf8mb4.Aplicação.
APP_URL — endereço completo do painel (ex.: https://monitor.example.com). Deve coincidir com o domínio no qual a licença foi ativada — caso contrário a chave será rejeitada (ver a secção «Licença»);TIMEZONE — fuso horário do PHP: afeta apenas a forma como o painel mostra datas e horas. No horário de execução das tarefas cron não influi — aí vigora o fuso do sistema (ver «Todas as tarefas cron»).Tempo de sessão. SESSION_LIFETIME — tempo limite de inatividade da sessão em segundos (deslizante: renova-se com a atividade). Por predefinição, 28800 = 8 horas; após esse tempo de inatividade o painel pedirá para iniciar sessão de novo. Por exemplo, 3600 = 1 hora, 86400 = um dia.
Registo de erros. Os erros nunca são mostrados aos visitantes; são escritos em logs/php_errors.log — podem ser vistos na página «Registos da aplicação». Estas linhas (display_errors=0, log_errors=1, o caminho error_log) normalmente não precisam de ser alteradas — as definições estão declaradas no próprio ficheiro e não dependem do php.ini.
public/), e neste painel a raiz web (DocumentRoot) é precisamente a raiz do painel, não o public/. O próprio ficheiro não «vaza»: no .htaccess da raiz existe uma proibição explícita para ele (Require all denied) — o servidor devolve 403. Mesmo sem essa regra o código-fonte não vazaria: é PHP — o servidor executa-o e não o devolve como texto. Por precaução: não o publique em repositórios públicos nem o envie ao suporte com a palavra-passe real. As permissões do ficheiro são 640.
UFW (Uncomplicated Firewall) — uma interface simples para nftables/iptables. Fecha todas as portas de entrada, exceto as explicitamente permitidas. A página «Firewall UFW» mostra o estado e as regras.
ufw enable, permita obrigatoriamente o SSH (ufw allow OpenSSH), caso contrário perderá o acesso ao servidor.
deny não é considerada acessível a partir do exterior.
Skipping adding existing rule — não é um erro. É assim que o UFW indica que já existe exatamente essa regra e não a adiciona novamente. Ao executar novamente a configuração automática (que é idempotente), esta é uma mensagem normal — não é necessário reagir.
Bloqueia automaticamente o IP após exceder o número de tentativas de início de sessão falhadas. Analisa os registos do SSH, Nginx, Apache e outros serviços.
A instalação básica está acima. Aqui fica a configuração operacional que gera dezenas de jails ativas e milhares de bloqueios: definições gerais, jails principais e banimento automático de IP maliciosos da lista ipsum.
Ficheiro /etc/fail2ban/jail.local — definições gerais e as jails mais importantes:
ignoreip indique obrigatoriamente o seu IP e as redes de confiança, caso contrário pode banir-se a si próprio. Após as alterações: sudo fail2ban-client reload.
Carregamento automático da lista de bloqueio ipsum — no cron do root (sudo crontab -e): o level 1 (mais de 100 mil IP) é carregado no conjunto ipsum, que é filtrado na firewall (mais detalhes na secção «Lista de bloqueio IPset»):
ipsum — é esse que o dashboard lê (cartão «IPset ipsum»). Níveis: levels/1.txt — cobertura máxima, levels/3.txt — mais preciso (3+ fontes).
Porque é que o «Monitor de segurança» está dividido em duas zonas. A proteção funciona em dois níveis, e o dashboard não os mistura:
sshd, apache-*, nginx-*, etc.) e reincidentes graves (jail recidive — os que já foram banidos várias vezes). São IP que realmente o atacaram — estão no mapa de ataques e na «Linha temporal».ipset ipsum, filtrada na firewall pela regra DROP. Na sua maioria, estes endereços nem sequer chegaram ao seu servidor — são cortados antecipadamente; o contador «IPset ipsum» mostra quantos foram filtrados preventivamente.A diferença é simples: reativo — «estes atacaram e foram banidos», preventivo — «estes foram bloqueados antes sequer de tentar». Antes, a level-3 do ipsum era colocada artificialmente na recidive (daí a antiga divisão «recidive por lista»); agora a recidive contém apenas reincidentes verdadeiros, e o preventivo fica inteiramente na firewall.
ipsum — lista pública de IP maliciosos, atualizada diariamente. O Monitor mostra o número de endereços carregados no painel e no mapa de ataques e considera-o na Avaliação de segurança (−10 se o conjunto não estiver carregado).
Variante mínima sem fail2ban — um conjunto ipsum separado com bloqueio através de iptables:
@reboot. Ao mesmo tempo, o comando create … -exist define o limite maxelem 300000 (por predefinição 65536 — o level 1 não cabe, dando «Hash is full»):
ipsum e, se a firewall for gerida pelo instalador (VPS novo — perfis «Completa»/«Ligeira»), liga o conjunto ao UFW com uma regra DROP — o tráfego desses IP é realmente bloqueado. A regra fica depois de ESTABLISHED,RELATED, por isso as ligações atuais (incluindo o seu SSH) não são cortadas — só se bloqueiam novas ligações da lista. O conjunto é restaurado no arranque do serviço ipsum-load.service antes da firewall (caso contrário o UFW não arrancaria) e é atualizado pelo cron às 04:00. Num servidor já configurado (painel, firewall próprio) o instalador não mexe na firewall — aí o ipsum permanece como lista para o painel e o mapa de ataques, e a regra DROP é adicionada manualmente se assim o desejar (a variante mínima com iptables … --match-set ipsum … -j DROP está acima). Na instalação automática não é preciso fazer nada manualmente.
Substituto moderno do Fail2ban com threat intelligence coletiva: bloqueios da comunidade mais regras próprias. Requer um bouncer separado para aplicar os bloqueios à firewall.
systemctl is-active crowdsec). Iniciar: sudo systemctl enable --now crowdsec; em caso de falha, consultar sudo journalctl -u crowdsec -n 30. A mesma regra aplica-se a qualquer serviço no estado «Não iniciado» (Suricata, Falco, Monit, MySQL).
stream halted / os bloqueios não são aplicados. Trata-se de uma chave de API órfã: o bouncer foi removido de cscli bouncers list, mas a sua chave antiga permaneceu em /etc/crowdsec/bouncers/*.yaml. Volte a registar o bouncer e defina a nova chave:
AIDE (Advanced Intrusion Detection Environment) tira uma imagem do sistema de ficheiros e, em cada verificação, comunica alterações em /etc, /bin, /usr. Após a instalação, é obrigatório inicializar a base de dados (aideinit).
aideinit o terminal fica 5–15 minutos parado na linha Running aide --init... — é normal (hashing de todo o sistema de ficheiros, carga no disco). Não interrompa com Ctrl+C. Se o processo parecer «pendurado» mas não escrever nada — talvez esteja à espera de resposta a um pedido oculto Overwrite existing aide.db.new [Yn]? (prima Y). Verifique a atividade a partir de outra sessão: pgrep -af aide.
aideinit: «21_aide_spamassassin … printf: invalid number» (return code 20) — bug conhecido do snippet de configuração do AIDE no Ubuntu 22.04. A base de dados não é criada. Remova o snippet defeituoso e repita:
aideinit nunca foi executado, ou (Ubuntu 24.04) a diretoria /var/lib/aide foi criada em modo 700 e está inacessível ao www-data — resolve-se com sudo chmod 755 /var/lib/aide (ver o bloco acima). «Sem verificações» = a base existe, mas ainda não foi feita nenhuma verificação — não é um erro. O monitor lê os resultados de /var/log/aide/aide.log.
/etc/cron.daily/aide padrão nas versões recentes de Ubuntu/Debian pode não escrever /var/log/aide/aide.log no formato esperado (e o aide.wrapper já não existe nelas). É mais fiável adicionar o seu próprio cron com --config explícito — este escreve o log em nome de root no modo 644, e o monitor lê-o sem grupos adicionais:
chmod 755 /var/lib/aide e o cron de verificação às 02:00 — não é preciso fazer nada manualmente.
sudo aideinit && sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db.
Antivírus para Linux. É especialmente útil para verificar /var/www em busca de shells PHP e código malicioso.
enable --now? Três causas típicas:
1. Ficou no ficheiro de configuração a linha Example — o clamd recusa-se a iniciar enquanto ela existir:
2. A base de assinaturas não foi descarregada — o clamd não inicia sem ela:
3. Está simplesmente a carregar — o clamd carrega ~8 milhões de assinaturas para a memória em 30–60 seg. Aguarde e verifique: systemctl is-active clamav-daemon (estado activating → ainda a carregar).
sudo journalctl -u clamav-daemon -n 30 --no-pager.
clamd apenas mantém as assinaturas na memória, ele próprio não analisa nada por agendamento. O painel mostra os resultados da análise agendada, por isso é necessário um cron que analise e escreva o registo. A instalação automática coloca o invólucro /usr/local/bin/clamav-scan.sh e um cron às 01:30 — após a primeira execução preenchem-se «Ficheiros analisados» e «Última análise». Para executar já, sem esperar pelo agendamento: sudo /usr/local/bin/clamav-scan.sh.
Linux Malware Detect (LMD) — analisador de software malicioso para ameaças web: shells PHP, backdoors web, downloaders. Usa o motor do ClamAV e complementa-o com as suas próprias assinaturas.
maldet --report.
update-rc.d: error: unable to read /etc/init.d/maldet — é inofensiva. O maldet não usa o init.d; a atualização de assinaturas e as análises são executadas via /etc/cron.daily/maldet. Se abaixo vir installation completed, então instalou tudo.
apt, mas sim em /usr/local/maldetect, e com o open_basedir ativo a sua presença é verificada via shell — consulte a secção «A página está vazia apesar de haver dados no servidor».
Sistema de deteção de intrusões na rede: analisa o tráfego ao nível dos pacotes e conhece milhares de assinaturas de ataques. Complementa o ModSecurity (este atua ao nível HTTP, o Suricata ao nível TCP/IP).
/var/log/suricata/eve.json como root com permissões 750 na diretoria, e o servidor web (www-data) não a consegue ler. Abra a diretoria para acesso — os ficheiros dentro dela permanecem protegidos:
Interceta chamadas de sistema através de eBPF/kernel module e deteta anomalias em tempo real: shell a partir do nginx, leitura de /etc/passwd por um processo web, escrita em /bin, etc.
journalctl -u falco (sem sudo — pelo grupo systemd-journal). Certifique-se de que o www-data está nesse grupo — consulte «Configuração de sudo» (ponto 2) na página de instalação manual.
/etc/passwd, escrita em diretórios do sistema). Zero eventos críticos num dia num servidor calmo é um estado saudável.
journalctl exige permissões sobre o journal; para que o painel veja os eventos de forma estável, a instalação automática ativa no Falco o file_output → /var/log/falco/falco.log e define UMask=0022 no serviço (o log é lido pelo servidor web). Numa nova instalação não é necessário configurar isto manualmente.
ModSecurity — firewall de aplicações web (WAF) para Apache ou Nginx. Bloqueia ataques ao nível da aplicação: injeções SQL, XSS, travessia de diretórios, scanners.
IncludeOptional /etc/modsecurity/*.conf, mas o pacote instala apenas modsecurity.conf-recommended — que não corresponde à máscara *.conf. Se não o copiar para modsecurity.conf, o SecRuleEngine mantém-se Off: o módulo está carregado, as regras CRS estão carregadas, mas o tráfego não é verificado e o registo de auditoria não é criado. O modo intermédio DetectionOnly apenas escreve eventos no registo, sem bloquear pedidos — o painel apresenta-o a amarelo.
Acesso do painel ao registo de auditoria. O registo /var/log/apache2/modsec_audit.log pertence ao root (permissões 640), o utilizador web não o consegue ler. O painel obtém os dados através de um wrapper — crie-o:
SecRuleEngine sem indentação: as linhas indentadas estão dentro de blocos <LocationMatch>/<Directory> (por exemplo, a desativação do WAF para o phpMyAdmin) e não definem o modo global.www-data, no HestiaCP o pool do site corre com o dono do site (por exemplo, admin) — verifique com grep -E '^user' /etc/php/*/fpm/pool.d/monitor.example.com.conf.X-Forwarded-For. Só entram nas estatísticas as transações com uma regra acionada: a diretiva SecAuditLogRelevantStatus escreve no registo de auditoria quaisquer respostas 4xx/5xx, por isso também lá entram os 403/500 normais — o painel não os conta como eventos do WAF.---RULES--- é necessário para a secção «Todas as regras ativas» — o painel apresenta não só as regras acionadas, mas todas as regras CRS carregadas + as personalizadas. Os três caminhos no ciclo for f in … são os locais típicos para as regras CRS e para as adições locais; se tiver uma disposição diferente (o pacote coloca os ficheiros no seu próprio diretório, ou as regras personalizadas não estão em /etc/modsecurity/custom-rules.conf), encontre os caminhos reais com o comando sudo grep -rl 'IncludeOptional\|^Include ' /etc/apache2/mods-enabled/security2.conf /etc/apache2/conf-enabled/*.conf 2>/dev/null e coloque-os na lista. Se o wrapper for antigo (sem esta secção) — a secção apenas apresenta o aviso «indisponível», o resto da página funciona como antes.
Auditd (Linux Audit Daemon) regista chamadas de sistema ao nível do kernel: inícios e términos de sessão, comandos sudo, tentativas de autenticação falhadas e alterações de ficheiros. O Monitor mostra os inícios de sessão, as tentativas falhadas e os comandos sudo de hoje.
ausearch (/usr/sbin/ausearch) e, se necessário, a partir de /var/log/audit/audit.log com o comando tail. Ambos têm de estar no sudoers.
Vigia os serviços (nginx, php-fpm, mysql, etc.) e reinicia-os em caso de falha. Pode enviar alertas por email.
monit status. Em /etc/monit/monitrc a interface HTTP deve estar ativada (bloco set httpd com allow localhost), caso contrário monit status devolve um erro.
monitrc a linha set httpd está comentada (por predefinição surge como # set httpd port 2812 …). Descomente o bloco e permita o localhost. (2) O httpd ativado por si só não monitoriza nada — o Monit considera apenas o que está descrito em blocos check; sem eles a lista fica vazia mesmo com a interface a funcionar. Configuração mínima funcional:
conf.d pronto com httpd na 2812 e um conjunto de verificações — numa instalação nova não é preciso configurar manualmente.
PSAD analisa o registo do iptables e deteta varrimentos de portas e ataques de rede, atribuindo a cada origem um nível de ameaça (1–5). Complementa o fail2ban e o Suricata.
psad --Status (necessário no sudoers). Sem o registo do iptables, a página fica vazia — é normal enquanto não houver varrimentos.
O Mandatory Access Control limita a que ficheiros e recursos um programa pode aceder, mesmo que este tenha sido comprometido. No Ubuntu/Debian, é usado por predefinição o AppArmor (normalmente já instalado e ativo).
aa-status (necessário no sudoers). Mostra o número de perfis em modo enforce/complain e os processos sem perfil.
«Perfis carregados» ser mais do que enforce + complain é normal. No AppArmor 4.x (Ubuntu 24.04 e mais recente) surgiu o modo unconfined: o perfil está carregado no kernel, mas não limita nada. O Ubuntu marca assim dezenas de perfis para programas que usam user namespaces (navegadores, clientes torrent e afins). Quando existem esses perfis, o cartão «Perfis carregados» fica âmbar e mostra o seu número — por exemplo unconfined: 90 com 120 carregados e 26 em enforce. Só protegem de facto os perfis em enforce; no Ubuntu 22.04 (AppArmor 3.x) este modo não existe e os números batem sempre certo.
unconfined só deve ser feito de forma consciente: não estão desativados por engano, mas porque de outro modo os próprios programas deixam de funcionar. Os perfis em complain são outra questão: aí as regras já estão escritas e apenas não são aplicadas.
O debsums verifica se os ficheiros dos pacotes instalados coincidem com as somas de verificação do repositório — deteta binários de sistema adulterados (complementa o AIDE). Uma verificação completa demora 1–2 minutos, por isso é executada por cron, e o painel lê o resultado de data/debsums/debsums.log e classifica-o por categorias (só importam os binários e as bibliotecas).
A tarefa fica no cron do root (sudo crontab -e). O wrapper pronto debsums-scan.sh é colocado em /usr/local/bin/ (chmod +x; ver o resumo das tarefas cron) e ele próprio grava o relatório em data/debsums/ do painel.
O wrapper debsums-scan.sh encontra sozinho a pasta data/ do painel — não é preciso indicar o caminho.
/etc/ (configurações) e /usr/share/ (recursos) no servidor costumam ser normais — o painel assinala-as com uma cor distinta. Preocupantes são as alterações de binários e bibliotecas (/bin, /sbin, /usr/lib, etc.) — o cartão «Binários / bibliotecas» mostra precisamente essas.
O Lynis é executado manualmente ou por cron. O relatório deve ser guardado na pasta data/lynis/ do projeto — o monitor lê o ficheiro lynis-report.dat.
lynis-scan.sh em segundo plano diretamente a partir do painel (sem esperar pelo cron): mostra «A analisar…» e, ao concluir, atualiza o relatório automaticamente. Para isso, o utilizador web precisa de uma linha no sudoers para executar o script — o instalador adiciona-a automaticamente em /etc/sudoers.d/monitor. Se o painel foi instalado manualmente/anteriormente, acrescente-a com o mesmo utilizador já indicado no ficheiro:
O Logwatch deve guardar os relatórios diários na pasta data/logwatch/ do projeto em formato .txt. O monitor mostra o último relatório e o arquivo.
O monitor de rede não requer instalação — é uma página integrada no painel. Mostra o estado de rede do servidor a partir de fontes locais:
/proc/net/dev;ip;ss;journalctl -k.As três primeiras fontes funcionam sem sudo, por isso as interfaces, o tráfego, as ligações e as portas ficam visíveis de imediato. O bloco «Eventos do kernel» utiliza journalctl -k — é lido através do grupo systemd-journal («Configuração do sudo», p.2), não é preciso sudo. Para verificar que tudo está acessível ao utilizador web:
UFW BLOCK não aparecem aqui — estão nas páginas «Firewall UFW» e «Mapa de ataques». Um bloco vazio com um visto verde = não houve falhas de rede nas últimas 24 horas.
A página integrada mostra três coisas:
df); a barra fica vermelha a partir de ≥90%;lsblk), apenas os reais (loop/snap ocultos);smartctl).O espaço e a lista de dispositivos funcionam de imediato, sem configuração. Para o SMART é necessário o pacote smartmontools. O processo web não tem acesso direto aos dispositivos de disco, por isso o SMART é recolhido por cron para o ficheiro data/disk/smart.txt, e o painel lê-o.
A tarefa fica no cron do root (sudo crontab -e). O wrapper pronto smart-scan.sh é colocado em /usr/local/bin/ (chmod +x; ver o resumo das tarefas cron) e escreve ele próprio em data/disk/ do painel.
O wrapper smart-scan.sh encontra ele próprio a pasta data/ do painel — não é preciso indicar o caminho. Internamente, lsblk -e7,11 exclui loop/cdrom.
A página mostra o histórico de carga do servidor nas últimas 24 horas — Load Average, ocupação da CPU e espera de I/O, RAM/Swap, tráfego de rede (receção/envio), I/O de disco (leitura/escrita), ocupação do disco e inodes, descritores de ficheiro abertos e ligações MySQL, além do número atual de ligações TCP e processos.
Os dados são recolhidos pelo cron/collect_metrics.php — a cada 5 minutos regista um instantâneo «em bruto» dos contadores (/proc/loadavg, /proc/meminfo, /proc/stat, /proc/net/dev, /proc/diskstats, df/df -i, /proc/sys/fs/file-nr, SHOW GLOBAL STATUS LIKE 'Threads_connected') na tabela da BD system_metrics; as percentagens e velocidades são calculadas pela própria página com base na diferença entre instantâneos consecutivos (ocupação do disco/inodes/descritores/ligações MySQL — valores instantâneos, sem recálculo). Não é necessário sudo — as fontes são lidas sem privilégios de root. Os pontos com mais de 24 horas são eliminados automaticamente a cada registo.
O wrapper collect-metrics-all.sh (ver o resumo das tarefas cron) encontra automaticamente todas as instâncias do painel instaladas no servidor e executa o cron/collect_metrics.php de cada uma em nome do proprietário do site.
Alertas de carga (secção «Definições» → «Alertas de carga») — ao ultrapassar o limite de CPU/RAM/disco/inodes, o painel envia uma notificação para Telegram/Email (os mesmos canais do relatório diário — não é preciso ativá-los à parte para os alertas), e mais uma quando a métrica regressa ao normal. Não faz spam enquanto o limite se mantém: a notificação seguinte só chega depois do ciclo «recuperou → voltou a ultrapassar».
collect_metrics.php a cada execução (a cada 5 minutos) — não é preciso um cron à parte. O estado «já notificado / ainda não» é guardado em data/alerts_state.json, e os limites nas definições do painel.
A página «Mapa de ataques» determina o país a partir do IP com o comando geoiplookup. Sem o pacote GeoIP os países não são determinados e os pontos não aparecem no mapa:
/usr/share/GeoIP/GeoIP.dat é lida por todos, os resultados ficam em cache em tmp/geoip_cache.json. O próprio mapa (Leaflet + tiles do OpenStreetMap) carrega no navegador — é preciso Internet no computador onde o painel está aberto.
Dois cartões integrados no dashboard que mostram não o «ligado/desligado» de uma ferramenta, mas a proteção real do servidor. Não requerem instalação e são lidos localmente sem sudo.
Exposição externa — quantos serviços escutam todas as interfaces (0.0.0.0/[::]) e estão acessíveis do exterior. Fica vermelho se uma base de dados ou cache estiver exposta (MySQL, PostgreSQL, Redis, MongoDB, Memcached, Elasticsearch) — é uma falha direta (−10 na Pontuação de segurança). Fonte: ss -tuln.
127.0.0.1 (bind-address na configuração do MySQL/PostgreSQL, bind 127.0.0.1 no Redis) ou feche a porta na UFW.
127.0.0.1 (loopback) só é visível para o próprio servidor — não é alcançável de fora, mesmo que a porta esteja «aberta». Por isso o Postfix na porta 25, associado ao loopback, é seguro: a configuração automática define inet_interfaces = loopback-only (mais um smtpd_banner neutro — resolve o aviso Lynis MAIL-8818 sobre a exposição da versão). O cartão «Exposição externa» conta como externo apenas o que escuta em 0.0.0.0/[::]; os serviços em loopback não entram nessa conta.
/etc/postfix/main.cf defina smtpd_banner = $myhostname ESMTP (sem versão nem SO) e inet_interfaces = loopback-only, depois sudo systemctl restart postfix.
Atualizações de segurança — quantos patches de segurança aguardam instalação e se é necessário reiniciar após a atualização do kernel (−5 na Pontuação de segurança se houver patches). Fonte: /usr/lib/update-notifier/apt-check, ficheiro /var/run/reboot-required. Lista detalhada — na página «Atualizações de segurança».
update-notifier-common). Se o apt-check não existir — o monitor calcula os patches através de apt-get -s upgrade.
Atualizações de segurança automáticas (unattended-upgrades) — na página «Atualizações de segurança» um cartão à parte mostra se a instalação automática de patches de segurança está ativa e quando foi executada pela última vez. Não é preciso sudo — o estado é lido através de apt-config dump.
A cópia de segurança é o seguro principal: a perda de dados é pior do que qualquer intrusão. São precisas duas coisas — cópia do servidor/sites e, à parte, cópia da BD do painel (contém utilizadores, chaves WebAuthn, definições, licença).
Opção A — HestiaCP: separador Backup do utilizador → botão de criação de cópia (ou por agendamento nas definições do servidor). A cópia inclui os sites e as respetivas BD.
Opção B — manual (cron): dump da BD + arquivo do diretório data/ do painel:
Atualização para uma nova versão. Comece por fazer uma cópia de segurança. Depois, volte a carregar os ficheiros de código, mantendo os seus dados:
public/, includes/, assets/, cron/, database/, bem como os .htaccess de raiz (o controlador frontal — o encaminhamento não pode ficar da versão antiga), manifest.json, sw.js;config.php (dados da BD), data/ (relatórios), logs/, tmp/ (sessões e cache).SSH_FX_PERMISSION_DENIED — Permission denied. Os ficheiros do painel pertencem ao www-data (foi assim que ficaram definidos na instalação), enquanto o cliente SFTP se liga com o seu próprio utilizador, que não tem permissão de escrita. Entregar todo o painel ao www-data «para funcionar» é precisamente o que causa este erro; abaixo há três formas, qualquer uma resolve o problema.
data/ (relatórios), tmp/ (sessões e cache), logs/; que continuam a pertencer ao www-data. O restante é código, e o servidor web só precisa dele para leitura, garantida pelo grupo www-data com permissões 644. Vantagem adicional: em caso de falha no PHP, os ficheiros do painel já não podem ser reescritos. Em painéis de alojamento (HestiaCP e semelhantes) a variante A não é necessária: aí os ficheiros do site já pertencem à conta com que se liga por SFTP, e o servidor web lê-os pelo grupo.
chmod posterior sobre os ficheiros repõe a máscara da ACL e o acesso desaparece silenciosamente. Se, depois de «arrumar as permissões», o carregamento voltar a esbarrar em Permission denied, repita ambos os comandos setfacl.
2 na variante C é o setgid: os ficheiros enviados por SFTP permanecem no grupo www-data, caso contrário o painel não os consegue substituir. Depois da variante C volte a ligar-se no FileZilla — o novo grupo só passa a valer numa nova sessão. Verificação: id deploy (deve aparecer o grupo www-data) e ls -ld /path/to/monitor (drwxrwsr-x — a letra s significa que o setgid está ativo).
Migração para outro servidor:
config.php, data/.mysqldump no antigo → importar no novo; corrija os dados da BD em config.php.adm, tarefas cron.Se não conseguir iniciar sessão, tudo se resolve diretamente na BD a partir do servidor. Abra a BD (o nome está em config.php):
Chave WebAuthn perdida (o segundo fator não passa) — desative o 2FA, inicie sessão com a palavra-passe e registe uma nova chave:
Palavra-passe esquecida — defina um novo hash (gere-o no servidor e insira-o):
Bloqueou-se a si próprio com o filtro de IP — desative a restrição:
sudo mysql no servidor, ou o phpMyAdmin / secção da BD no painel do alojamento. Após a recuperação, volte a ativar o WebAuthn e o filtro de IP.
O resumo das tarefas fica no cron root do servidor (adicionadas via sudo crontab -e). Deixe apenas as linhas das ferramentas que usa; ajuste os caminhos ao seu servidor.
sudo crontab -l e que o serviço cron está ativo.
TIMEZONE do config.php. A constante TIMEZONE afeta apenas o PHP (como o painel mostra as datas), mas o daemon cron executa as tarefas pela hora do sistema operativo. Se o fuso do servidor não coincidir com o seu, o relatório «08:00» chegará à hora errada. Exemplo: o servidor está noutro fuso (UTC, UTC+0) e o utilizador está em Lisboa (UTC+1) → o relatório «08:00» chega às 09:00 pelo seu fuso. Verifique e, se necessário, alinhe o fuso do sistema com o seu:
0 8 * * * será executada às 08:00 pela hora local. Caso contrário, teria de deslocar o próprio cron, mas na mudança para a hora de inverno/verão o desfasamento voltaria a divergir — por isso é mais correto configurar o fuso do sistema.
crontab.txt) estão na pasta system/ junto ao projeto, fora de public_html. Isto não faz parte do site — não é preciso carregá-los para a raiz web; coloque-os no servidor nos caminhos de sistema (como no crontab acima):
lynis-scan.sh → /usr/local/bin/ (chmod +x) — executa lynis audit system, durante a análise coloca a flag /tmp/lynis-running e copia lynis-report.dat para data/lynis/ do painel;logwatch_daily.sh → /usr/local/bin/ (chmod +x) — gera o relatório diário Logwatch (sshd, fail2ban, sudo, postfix) em data/logwatch/;smart-scan.sh → /usr/local/bin/ (chmod +x) — recolhe o estado dos discos (smartctl) em data/disk/;debsums-scan.sh → /usr/local/bin/ (chmod +x) — verifica a integridade dos pacotes (debsums) em data/debsums/;clamav-scan.sh → /usr/local/bin/ (chmod +x) — análise antivírus ClamAV por caminhos perigosos (web, home, temp); escreve o resumo em /var/log/clamav/scan.log, de onde a página ClamAV o lê (linha 01:30 no crontab acima);load-ipsum.sh → /usr/local/bin/ (chmod +x) — atualiza o conjunto ipset ipsum (level 1) no lugar, sem quebrar as regras ativas da firewall (linha 04:00 no crontab acima);daily-report-all.sh → /usr/local/bin/ (chmod +x) — executa o relatório cron/daily_report.php do painel (linha 08:00 no crontab acima);daily_report.php — já faz parte do painel (cron/daily_report.php), é executado via daily-report-all.sh, não é preciso instalá-lo à parte;collect-metrics-all.sh → /usr/local/bin/ (chmod +x) — executa cron/collect_metrics.php do painel (página «Desempenho», linha */5 no crontab acima); o collect_metrics.php já faz parte do painel, não é preciso instalá-lo à parte;crontab.txt (system/cron/) — modelo de tarefas; inscreva as linhas necessárias via sudo crontab -e./usr/local/bin/. Não é possível gravar diretamente para lá a partir do FileZilla — o diretório pertence ao root, e o cliente SFTP receberá SSH_FX_PERMISSION_DENIED. O procedimento é este: primeiro carregar o ficheiro para /tmp (onde todos podem escrever) e depois movê-lo para o local com um só comando:
/tmp na raiz do servidor — não /var/tmp nem tmp/ dentro do próprio painel (este último pertence ao www-data e está fechado ao seu utilizador). Na árvore do FileZilla, /tmp é um ramo de topo, ao lado de var, e não dentro dele.
/usr/local/bin/, o log é /var/log/arciveo-cron.log) — não é preciso fazer nada manualmente.
/home/*/web/*/public_html e /var/www/*, e colocam os relatórios nos respetivos data/. Se o painel estiver noutro caminho — adicione-o à linha for app in … dentro dos scripts, senão os relatórios do Lynis/SMART/debsums/Logwatch não chegam ao painel.
logs/cron.log é criado primeiro pelo cron root — pertencerá ao root, e o separador «Registo do cron» no painel não conseguirá lê-lo nem limpá-lo. Crie o ficheiro previamente como utilizador web (dono do diretório do site; no HestiaCP é a conta, p. ex. admin) — assim o cron root apenas acrescenta, sem mudar o dono:
stat -c %U /path/to/monitor.
sudo crontab -e), senão será executada duas vezes.
sudo crontab puro (seria uma escalada direta para root por qualquer pessoa que obtivesse acesso à sessão do painel), mas de um script restrito com dois comandos (list/set), que só toca no seu bloco entre os comentários de serviço. Instale uma vez:
www-data — verifique com que utilizador corre o pool PHP-FPM do site (ps -o user= -C php-fpm) e substitua-o na linha do sudoers.
public/crontab_monitor.php foi carregado por FTP/SFTP com um utilizador de sistema diferente (por exemplo, root) do dos restantes ficheiros do site, o servidor web não conseguirá lê-lo. Compare o dono e as permissões com um ficheiro vizinho e alinhe-os:
O monitor deteta a presença de ferramentas através do dpkg-query — a base de pacotes APT. Se a ferramenta não tiver sido instalada através do apt (manualmente, via snap ou a partir do código-fonte), o dpkg não a vê.
Erro 500 — verifique os registos do PHP, do nginx e do próprio monitor:
www-data, mas sob a conta do utilizador (por exemplo admin — proprietário do diretório do site). Todas as regras sudo e a pertença a grupos (adm, systemd-journal) têm de ser definidas para esse utilizador, caso contrário os módulos mostrarão «Inativo / 0» com os serviços a funcionar. Para saber o utilizador real do PHP: ps -o user= -C php-fpm | sort -u ou o proprietário do diretório do site stat -c '%U' /path/to/monitor. A seguir, em todos os comandos abaixo, use-o em vez de www-data. A instalação automática deteta o utilizador web por si própria e configura o sudoers para ele.
Os dados não são apresentados — quase sempre por permissões sudo não definidas. Verifique o comando concreto em nome do utilizador web (substitua www-data pelo seu). A flag -n = sem palavra-passe, como no PHP — se pedir palavra-passe, é porque não há regra no sudoers:
sudo aa-status no terminal mostra os perfis, mas a página «AppArmor» diz «Inativo»). Motivo: o utilizador web não tem permissão sudo para o comando desse módulo. Verifique-o na lista acima: se pedir palavra-passe — acrescente a linha em falta em /etc/sudoers.d/monitor («Configuração do sudo»). Comandos «novos» frequentes: /usr/sbin/aa-status (MAC), /usr/sbin/psad --Status (PSAD).
apache2ctl, ausearch, aa-status ou ss, ou o utilizador web não está nos grupos adm/systemd-journal (é de lá que se leem os registos do fail2ban/auth/modsec e o journalctl — Falco e eventos do núcleo).
Sintoma: no servidor há dados (visíveis via shell), mas a página mostra «sem dados» ou um estado incorreto — por exemplo, o AIDE indica «Não inicializada», embora a base tenha sido criada.
A causa é o open_basedir: muitos painéis e alojamentos restringem o pool do PHP-FPM ao diretório do domínio, por isso as funções PHP file_exists(), file_get_contents(), filemtime() ficam bloqueadas para caminhos de sistema (/var/lib/aide, /var/log, /proc…). O Monitor contorna isto lendo esses caminhos com comandos de sistema padrão (cat, test, stat).
open_basedir. A solução correta é a leitura por comandos de sistema (já feito para o AIDE e o Monitor de rede). Alargar o open_basedir a /var, /proc não é necessário e é menos seguro.
O monitor verifica os certificados ligando-se diretamente aos domínios pela porta 443. Se o domínio estiver inacessível a partir do próprio servidor ou a porta estiver fechada pela firewall, a verificação falha.
/etc/nginx/sites-enabled/, /etc/nginx/conf.d/) e do Apache (/etc/apache2/sites-enabled/), mais o host atual de HTTP_HOST.
O monitor liga-se ao MySQL com o utilizador de config.php, que só tem acesso à sua própria base de dados. O MySQL mostra em information_schema apenas as bases com privilégios — por isso as restantes não aparecem.
Para que o monitor veja todas as BD, conceda a este utilizador permissão apenas de leitura (uma vez como root; substitua o nome do utilizador de config.php):
sudo mysql: a lista de bases é obtida através da sua própria ligação PDO.
O PostgreSQL exige acesso ao nível do utilizador postgres, que o utilizador web do painel não tem. Expor um sudo psql amplo a partir do PHP é inseguro — em vez disso, o painel invoca uma camada restrita sem parâmetros, que apenas imprime a versão, o número de ligações e a lista de bases com os respetivos tamanhos. Crie-a:
monitor-pgstat do sudoers (passo 13 da instalação manual) e não crie o script: o cartão do PostgreSQL fica apenas inativo.
O painel mostra o que está a acontecer; abaixo, o que fazer em situações típicas. Princípio geral: não entrar em pânico, comparar com a atividade legítima (as suas ações, atualizações, backups) e reagir consoante a gravidade.
ignoreip./etc, fora de /usr/share) — possível substituição. Verifique o pacote: debsums PACKAGE_NAME e, em caso de dúvida, reinstale-o (apt install --reinstall).127.0.0.1 ou feche a porta na UFW. É uma falha real.certbot renew ou as definições no painel).sudo apt update && sudo apt upgrade; após atualizar o kernel, reinicie o servidor.