Voltar para Artigos
DevOps9 min de leitura

Segurança de Servidor Linux: SSH Keys, UFW, Fail2Ban e Hardening

Configuração completa de segurança em VPS Ubuntu: SSH key com Ed25519, desativar root login, UFW com regras granulares, Fail2Ban com jail para SSH e Nginx, Docker e UFW (o problema das iptables), e unattended-upgrades.

12 de agosto de 2026

Ao provisionar um VPS, ele entra no ar com o IP público visível ao mundo. Em questão de minutos, bots automatizados começam a tentar login SSH com senhas comuns. Logs do /var/log/auth.log em servidores sem hardening mostram centenas de tentativas por hora. Este artigo cobre a sequência completa de hardening para um servidor Ubuntu recém-criado.

O hardening não precisa ser complexo para ser eficaz. Os 5 passos abaixo cobrem a grande maioria dos vetores de ataque em servidores VPS: eliminar a conta root remota, substituir senhas por criptografia de chave pública, restringir portas expostas, banir IPs que fazem brute force, e manter o sistema atualizado automaticamente. Execute-os na ordem apresentada — preferencialmente logo após o provisionamento.

1. Crie um Usuário Não-Root

bash
# Nunca opere como root em produção
# Crie um usuário dedicado para a aplicação
adduser deploy
usermod -aG sudo deploy

# Copie a chave SSH do root para o novo usuário
mkdir -p /home/deploy/.ssh
cp /root/.ssh/authorized_keys /home/deploy/.ssh/
chown -R deploy:deploy /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
chmod 600 /home/deploy/.ssh/authorized_keys

2. SSH com Chave Ed25519 (sem senhas)

A chave Ed25519 é preferida sobre RSA 2048: chaves menores, mais rápidas de assinar, resistentes a ataques de canal lateral e amplamente suportadas. Desativar o PasswordAuthentication elimina completamente ataques de força bruta baseados em senha — um atacante sem a chave privada não tem como entrar, independente de quantas tentativas faça.

bash
# Na sua máquina LOCAL: gere uma chave Ed25519 (mais moderna e segura que RSA 2048)
ssh-keygen -t ed25519 -C "deploy@meu-projeto" -f ~/.ssh/meu-projeto_ed25519

# Copie a chave pública para o servidor
ssh-copy-id -i ~/.ssh/meu-projeto_ed25519.pub deploy@IP_DO_SERVIDOR

# No servidor: configure o SSH
sudo nano /etc/ssh/sshd_config

# Altere ou confirme estas linhas:
# PermitRootLogin no              # Nunca root via SSH
# PasswordAuthentication no       # Apenas chave criptográfica
# PubkeyAuthentication yes
# Port 2222                       # Opcional: porta não-padrão (reduz bots)
# AllowUsers deploy               # Apenas o usuário deploy pode conectar

sudo systemctl reload ssh

# ATENÇÃO: teste a conexão em um terminal separado ANTES de fechar o atual
# ssh -i ~/.ssh/meu-projeto_ed25519 deploy@IP -p 2222

3. Firewall com UFW

O UFW (Uncomplicated Firewall) é uma interface de linha de comando para o iptables, muito mais simples de usar. A regra fundamental é deny incoming por padrão: tudo que não for explicitamente permitido é bloqueado. Abra apenas as portas que a aplicação realmente precisa — nenhuma porta de banco de dados, Redis ou serviço interno deve ser exposta externamente.

bash
# UFW: bloqueia tudo por padrão, abre apenas o necessário
sudo ufw default deny incoming
sudo ufw default allow outgoing

# Se mudou a porta SSH, use o número correto!
sudo ufw allow 2222/tcp comment 'SSH'
sudo ufw allow 80/tcp comment 'HTTP'
sudo ufw allow 443/tcp comment 'HTTPS'

# Portas internas (banco, redis): NUNCA abra para 0.0.0.0
# Acesse apenas via SSH tunnel ou rede interna do Docker

sudo ufw enable  # Confirme com 'y'
sudo ufw status verbose

Docker e UFW não se falam bem. O Docker modifica as iptables diretamente, contornando as regras do UFW. Se você expõe uma porta com ports: ['5432:5432'], o PostgreSQL fica acessível publicamente — ignorando o ufw deny. A solução: bind apenas no loopback ports: ['127.0.0.1:5432:5432'] para serviços que não devem ser acessados externamente. Para serviços entre containers, use a rede interna do Docker sem mapear portas.

4. Fail2Ban: Banimento Automático

O Fail2Ban monitora arquivos de log em tempo real e bane IPs que excedem um número de tentativas falhas. Para SSH, 3 senhas erradas equivalem a um ataque de força bruta — um usuário legítimo não erra a senha 3 vezes seguidas. O ban de 24 horas para SSH torna ataques distribuídos exaustivamente lentos. A configuração para Nginx também protege contra tentativas de enumeração de endpoints via rate limiting no nível do log.

bash
sudo apt-get install -y fail2ban

# Crie uma configuração local (nunca edite jail.conf diretamente)
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo nano /etc/fail2ban/jail.local
jail.local
[DEFAULT]
# Tempo de banimento padrão: 1 hora
bantime = 3600
# Janela de observação: 10 minutos
findtime = 600
# Número de falhas permitidas antes do ban
maxretry = 5
# Ignorar IPs locais
ignoreip = 127.0.0.1/8 ::1

[sshd]
enabled = true
port = 2222          # Sua porta SSH personalizada
logpath = %(sshd_log)s
maxretry = 3         # SSH: 3 tentativas — mais rigoroso que o padrão
bantime = 86400      # Ban por 24h em caso de falha no SSH

[nginx-limit-req]
enabled = true
port = http,https
logpath = /var/log/nginx/error.log
maxretry = 10
bash
sudo systemctl enable fail2ban
sudo systemctl start fail2ban

# Verificar status e IPs banidos
sudo fail2ban-client status sshd
sudo fail2ban-client status nginx-limit-req

# Desbanir um IP (caso você mesmo seja banido)
sudo fail2ban-client set sshd unbanip SEU_IP

5. Atualizações Automáticas de Segurança

Vulnerabilidades em pacotes do sistema (OpenSSL, Kernel, SSH daemon) são a causa de muitas violações de segurança em servidores. O unattended-upgrades aplica automaticamente apenas patches de segurança — sem atualizar versões major que poderiam quebrar a aplicação. A janela entre a divulgação de uma CVE e sua exploração em massa é frequentemente de horas. Com atualizações automáticas, seu servidor é patcheado antes de você acordar.

bash
sudo apt-get install -y unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades

# Confirme que está ativado
sudo systemctl status unattended-upgrades

# O arquivo de configuração fica em:
# /etc/apt/apt.conf.d/50unattended-upgrades
# Por padrão, aplica apenas atualizações de segurança — não quebra o sistema

Verifique periodicamente o log /var/log/auth.log para entender a atividade no servidor: sudo grep 'Invalid user\|Failed password\|Accepted publickey' /var/log/auth.log | tail -50. Se você ver centenas de tentativas de IPs diferentes, o Fail2Ban está funcionando — eles estão sendo banidos após 3 falhas.

Conclusão

Os 5 passos — usuário não-root, SSH com Ed25519 sem senha, UFW bloqueando tudo exceto o necessário, Fail2Ban banindo brute force, e atualizações automáticas de segurança — cobrem a superfície de ataque mais comum em servidores expostos à internet. O Docker requer atenção especial: sempre use bind no loopback (127.0.0.1) para portas que não devem ser públicas, pois o Docker contorna o UFW via iptables direto.