Instalação totalmente manual: de um VPS acabado de adquirir até um painel operacional, passo a passo.
A preparação do servidor, a criação do site, a base de dados, o config.php e o SSL são descritos aqui.
Os comandos de cada ferramenta de segurança e do cron estão no
guia de FAQ, com ligações ao longo do texto.
Regra de ouro: ao alterar o SSH ou a firewall, não feche a ligação atual enquanto não tiver testado a nova numa janela separada. Se ainda assim perder o acesso — quase todos os alojamentos disponibilizam uma consola de emergência (VNC/Recovery) no painel de controlo.
01. Comprei um VPS com Ubuntu/Debian — por onde começar
Após a compra, o fornecedor de alojamento envia: endereço IP, nome de utilizador (normalmente root) e palavra-passe (ou chave SSH). É o suficiente para iniciar sessão. Sequência de ações (cada passo é uma secção abaixo):
Ligar ao servidor via SSH;
Atualizar o sistema, definir o nome de anfitrião e o fuso horário;
Criar um utilizador normal com permissões sudo (não trabalhar como root);
Configurar o início de sessão por chave SSH e desativar o início de sessão por palavra-passe;
Ativar a firewall e a autoproteção;
(opcional) instalar o painel de controlo HestiaCP — servidor web, base de dados e correio prontos a usar.
02. Primeira ligação via SSH
SSH é um terminal seguro para o servidor. Substitua o seu IP por 203.0.113.10.
203.0.113.10 é um exemplo, um endereço inexistente (reservado para documentação). Não o introduza tal como está — substitua-o pelo IP real do seu servidor indicado no e-mail do fornecedor de alojamento. Caso contrário, não haverá ligação.
Windows 10/11: abra o PowerShell ou o «Terminal» e utilize o ssh integrado (ou os clientes PuTTY / MobaXterm). macOS / Linux: abra o «Terminal».
# Entrar como root (a palavra-passe foi enviada pelo fornecedor de alojamento):
ssh root@203.0.113.10
# Se o fornecedor de alojamento deu um ficheiro-chave em vez da palavra-passe:
ssh -i caminho/para/chave root@203.0.113.10
Na primeira ligação, o SSH pergunta sobre a «authenticity of host» — introduza yes. A palavra-passe não é apresentada ao ser digitada (é normal). Se o fornecedor de alojamento deu uma palavra-passe temporária, altere-a com o comando passwd.
03. Atualização do sistema e configuração básica
Antes de tudo — atualize todos os pacotes e defina o nome de anfitrião e o fuso horário.
# Atualizar o sistema:
apt update && apt upgrade -y
# Utilitários básicos:
apt install -y curl wget ufw fail2ban unattended-upgrades
# Fuso horário (exemplo) e nome de anfitrião:
timedatectl set-timezone Europe/Lisbon
hostnamectl set-hostname myserver
# Atualizações de segurança automáticas:
dpkg-reconfigure -plow unattended-upgrades
Lista de fusos horários — timedatectl list-timezones. Se, no fim da atualização, surgir uma janela azul «Daemons using outdated libraries» — selecione todos os serviços (Espaço) e prima OK, é seguro.
04. Criar um utilizador com sudo
Trabalhar sempre como root não é seguro. Crie um utilizador normal e dê-lhe permissões sudo (executar comandos de administrador quando necessário). Substitua deploy por qualquer nome.
# Criar utilizador (define a palavra-passe e pede dados — pode carregar em Enter):
adduser deploy
# Adicionar ao grupo sudo:
usermod -aG sudo deploy
# Verificar (como root):
su - deploy
sudo whoami # deve mostrar: root
exit
A partir daqui, entre no servidor já com este utilizador: ssh deploy@203.0.113.10, e execute os comandos de administrador com o prefixo sudo.
05. Chaves SSH e desativação do início de sessão por palavra-passe
O início de sessão por chave é mais seguro do que por palavra-passe: uma palavra-passe pode ser adivinhada, uma chave praticamente não. Primeiro criamos a chave no seu computador, copiamo-la para o servidor, testamos o início de sessão — e só depois desativamos a palavra-passe.
Passo 1. Criar a chave no seu computador (Windows PowerShell / macOS / Linux):
ssh-keygen -t ed25519 -C "my-laptop"
# Enter em todas as perguntas (a chave fica em ~/.ssh/id_ed25519)
Passo 3. Testar o início de sessão por chave numa nova janela — deve permitir o acesso sem palavra-passe:
ssh deploy@203.0.113.10
Não execute a Variante B enquanto o início de sessão por chave não estiver verificado e funcional (Passos 1–3), e não feche a sessão de trabalho. Ela desativa o início de sessão por palavra-passe para todos os utilizadores, incluindo o root. Sem uma chave funcional, perderá totalmente o acesso ao servidor — só o poderá recuperar através da consola do fornecedor de alojamento. Não tem chave — use a Variante A.
Passo 4. Reforçar o acesso por SSH. As definições vão para um ficheiro separado, sem mexer no ficheiro de configuração principal. Escolha a variante conforme a situação:
Variante A — apenas fechar o root, mantendo a palavra-passe. Não é preciso chave e não perde o acesso:
Variante B — hardening completo. Desativar o início de sessão por palavra-passe e deixar o root apenas por chave. Execute só depois de confirmar que o início de sessão por chave funciona:
sudo tee /etc/ssh/sshd_config.d/00-hardening.conf >/dev/null <<'EOF'
PubkeyAuthentication yes
PasswordAuthentication no
PermitRootLogin prohibit-password
KbdInteractiveAuthentication no
EOF
sudo systemctl restart ssh
Em ambas as variantes, o root por palavra-passe fica fechado. PermitRootLogin no proíbe totalmente o root, prohibit-password — deixa o início de sessão apenas por chave (para administração, inicie sessão como deploy e use sudo). Se quiser mudar a porta SSH — adicione a linha Port 2222, mas primeiro abra a nova porta na firewall (secção seguinte) e teste o início de sessão, caso contrário ficará sem acesso.
06. Firewall básico e autoproteção
Feche tudo o que é desnecessário com o firewall e ative o fail2ban (bane tentativas de adivinhar palavras-passe por SSH). Primeiro permita o SSH, caso contrário perde o acesso depois de ativar o UFW.
# Permitir SSH (ou a sua porta, se a alterou) e a web:
sudo ufw allow OpenSSH
sudo ufw allow 80,443/tcp
# Ativar o firewall:
sudo ufw enable
sudo ufw status verbose
# fail2ban — proteção do SSH contra tentativas por força bruta (perfil básico ativo de imediato):
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd
Isto é o mínimo. As configurações de trabalho do fail2ban, a lista de bloqueio ipsum, o UFW avançado e as restantes ferramentas estão no grupo «Ferramentas de segurança» do manual. O próprio painel Arcivéo Monitor mostra de forma clara o estado de tudo isto.
07. Instalação do painel HestiaCP (opcional)
HestiaCP — painel de controlo de alojamento gratuito: instala e configura o servidor web (nginx + apache), PHP, base de dados (MariaDB), correio, DNS e certificados SSL, e disponibiliza uma interface web para os sites. É prático se não quiser configurar tudo manualmente e planear alojar sites (incluindo o próprio painel Arcivéo Monitor).
Instale o HestiaCP num servidor limpo (Ubuntu/Debian recente e suportado, no mínimo ~1–2 GB de RAM), antes de instalar outros servidores web e bases de dados — caso contrário haverá conflitos. A instalação demora 10–20 minutos e reinicia o servidor.
# Descarregar o instalador e executar:
wget https://raw.githubusercontent.com/hestiacp/hestiacp/release/install/hst-install.sh
sudo bash hst-install.sh
O instalador pede o email e o nome do host e, em seguida, instala toda a stack. Após a reinicialização, o painel fica acessível no endereço https://YOUR_IP:8083 (o instalador mostra o login e a palavra-passe no final).
O HestiaCP gere ele próprio o UFW e o fail2ban — não é preciso configurá-los à parte, ele trata disso. Ainda assim, configure as chaves SSH e a desativação da palavra-passe (secção anterior).
08. Requisitos de sistema e ionCube
O painel é uma aplicação PHP numa pilha LAMP/LEMP típica:
SO: Linux (recomendam-se Ubuntu/Debian);
Servidor web: nginx ou Apache com PHP-FPM;
PHP 8.0+ com as extensões: pdo_mysql, openssl, curl, json, mbstring;
ionCube Loader — extensão do PHP necessária para o funcionamento do painel;
BD: MySQL 5.7+ ou MariaDB 10.3+;
HTTPS — obrigatório (o início de sessão e o WebAuthn só funcionam por https);
sudo para o utilizador do servidor web (conjunto restrito — passo 13).
# Verificar a versão do PHP e as extensões:
php -v
php -m | grep -iE 'pdo_mysql|openssl|curl|mbstring|ioncube'
Instalação do ionCube Loader (se ainda não estiver instalado). Num alojamento com painel (HestiaCP, cPanel), o ionCube ativa-se com uma marca nas definições do PHP. Manualmente em Ubuntu/Debian:
# Descobrir a versão do PHP e o diretório de extensões:
php -v
EXTDIR=$(php -r 'echo ini_get("extension_dir");'); PHPVER=$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')
# Descarregar e extrair os loaders (64-bit):
cd /tmp
wget -q https://downloads.ioncube.com/loader_downloads/ioncube_loaders_lin_x86-64.tar.gz
tar xzf ioncube_loaders_lin_x86-64.tar.gz
# Copiar o loader da sua versão do PHP para o diretório de extensões:
sudo cp ioncube/ioncube_loader_lin_${PHPVER}.so "$EXTDIR"/
# Ativar (CLI + PHP-FPM) e reiniciar:
echo "zend_extension=ioncube_loader_lin_${PHPVER}.so" | sudo tee /etc/php/${PHPVER}/mods-available/ioncube.ini
sudo phpenmod ioncube
sudo systemctl restart php${PHPVER}-fpm
# Verificação — no resultado aparecerá a linha "with the ionCube PHP Loader":
php -v
A versão do loader tem de coincidir com a versão do PHP (por exemplo ioncube_loader_lin_8.1.so para PHP 8.1). Se usar várias versões do PHP — ative o loader para cada uma.
09. Domínio e DNS
Para abrir o painel num endereço como monitor.example.com e obter SSL gratuito, precisa de um domínio que aponte para o seu servidor. No painel de gestão de DNS, crie um registo A:
Tipo: A
Nome: monitor (subdomínio → monitor.example.com)
ou @ (raiz do domínio → example.com)
Valor: 203.0.113.10 ← IP do seu servidor
TTL: 3600
Após alguns minutos, verifique se o domínio aponta para o servidor:
dig +short monitor.example.com # deve devolver o seu IP
# ou, se não tiver o dig:
getent hosts monitor.example.com
O certificado SSL da Let's Encrypt só é emitido para um domínio — o DNS tem de apontar para o servidor antes da emissão do certificado.
10. Criar o site e enviar os ficheiros do painel
Apache: DocumentRoot — na raiz do painel, NÃO em public/. Os estilos (CSS/JS), o sw.js e o manifest.json ficam em assets/ junto de public/ e são pedidos a partir da raiz do site. O .htaccess raiz é o controlador frontal. Se, com o Apache, definir o DocumentRoot para public/, o painel abre sem estilos. Com nginx puro é o contrário: a raiz passa a ser public/ e assets/ é servido por uma regra separada (ver o bloco nginx abaixo).
Os ficheiros do painel (o arquivo da distribuição) são descarregados após a compra na área pessoal em my.arciveo.com → «Transferências». Extraia o arquivo antes de o enviar.
1) Crie a diretoria do painel e envie para ela o conteúdo da distribuição (para que dentro fiquem public/, assets/, config.php, etc.):
sudo mkdir -p /var/www/monitor
# depois enviar os ficheiros da distribuição para /var/www/monitor (FileZilla / WinSCP / scp)
2) Configure o servidor web.Apache: DocumentRoot — na raiz do painel (NÃO em /public); o AllowOverride All é obrigatório. O caminho para o socket do PHP-FPM é detetado automaticamente. O bloco é colado no terminal por inteiro:
PHPSOCK=$(ls -1 /run/php/php*-fpm.sock 2>/dev/null | head -1) # deteção automática do socket PHP-FPM
sudo tee /etc/apache2/sites-available/monitor.conf > /dev/null <<'EOF'
<VirtualHost *:80>
ServerName monitor.example.com
DocumentRoot /var/www/monitor
<Directory /var/www/monitor>
AllowOverride All
Require all granted
</Directory>
<FilesMatch \.php$>
SetHandler "proxy:unix:__PHPSOCK__|fcgi://localhost"
</FilesMatch>
</VirtualHost>
EOF
sudo sed -i "s#__PHPSOCK__#${PHPSOCK}#" /etc/apache2/sites-available/monitor.conf
sudo a2dissite 000-default.conf
sudo a2ensite monitor.conf
sudo apache2ctl configtest
sudo systemctl reload apache2
nginx: o nginx não tem .htaccess, por isso a raiz passa a ser public/, e assets/, sw.js, manifest.json (um nível acima) são servidos por uma regra separada:
PHPSOCK=$(ls -1 /run/php/php*-fpm.sock 2>/dev/null | head -1) # deteção automática do socket PHP-FPM
sudo tee /etc/nginx/sites-available/monitor.conf > /dev/null <<'EOF'
server {
listen 80;
server_name monitor.example.com;
root /var/www/monitor/public;
index index.php;
# assets, service worker e manifest ficam um nível acima de public/
location ~ ^/(assets/|sw\.js|manifest\.json) { root /var/www/monitor; }
location / { try_files $uri $uri/ /index.php?$query_string; }
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:__PHPSOCK__;
}
}
EOF
sudo sed -i "s#__PHPSOCK__#${PHPSOCK}#" /etc/nginx/sites-available/monitor.conf
sudo ln -s /etc/nginx/sites-available/monitor.conf /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
Envio dos ficheiros — SFTP/SCP (FileZilla, WinSCP) ou scp:
# Exemplo via scp a partir do computador local:
scp -r ./monitor/* deploy@203.0.113.10:/var/www/monitor/
Defina as permissões dos ficheiros — este passo é obrigatório. Se enviou como root ou por SFTP, os ficheiros pertencem a root e o servidor web (www-data) não os consegue ler — o painel abre vazio ou com erro 403 (no log: .htaccess unreadable / directory not executable). O comando abaixo corrige isto:
# Normalizamos as permissões de todo o webroot: uma diretoria criada por root fica inacessível
# ao servidor web (www-data) — sem isto o painel devolve uma página vazia ou 403.
# O Apache corre como www-data; se tiver outro utilizador web, substitua-o.
cd /var/www/monitor
# Criamos as pastas de trabalho ANTES do chown — senão as novas diretorias ficam root:root
# e, com chmod 750, o servidor web (www-data) não consegue escrever nelas.
sudo mkdir -p data/lynis data/logwatch tmp logs
sudo chown -R www-data:www-data /var/www/monitor
sudo find /var/www/monitor -type d -exec chmod 755 {} \;
sudo find /var/www/monitor -type f -exec chmod 644 {} \;
sudo chmod 640 /var/www/monitor/config.php
sudo chmod 750 data tmp logs
3) Abra para si próprio o envio de ficheiros por SFTP. Depois do comando acima todos os ficheiros pertencem ao www-data, enquanto o FileZilla / WinSCP se ligam com o seu próprio utilizador — o envio falhará com SSH_FX_PERMISSION_DENIED (Permission denied). Entrar como root para enviar não é opção — o acesso root foi desativado no passo 05. Escolha uma das duas variantes.
Variante A — uma ACL apenas para o seu utilizador (recomendado). A permissão de escrita fica só consigo; o servidor web continua sem poder substituir o código do painel:
sudo apt install -y acl
# Permissão de escrita para o seu utilizador em todo o diretório do painel:
sudo setfacl -R -m u:deploy:rwX /var/www/monitor
# A mesma regra por omissão — para ficheiros e pastas criados mais tarde:
sudo setfacl -R -d -m u:deploy:rwX /var/www/monitor
Variante B — através do grupo www-data. Mais simples, mas a permissão de escrita nos ficheiros do painel passa também para o servidor web: com uma vulnerabilidade no PHP o código poderia ser substituído. A ordem dos comandos importa — config.php e as pastas de trabalho são fechadas por último:
sudo usermod -aG www-data deploy
# Escrita para o grupo + setgid (o bit 2): os ficheiros enviados por SFTP
# permanecem no grupo www-data — caso contrário o painel não os consegue substituir.
sudo find /var/www/monitor -type d -exec chmod 2775 {} \;
sudo find /var/www/monitor -type f -exec chmod 664 {} \;
sudo chmod 640 /var/www/monitor/config.php
sudo chmod 2750 /var/www/monitor/data /var/www/monitor/tmp /var/www/monitor/logs
Depois da variante B volte a ligar-se no FileZilla (Servidor → Desligar e entrar de novo) — o novo grupo só passa a valer numa nova sessão, até lá continua sem permissões. Verificação: id deploy — na lista de grupos deve aparecer www-data; ls -ld /var/www/monitor — permissões drwxrwsr-x, a letra s em vez de x significa que o setgid está ativo.
11. Base de dados
Crie a base de dados e o utilizador, depois importe o esquema. O bloco é colado no terminal na íntegra. monitor_db e monitor_user são nomes de exemplo, pode definir os seus; memorize o nome da base, do utilizador e a palavra-passe — irá inseri-los em config.php no passo seguinte:
# 1. Base de dados. A palavra-passe define-se UMA vez em DBPASS e é usada em todas as linhas.
# O bloco é colado no terminal NA ÍNTEGRA; sudo mysql entra como root via socket unix
# (não precisa da palavra-passe de root). NÃO use o interativo `sudo mysql -u root -p`
# com copiar/colar — ao colar, as linhas SQL vão para o pedido de palavra-passe e perdem-se.
DBPASS='CHOOSE_A_PASSWORD' # ← altere apenas esta linha
sudo mysql <<SQL
CREATE DATABASE IF NOT EXISTS monitor_db CHARACTER SET utf8mb4;
CREATE USER IF NOT EXISTS 'monitor_user'@'localhost' IDENTIFIED BY '$DBPASS';
GRANT ALL ON monitor_db.* TO 'monitor_user'@'localhost';
FLUSH PRIVILEGES;
SQL
# Verificação (deve mostrar monitor_db):
mysql -u monitor_user -p"$DBPASS" -e "SHOW DATABASES;"
# Insira esta mesma palavra-passe em config.php → DB_PASS.
Não é preciso importar o esquema — o painel cria as tabelas e a conta admin no primeiro acesso pelo navegador (a partir de database/db.sql), se a base de dados estiver vazia. A importação manual do esquema só é necessária se a inicialização automática não funcionar.
Se usou o instalador no navegador public/start_db.php — elimine-o logo após a instalação: ele permite recriar a base de dados sem autenticação. Enquanto o ficheiro estiver na raiz do painel ou em public/, o painel mostra um aviso vermelho.
12. Configuração do config.php
config.php na raiz do painel (/var/www/monitor/config.php) é o único ficheiro que precisa de editar manualmente. Todas as definições do painel são especificadas nele através de constantes define(). Abra-o num editor:
sudo nano /var/www/monitor/config.php
Introduza os seus valores nos locais destacados; deixe o resto como está:
// --- Base de dados (do passo 11) ---
define('DB_HOST', 'localhost'); // manter
define('DB_NAME', 'db_name'); // o que criou no passo 11
define('DB_USER', 'user'); // o que criou no passo 11
define('DB_PASS', 'db_password'); // o que definiu no passo 11
define('DB_CHARSET', 'utf8mb4'); // manter
// --- Aplicação ---
define('APP_URL', 'https://monitor.example.com'); // endereço do painel, sem barra no final
define('TIMEZONE', 'Europe/Lisbon'); // o seu fuso horário
// --- Tempo de sessão ---
define('SESSION_LIFETIME', 28800); // inatividade até novo início de sessão, seg (28800 = 8 h)
O que alterar:
DB_NAME, DB_USER, DB_PASS — exatamente o mesmo nome de base, utilizador e palavra-passe que definiu ao criar a BD no passo 11 (se deixou os exemplos — monitor_db / monitor_user). Não mexa em DB_HOST e DB_CHARSET.
APP_URL — endereço completo do painel com https://, sem barra no final e sem www. Tem de coincidir com o domínio no qual ativa a licença (passo 16), caso contrário a chave será rejeitada.
TIMEZONE — o seu fuso horário (lista — timedatectl list-timezones). Afeta apenas a forma como o painel mostra as datas; não afeta a hora de execução das tarefas cron (aí aplica-se o fuso do sistema).
SESSION_LIFETIME — ao fim de quantos segundos de inatividade o painel pede novo início de sessão (por predefinição 8 horas). Ex. 3600 = 1 hora, 86400 = um dia.
Bloco de registo de erros (display_errors, log_errors, error_log) — deixe por predefinição.
Guarde o ficheiro (Ctrl+O, Enter, depois Ctrl+X) e reinicie o PHP-FPM — caso contrário, devido ao OPcache, as alterações não serão aplicadas:
sudo systemctl restart php*-fpm
config.php — ficheiro secreto (contém a palavra-passe da BD). Fica na raiz do painel, que é a própria raiz web, mas está protegido: permissões 640 (definidas no passo 10) e proibição explícita no .htaccess da raiz. Não o coloque em repositórios públicos nem o envie para o suporte com a palavra-passe real.
O PHP é executado com o utilizador do servidor web, que não tem permissões sobre comandos de sistema. O acesso é concedido de forma restrita: sudo pontual para utilitários específicos e leitura de registos através de grupos (sem sudo). Uma invasão da camada web não dá root.
Nos exemplos, www-data é o utilizador padrão do Apache. Se o seu for outro (nalguns painéis o PHP corre com um utilizador próprio), substitua em todo o lado. Para saber: ps -o user= -C php-fpm | sort -u.
1. Crie o /etc/sudoers.d/monitor com sudo visudo -f /etc/sudoers.d/monitor e cole (remova as linhas dos módulos que não usa):
# UFW — estado e regras (página «Firewall»)
www-data ALL=(ALL) NOPASSWD: /usr/sbin/ufw status, /usr/sbin/ufw status verbose, /usr/sbin/ufw status numbered
www-data ALL=(ALL) NOPASSWD: /usr/sbin/ufw allow [0-9]*, /usr/sbin/ufw deny [0-9]*, /usr/sbin/ufw --force delete [0-9]*
# Fail2ban — estado, ban e unban (banned devolve os bans de todos os jails num só comando;
# ban/unban são precisos para os botões do painel)
www-data ALL=(ALL) NOPASSWD: /usr/bin/fail2ban-client status, /usr/bin/fail2ban-client status *, /usr/bin/fail2ban-client banned, /usr/bin/fail2ban-client set * banip *, /usr/bin/fail2ban-client set * unbanip *
# Atualizações de segurança (cartão «Atualizações»). Apenas leitura, mas mesmo como root:
# a cache do apt (~70 MB) só é acessível ao root; um não-root reconstrói-a a cada chamada
# (4,2 s de CPU contra 0,01 s). Sem wildcard — exatamente este único comando, não instala nada.
www-data ALL=(ALL) NOPASSWD: /usr/bin/apt list --upgradable
# IPset (mapa de ataques, dashboard)
www-data ALL=(ALL) NOPASSWD: /usr/sbin/ipset list -t ipsum
# CrowdSec
www-data ALL=(ALL) NOPASSWD: /usr/bin/cscli decisions list *, /usr/bin/cscli alerts list *, /usr/bin/cscli bouncers list *, /usr/bin/cscli scenarios list *
# Auditd — pesquisa de eventos + leitura das últimas linhas do registo (caminho exato)
www-data ALL=(ALL) NOPASSWD: /usr/sbin/ausearch -m *
www-data ALL=(ALL) NOPASSWD: /usr/bin/tail -n 300 /var/log/audit/audit.log
# Monit / ModSecurity / AppArmor / PSAD
www-data ALL=(ALL) NOPASSWD: /usr/bin/monit status
www-data ALL=(ALL) NOPASSWD: /usr/sbin/apache2ctl -M
www-data ALL=(ALL) NOPASSWD: /usr/local/bin/monitor-modsec
www-data ALL=(ALL) NOPASSWD: /usr/sbin/aa-status
www-data ALL=(ALL) NOPASSWD: /usr/sbin/psad --Status
# Portas abertas (os registos do kernel/SSH/Falco leem-se SEM sudo — através do grupo
# systemd-journal, ver ponto 2; NÃO é preciso dar sudo ao journalctl e é inseguro)
www-data ALL=(ALL) NOPASSWD: /usr/bin/ss -tuln, /usr/sbin/ss -tuln, /bin/ss -tuln
# PostgreSQL (só se o usar) — script read-only fixo,
# crie-o pelo FAQ «PostgreSQL não aparece»; sem ele, elimine a linha
www-data ALL=(ALL) NOPASSWD: /usr/local/bin/monitor-pgstat
2. Acesso aos registos e ao journal do systemd. Os módulos leem /var/log/fail2ban.log, auth.log, ufw.log, apache2/*, aide diretamente (no Debian/Ubuntu estes registos estão no grupo adm). Os eventos do kernel, SSH e Falco são obtidos do journald com o comando journalctlsem sudo, através do grupo systemd-journal. Adicione o utilizador web a ambos os grupos e reinicie o PHP-FPM:
sudo usermod -aG adm,systemd-journal www-data
sudo systemctl restart php*-fpm # obrigatório, senão os grupos não são aplicados
3. Se o ClamAV ou o Suricata escreverem os registos fora do grupo adm (por vezes fica root:root), conceda acesso através de ACL:
4. Wrapper do ModSecurity. O registo de auditoria do WAF (/var/log/apache2/modsec_audit.log) pertence ao root com permissões 640, e o utilizador web não o consegue ler diretamente. A página do ModSecurity obtém o modo do motor, os eventos e a lista de regras ativas através de um script read-only fixo — é esse que está autorizado no sudoers na linha acima:
Sem o ficheiro /etc/modsecurity/modsecurity.conf o próprio WAF não funciona: o pacote coloca apenas o modsecurity.conf-recommended e o motor de regras fica desativado — para saber como ativá-lo, ver FAQ → «Instalação do ModSecurity».
O utilizador em todas as linhas do sudoers deve coincidir com o utilizador do pool FPM: num Apache/Debian normal é www-data; no HestiaCP o pool do site corre com o dono do site (por exemplo, admin) — verifique grep -E '^user' /etc/php/*/fpm/pool.d/monitor.example.com.conf.
5. Se houver Nginx à frente do Apache (HestiaCP, ISPmanager e outros painéis — nesse caso o Nginx faz proxy do PHP para o Apache e serve ele próprio os ficheiros estáticos). As diretorias de serviço estão protegidas por ficheiros .htaccess, mas o Nginx não os lê: qualquer ficheiro estático (.json, .txt, .log, .dat) ele serve-o diretamente, sem passar pelo Apache. Para fora vazam as caches do painel e os dados — por exemplo tmp/modsec_cache.json com os eventos do WAF e os IP dos atacantes. Adicione a proibição à configuração do site no Nginx:
O prefixo ^~ é obrigatório: é selecionado antes da regra por expressão regular para estáticos dentro de location /, caso contrário a proibição não funciona.
No HestiaCP, coloque isto num ficheiro separado /home/<user>/conf/web/<domain>/nginx.ssl.conf_deny (e nginx.conf_deny para HTTP) — a configuração do site inclui nginx.ssl.conf_* e, ao reconstruir, não apaga esses ficheiros. Para aplicar: sudo nginx -t && sudo systemctl reload nginx.
Verificação: curl -s -o /dev/null -w '%{http_code}\n' https://monitor.example.com/tmp/modsec_cache.json — deve dar 403. Se o Apache funcionar sem Nginx (escuta ele próprio o 80/443), não é preciso adicionar nada — o .htaccess é suficiente.
Verifique os caminhos dos binários com which (por exemplo which ufw cscli ausearch ss). Edite o sudoers apenas através de visudo. A lista de todas as bases de dados MySQL é ativada por um GRANT separado (FAQ → «Só aparece uma BD»).
14. Restrição de acesso por IP
Restrinja o acesso ao monitor por endereço IP — mesmo que o URL se torne conhecido, a página de início de sessão não abrirá. Pode fazê-lo ao nível do servidor web (exemplo para nginx abaixo) ou no próprio painel («Definições» → «Restrição de acesso por IP»). Se usar Apache, utilize a restrição no painel.
Se o site nginx já estiver configurado conforme o passo 10, não adicione um segundolocation / — insira as linhas allow/deny no bloco já existente. Dois location / iguais num mesmo server { } são um erro de configuração e o nginx não reiniciará.
# Na configuração do nginx (dentro de server { }):
# Mantemos o caminho ACME do Let's Encrypt aberto, contornando a restrição de IP —
# para que a emissão e a renovação automática do SSL (passo 15) não dependam do filtro de IP.
location ^~ /.well-known/acme-challenge/ { allow all; }
location / {
allow 203.0.113.10; # ← insira o seu IP
allow 10.0.0.0/8; # rede local (se necessário)
deny all;
try_files $uri $uri/ /index.php?$query_string;
}
# Recarregar o nginx:
sudo nginx -t && sudo systemctl reload nginx
15. Emitir SSL (HTTPS)
O painel funciona apenas por HTTPS. A sessão de início de sessão usa uma cookie segura, e o WebAuthn (2FA) só funciona em HTTPS. Não é possível entrar por http://.
O certificado é gratuito (Let's Encrypt). O DNS do domínio já deve apontar para o servidor. O comando depende do servidor web:
# Apache:
sudo certbot --apache -d monitor.example.com
# nginx — APENAS se usar mesmo nginx. Em Apache NÃO execute:
# apt puxaria o nginx e ocuparia a porta 80, conflito com o Apache.
# sudo apt install python3-certbot-nginx
# sudo certbot --nginx -d monitor.example.com
# o certbot escreve o HTTPS na config e configura a renovação automática
O que o certbot pergunta: e-mail → aceitação dos Terms (Y) → partilha do e-mail com a EFF (opcional). Depois emite o certificado, escreve <VirtualHost *:443>, configura o redirecionamento http→https e a renovação automática.
O DNS deve apontar para o servidor ANTES de executar o certbot (validação de propriedade pela porta 80). Verificação: dig +short monitor.example.com → IP do servidor. Portas 80/443 abertas: sudo ufw allow 80,443/tcp.
Após a emissão: https://monitor.example.com abre com o cadeado, http:// redireciona para https:// (o APP_URL em config.php já foi definido no passo 12).
16. Início de sessão e configuração inicial
Abra https://monitor.example.com, inicie sessão com admin / useradmin e siga a lista de verificação:
Alterar a palavra-passe de admin — secção «Utilizadores» no menu.
Ativar WebAuthn (2FA) — «Chaves WebAuthn» → registar chave/passkey (requer HTTPS). Registe logo duas: se perder a única chave, o início de sessão com ela torna-se impossível. Saber mais.
Restringir o acesso por IP — «Definições» → «Restrição de acesso por IP» (introduza o seu IP antes de ativar, caso contrário bloqueia o seu próprio acesso).
Introduzir a licença — ative o código ARCIVEO-… da sua área pessoal para o seu domínio e cole a chave em «Definições» → «Licença». Saber mais.
Configurar as notificações — Telegram e/ou Email em «Definições». Saber mais.
Eliminar o instaladorpublic/start_db.php, caso ainda exista (passo 11).
17. Ferramentas de segurança (opcional)
O painel já está a funcionar. As ferramentas instalam-se conforme necessário — instale só o que precisa e o painel mostra logo o estado. Os comandos de instalação de cada uma estão no guia (secções separadas por ferramenta):
Esta é uma demonstração do Arcivéo Security Monitor apenas para visualização — todas as alterações estão desativadas. Instale-o no seu servidor para gerir dados de segurança reais.