Roteiro para configurar um VPS Ubuntu 24.04 a partir do root até um ambiente endurecido com usuário
não-root, SSH key-only, fail2ban, UFW e diretório de deploy pronto.
Otávio aqui: isso foi 99% escrito pelo
Claudeusando meu DEV_GUIDE de outros vídeos.
VPS já provisionado e acesso via root.
Acesse o VPS conforme o provedor permitir. Na Hostinger isso pode ser feito na
tela do hPanel em VPS -> Visão Geral -> Terminal.
Depois crie o seu usuário
apt update && apt upgrade -y
useradd -m -s /bin/bash luizotavio
usermod -aG sudo luizotavio
# Isso é para configurar a senha do seu usuário
passwd luizotavioO que acontece:
apt update && upgradeaplica patches de segurança pendentes.useradd -m -s /bin/bashcria o usuário com home (-m) e shell bash (-s).usermod -aG sudocoloca no gruposudo(no Ubuntu, esse grupo é o que recebe permissão via/etc/sudoers).passwddefine a senha que osudovai pedir mais tarde (mesmo com NOPASSWD configurado depois, é boa prática ter senha local pra console).
(Opcional) dotfiles para o root:
Isso é pra configurar tudo em modo vim. TUDO MESMO, incluindo o terminal. Se
você não entendeu algo do que está escrito nessa frase, pule este trecho.
# De novo, modo vim, se não sabe o que é, não aplique isso.
GIST_BASE='https://gist.githubusercontent.com/luizomf/9a52ba5b7b43aa69cc9a7121795bb9fa/raw/30d935ffe0eeb8e191b3bb98582edcd8d074e378'
curl -fsSL "$GIST_BASE/.vimrc" -o /root/.vimrc
curl -fsSL "$GIST_BASE/bash_minimal_setup" >> /root/.bashrcSubstitua o gist pelo seu. Esse aí é o do Otávio (
jj→Esc, KISS auto session, etc.). Se não quiser personalizar, pula.
Atenção: se for adicionar ao grupo docker, só rode se o docker estiver
instalado - caso contrário, usermod -aG docker é silencioso e o grupo nem
existe:
# só se docker estiver instalado:
# usermod -aG docker luizotavioDepois, vira o user (ou desconecta e reconecta como ele):
su luizotavioGere sua chave SSH:
Esses comandos são no seu computador:
# NO SEU COMPUTADOR
ssh-keygen -t ed25519 -a 100 -f ~/.ssh/nome_da_chave -C "luizotavio"
# ENTER ENTER ENTER
ssh-copy-id -i ~/.ssh/nome_da_chave.pub luizotavio@IP_OU_HOST_DO_VPS
# Digite sua senha e tente acessar
ssh luizotavio@IP_OU_HOST_DO_VPS -i ~/.ssh/nome_da_chave.pub# Modo vim (opcional), se não sabe o que é, não aplique isso.
# Basta pular.
GIST_BASE='https://gist.githubusercontent.com/luizomf/9a52ba5b7b43aa69cc9a7121795bb9fa/raw/30d935ffe0eeb8e191b3bb98582edcd8d074e378'
curl -fsSL "$GIST_BASE/.vimrc" -o ~/.vimrc
curl -fsSL "$GIST_BASE/bash_minimal_setup" >> ~/.bashrc
. ~/.bashrcecho "luizotavio ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/luizotavio
sudo chmod 440 /etc/sudoers.d/luizotavioTradeoff honesto: isso libera sudo sem senha. Conforto enorme pra workflow
com agente, mas se sua chave SSH vazar, é root direto. Se tu não roda agente,
considere deixar sem NOPASSWD e digitar a senha quando preciso. Mas, vale
lembrar que o agente não vai conseguir instalar nada se sua senha ou sem você
permitir de alguma forma. Segurança vs Conforto, escolha.
A permissão 440 no arquivo é exigida pelo visudo — sem ela, sudo se recusa
a ler o sudoers e pode até travar tudo.
sudo apt install -y vim curl ca-certificates htop python3 python3-dev acl \
build-essential tree just fail2ban ufwacl→ ACLs estendidas (precisamos prasetfaclem/projects).fail2ban+ufw→ as duas ferramentas centrais do hardening.just→ command runner moderno (Justfile), opcional mas útil.
sudo timedatectl set-timezone America/Sao_PauloNão é segurança, é sanidade. Logs em UTC viram quebra-cabeça depois.
sudo tee /etc/ssh/sshd_config.d/01_sshd_settings.conf >/dev/null <<'EOF'
# Hardened SSH config (drop-in, loaded before cloud-init defaults)
# Authentication
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
ChallengeResponseAuthentication no
PermitRootLogin no
PermitEmptyPasswords no
UsePAM no
AuthenticationMethods publickey
# Attack surface reduction
PermitUserEnvironment no
PermitUserRC no
X11Forwarding no
AllowStreamLocalForwarding no
AllowAgentForwarding no
# Session management
MaxAuthTries 4
LoginGraceTime 30
ClientAliveInterval 300
ClientAliveCountMax 2
UseDNS no
# Show ip on login/logout
PrintLastLog no
PrintMotd no
LogLevel ERROR
Banner none
# Allow tunnels
# Se não usar tunnels, mude para o trecho comentado
# AllowTcpForwarding no
# PermitOpen none
# PermitListen none
# GatewayPorts no
AllowTcpForwarding yes
PermitOpen any
PermitListen any
GatewayPorts yes
EOF
sudo chmod 600 /etc/ssh/sshd_config.d/01_sshd_settings.conf
sudo sshd -t && sudo systemctl restart sshsudo tee /etc/fail2ban/jail.local >/dev/null <<'EOF'
[DEFAULT]
ignoreip = 127.0.0.1/8 ::1
allowipv6 = auto
[sshd]
enabled = true
port = ssh
backend = systemd
maxretry = 5
findtime = 10m
bantime = 1h
bantime.increment = true
bantime.factor = 2
bantime.max = 24h
EOF
sudo systemctl enable --now fail2banTradução: depois de 5 falhas em 10 minutos, banido por 1h. A cada nova
reincidência o tempo dobra (factor = 2), até no máximo 24h. Bom contra
brute-force estúpido — não é solução final, mas reduz ruído absurdo.
backend = systemd lê os logs direto do journald (Ubuntu 24.04 não escreve mais
em /var/log/auth.log por padrão).
CRÍTICO: libere SSH antes de habilitar o UFW. Se não, o
enablepode te trancar fora.
sudo ufw disable
yes | sudo ufw reset
sudo ufw default deny incoming
sudo ufw default allow outgoing
# For static IP (if you have it)
# sudo ufw allow from YOUR_IP_ADDRESS_HERE to any port 22 proto tcp comment 'SSH Home'
# If you use the rule above, you should consider not using the rule below.
sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
echo y | sudo ufw enable- Tudo que entra é negado por padrão.
- Tudo que sai é liberado (necessário pro Claude Code Remote, apt, etc.).
- Apenas 22, 80, 443 ficam abertos pro mundo.
Se você usa WireGuard, considere fechar até a 22 e abrir só pra rede VPN:
sudo ufw delete allow ssh sudo ufw allow from 10.0.0.0/24 to any port 22O Claude Code Remote continua funcionando porque é conexão outbound do VPS — você não precisa expor porta nenhuma pro mundo pra controlar pelo navegador/celular.
# NEW
# Just a link to /projects directory
sudo install -d /projects -o luizotavio -g luizotavio -m 2775
git config --global --add safe.directory /projects
sudo setfacl -m d:g:luizotavio:rwx /projects
ln -sfn /projects ~/projectsResumo: qualquer arquivo criado em /projects (por você, por container, por
agente) é acessível pelo grupo luizotavio sem chmod manual depois.
Se o template já vem com o Claude instalado em
/root/.local, você só precisa copiar pra sua home e ajustar PATH. Se quer instalar do zero:
curl -fsSL claude.ai/install.sh | bash
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
. ~/.bashrc
claude # primeiro login (interativo)O modo CLI normal (claude) morre quando você fecha o terminal. Para
sobreviver à desconexão:
Opção A — tmux (rápido):
tmux new -s claude
claude --remote-control
# Ctrl+b d → detach (agente continua vivo)
# tmux attach -t claude → volta depoisReboot do VPS mata tmux. Pra sobreviver a reboot, precisa systemd.
Opção B — systemd user service (produção):
mkdir -p ~/.config/systemd/user
cat > ~/.config/systemd/user/claude-remote.service <<'EOF'
[Unit]
Description=Claude Code Remote Control
After=network-online.target
[Service]
ExecStart=%h/.local/bin/claude --remote-control
Restart=on-failure
RestartSec=5
[Install]
WantedBy=default.target
EOF
loginctl enable-linger "$USER"
systemctl --user daemon-reload
systemctl --user enable --now claude-remoteloginctl enable-linger é essencial — sem ele, o systemd user mata seus
serviços quando você desloga.
Depois de rodar tudo, confirme:
# SSH endurecido?
sudo sshd -T | grep -iE 'passwordauth|permitroot|pubkeyauth'
# fail2ban ativo e watching SSH?
sudo fail2ban-client status sshd
# UFW ativo e regras certas?
sudo ufw status verbose
# Timezone OK?
timedatectl | grep -i 'time zone'
# /projects com setgid + ACL?
ls -ld /projects && getfacl /projectsCoisas que valem estudo, fora do escopo deste roteiro mínimo:
unattended-upgrades— patches de segurança automáticos. Linha única:sudo dpkg-reconfigure -plow unattended-upgrades.- WireGuard — fechar 22/80/443 e expor tudo só pra VPN. Casa perfeito com o Claude Code Remote (que é outbound).
- Traefik / reverse proxy — Solicitar
claudepara configurar, liberar no UFW e fazer checagens de segurança. Mantenha um registro A com valor*no DNS do domínio apontando para o IP do no VPS. Isso permite ter quantos subdomínios você quiser no mesmo servidor.
Roteiro construído numa sessão Claude Code Remote rodando dentro do próprio VPS
Hostinger. O conteúdo da conversa original está em claude-vps.txt nesta pasta
— vale ler se quiser ver a investigação e o "porquê" de cada decisão.
By Claude com base no DEV_GUIDE.md e revisão do Otávio 🤝