Hardening de servidores Linux é uma prática essencial para qualquer profissional que lida com infraestrutura, especialmente quando se trata de hospedar aplicações críticas como Node.js. Ao migrar de um ambiente de desenvolvimento local para uma VPS (Virtual Private Server) em produção, as configurações padrão do sistema operacional não são mais suficientes. Elas priorizam a conveniência e a compatibilidade sobre a segurança, o que deixa portas abertas para vulnerabilidades comuns.
O objetivo deste tutorial é guiar você, sysadmin ou desenvolvedor, através de um checklist prático e robusto para endurecer sua instalação do Linux antes mesmo de instalar o Node.js. Um servidor bem configurado dificulta a vida de atacantes, reduz a superfície de ataque e garante que, caso uma falha ocorra no nível da aplicação, o sistema operacional continue estável e isolado.
1. Preparação do Ambiente e Atualização do Sistema
A primeira regra de ouro é nunca começar com um sistema desatualizado. Vulnerabilidades conhecidas (CVEs) em pacotes base são frequentemente exploradas automaticamente por bots na internet. Antes de qualquer configuração avançada, execute o update completo da sua distribuição Linux.
Para sistemas baseados em Debian e Ubuntu (como a maioria das VPS populares):
sudo apt update && sudo apt upgrade -y
sudo apt autoremove -y
Para sistemas baseados em RHEL, CentOS ou Amazon Linux:
sudo yum update -y
# Ou para DNF:
sudo dnf update -y
Reinicie o servidor após grandes atualizações do kernel para garantir que todas as novas camadas de segurança estejam ativas:
sudo reboot
2. Gestão de Usuários e Acesso SSH Seguro
O acesso root direto é o vetor de ataque mais comum. Hackers utilizam scripts automatizados para tentar credenciais padrão contra a porta 22 (SSH). Para mitigar isso, precisamos criar um usuário não-root com privilégios sudo e desabilitar o login raiz.
Criando um Usuário Administrativo
Crie um novo usuário, por exemplo, admin, e adicione-o ao grupo de sudoers:
sudo adduser admin
sudo usermod -aG sudo admin
Defina uma senha forte para este novo usuário ou, preferencialmente, configure chaves SSH para autenticação sem senha (recomendado para maior segurança).
Configurando o SSHD
Edite o arquivo de configuração do serviço SSH. No Debian/Ubuntu, o caminho é /etc/ssh/sshd_config.
sudo nano /etc/ssh/sshd_config
Realize as seguintes alterações críticas:
- PermitRootLogin no: Impede que qualquer pessoa tente logar como root. Isso força o atacante a adivinhar um nome de usuário válido antes de tentar uma senha.
- PasswordAuthentication no: Desabilita login por senha. Force o uso de chaves SSH públicas/privadas. Senhas são vulneráveis a ataques de força bruta e dicionário.
- Port 22: Considere mudar para uma porta não padrão (ex:
Port 2200). Isso não é segurança por obscuridade, mas reduz drasticamente o ruído dos logs e ataques automatizados.
Exemplo de configuração segura no arquivo:
PermitRootLogin no
PasswordAuthentication no
Port 2200
AllowUsers admin
Após salvar as alterações, reinicie o serviço SSH para aplicar as mudanças:
sudo systemctl restart sshd
Atenção: Antes de fechar sua sessão atual, teste a conexão com o novo usuário em uma nova janela de terminal. Se você mudou a porta, lembre-se de especificá-la no comando de conexão:
ssh -p 2200 admin@seu_ip
3. Configuração do Firewall (UFW)
Um firewall é sua primeira linha de defesa perimetral. O UFW (Uncomplicated Firewall) é uma interface amigável para o iptables, disponível nativamente em muitas distribuições Linux.
Primeiro, instale o UFW se ainda não estiver presente:
sudo apt install ufw
Agora, defina as políticas padrão. A lógica é simples: bloquear tudo que não foi explicitamente permitido.
sudo ufw default deny incoming
sudo ufw default allow outgoing
Habilite o acesso SSH. Se você mudou a porta para 2200, como sugerido acima, permita o acesso nela:
sudo ufw allow 2200/tcp
Se sua aplicação Node.js rodará na porta padrão HTTP (80) ou HTTPS (443), abra essas portas agora. Para fins de teste e hardening inicial, podemos deixar o HTTP aberto, mas o ideal em produção é usar um proxy reverso (como Nginx) que gerencia o TLS.
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
Ative o firewall e verifique o status:
sudo ufw enable
sudo ufw status verbose
O comando enable irá perguntar se deseja continuar, pois pode interferir em conexões SSH ativas. Confirme apenas se você tem certeza de que a regra SSH está correta.
4. Instalação Segura do Node.js e NPM
Agora que o sistema operacional está protegido, focamos na aplicação. Evite instalar o Node.js via apt install nodejs, pois as versões nos repositórios oficiais costumam ser desatualizadas e podem conter vulnerabilidades conhecidas já corrigidas em versões mais recentes.
A maneira recomendada de manter controle sobre a versão e garantir atualizações seguras é através do nvm (Node Version Manager).
Instalando o NVM
Faça login como seu usuário admin (não use root) e execute o script de instalação oficial:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
Para carregar o comando nvm no seu terminal atual, feche e reabra o terminal ou execute:
source ~/.bashrc
Instalando a Versão LTS do Node.js
O NVM permite instalar múltiplas versões. Para produção, sempre utilize a versão LTS (Long Term Support), que recebe correções de segurança por um período prolongado.
nvm install --lts
nvm use --lts
nvm alias default lts/*
Verifique a instalação:
node -v
npm -v
Segurança do NPM
O ecossistema de pacotes do Node.js é vasto, mas também alvo de ataques de "typosquatting" e injeção de código malicioso em dependências. Adote as seguintes práticas:
- Sempre verifique o nome do pacote antes de instalar.
- Use
npm ciem vez denpm installem ambientes de produção. Ociignora opackage.jsone instala estritamente conforme opackage-lock.json, garantindo reproduzibilidade e evitando atualizações não intencionais. - Execute regularmente
npm auditpara identificar dependências com vulnerabilidades conhecidas.
5. Isolamento de Processo e Execução
Nunca, em hipótese alguma, execute sua aplicação Node.js como usuário root. Se houver uma falha de segurança na sua aplicação (como um exploit de RCE - Remote Code Execution), o atacante terá controle total do servidor.
A solução é executar a aplicação sob um usuário dedicado e com permissões mínimas.
Criando Usuário Dedicado
sudo adduser --disabled-password --gecos "" nodeapp
# Adicione este usuário ao grupo sudo apenas se ele precisar fazer deploy, mas não execute a app como root
Usando Systemd para Gerenciamento Seguro
O Systemd é o gerenciador de processos do Linux e oferece recursos poderosos de isolamento. Crie um arquivo de serviço para sua aplicação Node.js.
sudo nano /etc/systemd/system/nodeapp.service
Configure o arquivo com as seguintes diretrizes de segurança:
[Unit]
Description=Node.js Application
After=network.target
[Service]
Type=simple
User=nodeapp
Group=nodeapp
WorkingDirectory=/var/www/nodeapp
ExecStart=/home/admin/.nvm/versions/node/v18.16.0/bin/node server.js
Restart=on-failure
# Hardening do Systemd
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
ReadWritePaths=/var/www/nodeapp/logs
[Install]
WantedBy=multi-user.target
Explicação das diretivas de hardening no Systemd:
- NoNewPrivileges=yes: Impede que o processo ganhe novos privilégios (ex: via setuid).
- ProtectSystem=strict: Torna todo o sistema de arquivos apenas leitura, exceto diretórios explícitos.
- PrivateTmp=yes: Dá ao processo seu próprio espaço temporário isolado do resto do sistema.
- User=nodeapp: Garante que a app rode com permissões limitadas do usuário criado especificamente para ela.
Ative e inicie o serviço:
sudo systemctl daemon-reload
sudo systemctl enable nodeapp
sudo systemctl start nodeapp
6. Monitoramento e Logs
A segurança não termina com a configuração inicial. Você precisa monitorar o que acontece no seu servidor. O fail2ban é uma ferramenta essencial para proteção contra ataques de força bruta no SSH.
Instalando Fail2Ban
sudo apt install fail2ban
Crie um arquivo de configuração local para não sobrescrever as configurações padrão durante atualizações:
sudo nano /etc/fail2ban/jail.local
Adicione a seguinte configuração para proteger sua porta SSH personalizada:
[sshd]
enabled = true
port = 2200
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
Reinicie o fail2ban:
sudo systemctl restart fail2ban
Isso bloqueará automaticamente qualquer IP que tentar fazer mais de 3 logins falhos no SSH em um período curto.
7. Atualização Contínua e Backups
O hardening é um processo contínuo, não um evento único.
- Atualizações Automáticas: Configure atualizações de segurança automáticas para o sistema operacional. No Debian/Ubuntu, use o pacote
unattended-upgrades. - Backups: Implemente backups regulares do seu código-fonte e configurações. Teste a restauração desses backups periodicamente.
- Auditoria de Dependências: Integre
npm auditno seu pipeline de CI/CD para bloquear deploys que introduzam vulnerabilidades conhecidas.
Lembre-se: a segurança é uma camada. Se o Node.js tiver uma falha, o Systemd isola o dano. Se o SSH for atacado, o Fail2Ban bloqueia o invasor. Se o firewall estiver ativo, portas desnecessárias permanecem fechadas.
Ao seguir estes passos, você transforma sua VPS de um servidor padrão em uma máquina robusta, pronta para hospedar aplicações Node.js com um nível profissional de segurança e estabilidade.