Linux Server Hardening Checklist 2026: SSH, Firewall e Kernel
Um servidor Linux recém-instalado vem com dezenas de serviços activos, root acessível por SSH e kernel em configuração permissiva. Este guia percorre 12 secções práticas — desde o endurecimento do SSH ao sysctl do kernel, fail2ban, AppArmor/SELinux e auditoria Lynis — com comandos reais para Ubuntu, Debian, RHEL, AlmaLinux e Rocky Linux.
⚠ Aplicar primeiro em staging
Antes de endurecer qualquer servidor em produção, testa todos os passos num ambiente de staging idêntico. Garante que tens acesso à consola (VNC, IPMI ou painel da VPS) — se bloqueares o SSH por engano, a consola é a única forma de recuperar o acesso. Faz uma cópia de segurança do /etc/ssh/sshd_config antes de qualquer alteração.
Neste artigo
1. Superfície de Ataque
Um servidor Linux recém-instalado — seja Ubuntu, Debian, RHEL, AlmaLinux ou Rocky — expõe uma superfície de ataque considerável por defeito. Eis o que está acessível antes de qualquer hardening:
- SSH na porta 22 — o primeiro alvo de bots que fazem brute-force a root/admin/redis com dicionários de passwords comuns.
- Login de root por SSH — em Ubuntu/Debian vem desactivado por defeito (usa sudo), mas em RHEL/CentOS o
PermitRootLoginpode estar activo consoante a imagem. - Serviços desnecessários — rpcbind, avahi-daemon, cups, postfix, dnsmasq abrem portas sem utilidade para a maioria dos servidores.
- Kernel permissivo — redireccionamentos ICMP, IP forwarding, kptr expose e core dumps activos por defeito.
- Sem actualizações automáticas — unattended-upgrades ou dnf-automatic não vêm configurados; patches de segurança ficam por aplicar.
- Sem MAC — AppArmor pode estar em complain mode; SELinux pode estar disabled ou permissive.
- IPv6 activo — se não usas IPv6, todas as portas abertas em IPv4 também estão abertas em IPv6, frequentemente esquecidas na firewall.
- /dev/shm com exec — partilha de memória montada sem noexec/nosuid/nodev, permitindo execução de binários aí colocados.
- Sem logrotate ou rotação configurada — logs podem crescer sem limite e encher o disco em produção.
Cada ponto acima é corrigido nas secções seguintes. A ordem recomendada é: SSH → firewall → actualizações → fail2ban → kernel → MAC → serviços → /dev/shm + IPv6 → auditoria.
2. Cenários
O nível de hardening depende do contexto. Nem todos os passos se aplicam a todos os servidores — adapta conforme o cenário:
| Cenário | Prioridade | Notas |
|---|---|---|
| VPS nova (cloud) | Alta — SSH exposto à Internet desde o minuto 1 | Aplicar SSH + firewall + fail2ban antes de instalar qualquer serviço. Bots atacam IPs novos em minutos. |
| Servidor on-premise | Média — atrás de router/firewall de rede | Hardening de kernel e MAC continua necessário — firewall de rede não substitui defesa em profundidade. |
| Staging com IP público | Alta — mesmo que produção | Staging com IP público é alvo tão válido como produção. Aplicar a mesma checklist completa. |
| Pós-migração | Alta — serviços herdados podem estar activos | Rever serviços activos com ss -tulpn — migrações arrastam postfix, rpcbind, etc. |
3. Endurecer SSH
O SSH é a porta de entrada mais atacada em servidores Linux. Os três passos essenciais: usar chaves Ed25519 em vez de passwords, proibir login de root e mudar a porta padrão.
Gerar chave Ed25519 na máquina cliente
# Gerar chave Ed25519 (mais rápida e segura que RSA 2048)
ssh-keygen -t ed25519 -a 100 -C "[email protected]"
# Copiar a chave pública para o servidor
ssh-copy-id -i ~/.ssh/id_ed25519.pub utilizador@servidor
# Testar login sem password
ssh utilizador@servidor
Configurar sshd_config
# Backup do ficheiro original
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
# Editar configuração
sudo nano /etc/ssh/sshd_config
Parâmetros a alterar ou adicionar no /etc/ssh/sshd_config:
Port 22022
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
PermitEmptyPasswords no
X11Forwarding no
MaxAuthTries 3
LoginGraceTime 30
ClientAliveInterval 300
ClientAliveCountMax 2
AllowUsers utilizador
Recarregar e verificar
# Validar sintaxe antes de recarregar (NÃO saltar este passo)
sudo sshd -t
# Recarregar sshd (NÃO reiniciar — mantém sessão actual)
sudo systemctl reload sshd
# Testar ligação na nova porta ANTES de fechar a sessão actual
ssh -p 22022 utilizador@servidor
ⓘ Importante
Nunca feches a sessão SSH actual sem primeiro testar a nova configuração numa janela separada. Se algo estiver mal configurado, a sessão antiga continua aberta para corrigir.
4. Firewall
A firewall deve seguir política default deny: tudo é proibido excepto o que for explicitamente permitido. O Ubuntu/Debian usa UFW; o RHEL/AlmaLinux/Rocky usa firewalld.
UFW (Ubuntu/Debian)
sudo apt update && sudo apt install -y ufw
# Politica default: deny incoming, allow outgoing
sudo ufw default deny incoming
sudo ufw default allow outgoing
# Permitir SSH na porta configurada (usar a porta do sshd_config)
sudo ufw allow 22022/tcp comment 'SSH'
# Permitir HTTP e HTTPS se for servidor web
sudo ufw allow 80/tcp comment 'HTTP'
sudo ufw allow 443/tcp comment 'HTTPS'
# Activar firewall
sudo ufw enable
# Verificar regras
sudo ufw status verbose
firewalld (RHEL/AlmaLinux/Rocky)
sudo dnf install -y firewalld
sudo systemctl enable --now firewalld
# Adicionar SSH na porta configurada
sudo firewall-cmd --permanent --add-port=22022/tcp
# Adicionar HTTP e HTTPS se necessario
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
# Recarregar e verificar
sudo firewall-cmd --reload
sudo firewall-cmd --list-all
Se mudaste a porta SSH para 22022, garante que a firewall permite essa porta antes de recarregar o sshd — caso contrário ficas sem acesso remoto.
5. Actualizações Automáticas
Manter o servidor actualizado é a defesa mais eficaz contra exploits conhecidos. Configurar actualizações automáticas apenas de segurança evita quebras de produção por updates não testados.
unattended-upgrades (Debian/Ubuntu)
sudo apt install -y unattended-upgrades apt-listchanges
# Configurar apenas security updates
sudo dpkg-reconfigure -plow unattended-upgrades
Verifica o ficheiro /etc/apt/apt.conf.d/50unattended-upgrades e garante que apenas a origem de segurança está activa:
Unattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}-security";
};
// Reboot automatico se necessario (kernel upgrade)
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "04:00";
dnf-automatic (RHEL/AlmaLinux/Rocky)
sudo dnf install -y dnf-automatic
# Configurar apenas security updates
sudo sed -i 's/^upgrade_type.*/upgrade_type = security/' /etc/dnf/automatic.conf
sudo sed -i 's/^apply_updates.*/apply_updates = yes/' /etc/dnf/automatic.conf
# Activar
sudo systemctl enable --now dnf-automatic.timer
# Verificar timer
sudo systemctl status dnf-automatic.timer
6. fail2ban
O fail2ban monitoriza logs de autenticação e bloqueia automaticamente IPs que falham repetidas vezes. É a camada que complementa a firewall contra brute-force SSH.
# Ubuntu/Debian
sudo apt install -y fail2ban
# RHEL/AlmaLinux/Rocky
sudo dnf install -y fail2ban fail2ban-firewalld
# Criar configuracao local (NAO editar jail.conf directamente)
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo nano /etc/fail2ban/jail.local
Configuração da jail SSH no /etc/fail2ban/jail.local:
[sshd]
enabled = true
port = 22022
filter = sshd
logpath = /var/log/auth.log
backend = systemd
maxretry = 3
findtime = 600
bantime = 3600
ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24
Parâmetros: bantime = duração do banimento em segundos (3600 = 1 hora); findtime = janela de tempo para contar tentativas (600 = 10 minutos); maxretry = tentativas antes de banir. Em RHEL, substitui logpath = /var/log/auth.log por logpath = %(sshd_log)s e usa backend = systemd.
# Reiniciar e activar
sudo systemctl restart fail2ban
sudo systemctl enable fail2ban
# Verificar estado da jail
sudo fail2ban-client status sshd
# Verificar IPs banidas
sudo fail2ban-client status sshd | grep "Banned IP"
7. Kernel sysctl Hardening
O kernel Linux traz por defeito configurações pensadas para routers e workstations, não para servidores. Endurecer via sysctl reduz a superfície de ataque ao nível da pilha de rede e do próprio kernel.
Cria o ficheiro /etc/sysctl.d/99-hardening.conf:
sudo nano /etc/sysctl.d/99-hardening.conf
Conteúdo recomendado para um servidor que não é router:
# Redireccionamentos ICMP — desactivar
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
# IP forwarding — desactivar se NAO for router
net.ipv4.ip_forward = 0
net.ipv6.conf.all.forwarding = 0
# Proteccao SYN flood
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 5
# ICMP broadcast (smurf attack)
net.ipv4.icmp_echo_ignore_broadcasts = 1
# Log packets with impossible addresses
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1
# Reverse path filtering
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
# Kernel hardening
kernel.kptr_restrict = 2
kernel.dmesg_restrict = 1
kernel.perf_event_paranoid = 2
kernel.yama.ptrace_scope = 1
# Desactivar core dumps de SUID
fs.suid_dumpable = 0
# Proteccao contra hardlinks/hardlinks
fs.protected_hardlinks = 1
fs.protected_symlinks = 1
fs.protected_fifos = 2
fs.protected_regular = 2
# Aplicar sem reiniciar
sudo sysctl --load /etc/sysctl.d/99-hardening.conf
# Verificar
sudo sysctl net.ipv4.conf.all.send_redirects
sudo sysctl kernel.kptr_restrict
sudo sysctl fs.suid_dumpable
8. AppArmor/SELinux
Mandatory Access Control (MAC) restringe o que cada processo pode fazer, mesmo com root. Ubuntu/Debian usa AppArmor; RHEL/AlmaLinux/Rocky usa SELinux. Ambos devem estar em modo enforcing em produção.
AppArmor (Ubuntu/Debian)
# Verificar estado
sudo aa-status
# Instalar se nao estiver presente
sudo apt install -y apparmor apparmor-utils apparmor-profiles
# Garantir modo enforcing
sudo systemctl enable --now apparmor
# Activar perfis
sudo systemctl enable apparmor.service
sudo systemctl start apparmor.service
# Verificar perfis carregados
sudo apparmor_status | head -20
Para colocar um perfil individualmente em enforcing:
# Colocar perfil em enforcing
sudo aa-enforce /etc/apparmor.d/usr.sbin.mysqld
# Modo complain (apenas regista, nao bloqueia) — para testar
sudo aa-complain /etc/apparmor.d/usr.sbin.mysqld
# Listar perfis em complain
sudo aa-status | grep "complain"
SELinux (RHEL/AlmaLinux/Rocky)
# Verificar modo actual
getenforce
# Estado detalhado
sudo sestatus
# Activar enforcing (persistente)
sudo sed -i 's/^SELINUX=.*/SELINUX=enforcing/' /etc/selinux/config
# Activar imediatamente (sem reboot)
sudo setenforce 1
# Verificar
getenforce
Diferença entre modos SELinux: disabled = completamente desactivado; permissive = regista violações mas não bloqueia (útil para testar políticas); enforcing = bloqueia violações. Em produção usa sempre enforcing — permissive só serve para diagnosticar problemas de política durante transição.
9. Desactivar Serviços Desnecessários
Cada serviço activo é uma porta aberta e um vetor de ataque potencial. Lista todos os serviços activos e desactiva os que não são necessários.
# Listar todos os servicos activos
systemctl list-unit-files --state=enabled
# Ver portas abertas e processos associados
ss -tulpn
# Desactivar servicos desnecessarios (se nao usados)
sudo systemctl disable --now rpcbind
sudo systemctl disable --now avahi-daemon
sudo systemctl disable --now cups
sudo systemctl disable --now postfix
sudo systemctl disable --now dnsmasq
# Remover pacotes completamente (opcional)
sudo apt purge -y rpcbind avahi-daemon cups postfix dnsmasq # Debian/Ubuntu
sudo dnf remove -y rpcbind avahi cups postfix dnsmasq # RHEL
| Serviço | Porta | Desactivar se… |
|---|---|---|
| rpcbind | 111 | Não usas NFS ou NIS |
| avahi-daemon | 5353 | Servidor não precisa de mDNS/DNS-SD |
| cups | 631 | Não há impressoras no servidor |
| postfix | 25 | Não é servidor de email (usa relay externo) |
| dnsmasq | 53 | Não és servidor DNS local |
10. /dev/shm e IPv6
Endurecer /dev/shm
A partilha de memória /dev/shm vem montada sem restrições por defeito. Adiciona noexec, nosuid e nodev para impedir execução de binários aí colocados:
# Verificar montagem actual
mount | grep /dev/shm
# Adicionar ao /etc/fstab
sudo nano /etc/fstab
# Linha a adicionar:
tmpfs /dev/shm tmpfs defaults,noexec,nosuid,nodev 0 0
# Remontar imediatamente
sudo mount -o remount /dev/shm
# Verificar
mount | grep /dev/shm
Desactivar IPv6 (se não usado)
Se o servidor não usa IPv6, desactivá-lo fecha todas as portas IPv6 que a firewall pode estar a esquecer. Adiciona ao ficheiro /etc/sysctl.d/99-disable-ipv6.conf:
sudo nano /etc/sysctl.d/99-disable-ipv6.conf
# Conteudo:
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
# Aplicar
sudo sysctl --load /etc/sysctl.d/99-disable-ipv6.conf
# Verificar
cat /proc/sys/net/ipv6/conf/all/disable_ipv6
11. Auditoria Lynis
O Lynis é uma ferramenta de auditoria de segurança open-source que analisa o sistema e gera um relatório com recomendações e um hardening index (pontuação de 0 a 100).
# Ubuntu/Debian
sudo apt install -y lynis
# RHEL/AlmaLinux/Rocky
sudo dnf install -y lynis
# Executar auditoria completa
sudo lynis audit system
# Ou auditoria apenas para visualizar (sem escrever logs)
sudo lynis audit system --quick
O relatório é guardado em /var/log/lynis.log e os dados de auditoria em /var/log/lynis-report.dat. Interpreta os resultados:
- Hardening index: pontuação de 0-100. <50 = fraco, 50-70 = razoável, 70-85 = bom, >85 = excelente.
- Warnings: problemas críticos que devem ser corrigidos imediatamente.
- Suggestions: recomendações de hardening ordenadas por prioridade (alta/média/baixa).
- Tests skipped: testes não executados por falta de pacotes — instalar pacotes relevantes para cobertura completa.
# Ver apenas warnings e suggestions
sudo grep -E "Warning|Suggestion" /var/log/lynis.log
# Ver hardening index
sudo grep "hardening_index" /var/log/lynis-report.dat
# Ver todos os testes executados
sudo grep -c "^test=" /var/log/lynis-report.dat
12. Erros Comuns e Checklist
Erros Comuns
| Problema | Causa | Solução |
|---|---|---|
| Ficas sem acesso SSH após mudar porta | Firewall não permite a nova porta ou sshd não recarregou | Aceder por consola VNC/IPMI; confirmar sshd -t sem erros e ufw allow porta/tcp antes de recarregar |
| fail2ban bane o teu próprio IP | IP não está em ignoreip; testaste login errado repetidamente | Adicionar IP a ignoreip; desbanir com fail2ban-client unban IP |
| SELinux bloqueia serviço após enabling | Política não cobre o serviço; ficheiros com contexto errado | Usar audit2allow para gerar política; ou permissive temporariamente |
| sysctl não aplica após reboot | Ficheiro em local errado ou sintaxe incorrecta | Confirmar ficheiro em /etc/sysctl.d/ com extensão .conf; validar com sysctl --load |
| AppArmor em complain mas não enforcing | Perfil individual em modo complain | Usar aa-enforce /etc/apparmor.d/perfil em cada perfil |
| unattended-upgrades instala pacotes que partem produção | Allowed-Origins inclui updates normais além de security | Manter apenas ${distro_id}:${distro_codename}-security em Allowed-Origins |
Checklist de Hardening
- SSH: gerar chave Ed25519, copiar com
ssh-copy-id, definirPermitRootLogin no,PasswordAuthentication no, porta não-standard,sshd -tantes de recarregar - Firewall: UFW ou firewalld, política default deny, permitir apenas SSH/HTTP/HTTPS, activar
- Actualizações: instalar unattended-upgrades (Debian) ou dnf-automatic (RHEL), configurar apenas security updates
- fail2ban: instalar, configurar jail sshd com bantime/findtime/maxretry, adicionar ignoreip, activar
- Kernel sysctl: criar
99-hardening.conf, desactivar redireccionamentos, activar syncookies,kptr_restrict=2,suid_dumpable=0, aplicar comsysctl --load - MAC: verificar AppArmor com
aa-statusou SELinux comgetenforce, activar enforcing - Serviços: listar com
systemctl list-unit-files --state=enabled, desactivar rpcbind/avahi/cups/postfix/dnsmasq, confirmar portas comss -tulpn - /dev/shm: adicionar
noexec,nosuid,nodevao fstab, remontar - IPv6: se não usado, desactivar via sysctl em
99-disable-ipv6.conf - Auditoria: instalar Lynis, executar
lynis audit system, corrigir warnings, visar hardening index >70 - Logrotate: verificar
/etc/logrotate.confe configurações em/etc/logrotate.d/, testar comlogrotate -d /etc/logrotate.conf