Linux: Projeto Final — Montando um Servidor Web Dev do Zero

Esse é o projeto final do curso. Você vai juntar tudo que aprendeu nas 25 aulas anteriores — começando de uma máquina zerada pra montar um servidor de desenvolvimento Web totalmente funcional.

📋 Pré-requisitos: Você já deve conhecer

1. O Que Você Vai Aprender


2. O Desafio "Vai Pra Produção Amanhã" do Xiaoming

(1) O Problema: Servidor Novo, Tem que Ir Pra Produção Amanhã

A empresa do Xiaoming comprou um servidor na nuvem. O chefe disse: "vai pra produção amanhã". Diante de uma máquina zerada com apenas um IP e a senha de root, o Xiaoming precisava aplicar tudo que tinha aprendido.

(2) 10 Passos Da Máquina Nua Até a Produção

O Xiaoming montou um plano:

BASH

1. Login SSH           → 6. Deploy da app Node.js
2. Criação de usuário + hardening do SSH → 7. Configurar certificado HTTPS
3. Config do firewall   → 8. Configurar o gerenciador de processos PM2
4. Instalar o Nginx     → 9. Backup automatizado
5. Configurar proxy reverso → 10. Health check + alertas

(3) O Benefício: Entregue em 3 Horas

O Xiaoming começou às 14h, executou o plano passo a passo e terminou o deploy completo às 17h. O chefe testou e respondeu: "bom, tá pronto pra produção".


3. Pontos-Chave

(1) Checklist de Inicialização do Servidor

BASH
□ Login SSH (senha de root)
□ Atualizar o sistema (apt update && apt upgrade)
□ Criar usuário comum (useradd -m -s /bin/bash)
□ Configurar sudo (usermod -aG sudo)
□ Autenticação por chave SSH
□ Desabilitar login de root + por senha
□ Firewall (ufw: 22/80/443)
□ Proteção com fail2ban
□ Atualizações automáticas de segurança
⚠️ Atenção: Antes de desabilitar o login por senha, garanta que as chaves SSH estão configuradas e testadas. Caso contrário, você vai ficar trancado do lado de fora do servidor. Ordem recomendada: 1) Configure as chaves; 2) Faça login com sucesso usando as chaves; 3) Confirme que tudo funciona e só então desabilite o login por senha. Mantenha sempre uma sessão SSH ativa como rede de segurança.

(2) Stack LEMP (Linux + Nginx + MySQL + PHP/Node.js/Python)

BASH
# Nginx
sudo apt install nginx
sudo systemctl enable --now nginx

# Se for usar MySQL
sudo apt install mysql-server
sudo mysql_secure_installation

# Comparação de deploy de aplicação
Método Melhor Para Prós Contras
serviço systemd Qualquer linguagem Nativo, maduro, estável Config um pouco mais complexa
PM2 Node.js Zero config, monitoramento embutido Só Node.js
Gunicorn/uWSGI Python Boa performance, padrão WSGI Precisa de Nginx
Docker Compose Apps complexos Ambiente consistente, fácil de escalar Exige conhecimento de Docker

(3) ▶ Exemplo: Deploy de uma App Node.js no Nginx

BASH
#!/bin/bash
# Faz o deploy de uma app Node.js em produção

# 1. Criar diretório da app
sudo mkdir -p /opt/webapp
sudo chown -R alice:alice /opt/webapp

# 2. Clonar os arquivos da app (assumindo que já foi desenvolvida)
git clone https://github.com/example/webapp.git /opt/webapp

# 3. Instalar dependências e build
cd /opt/webapp
npm install
npm run build

# 4. Configurar o PM2
npm install -g pm2
pm2 start server.js --name webapp -i max
pm2 save
pm2 startup

# 5. Configurar proxy reverso do Nginx
sudo tee /etc/nginx/sites-available/webapp << 'EOF'
server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location /static/ {
        alias /opt/webapp/public/;
        expires 30d;
    }
}
EOF

sudo ln -sf /etc/nginx/sites-available/webapp /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t && sudo systemctl reload nginx

Saída:

TEXT
npm WARN deprecated package@1.0.0
added 245 packages in 12s
Building production bundle...
[PM2] Process webapp started
┌────┬──────────┬─────────┬─────────┐
│ id │ name     │ status  │ cpu     │
├────┼──────────┼─────────┼─────────┤
│ 0  │ webapp   │ online  │ 0%      │
└────┴──────────┴─────────┴─────────┘
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

(4) ▶ Exemplo: HTTPS (Let's Encrypt + certbot)

💡 Dica: O certbot adiciona automaticamente um systemd timer ou um job do cron pra renovar os certificados. Depois de configurar, teste o processo de renovação com sudo certbot renew --dry-run. Também vale colocar um lembrete no calendário pra verificar manualmente se a renovação deu certo uns 30 dias antes do vencimento (por volta do dia 60), caso alguma mudança de config tenha quebrado a renovação automática.

BASH
# Instalar o certbot
sudo apt install certbot python3-certbot-nginx -y

# Obter o certificado (modifica automaticamente a config do Nginx)
sudo certbot --nginx -d example.com -d www.example.com

# Ver os certificados
sudo certbot certificates

# Validar a renovação automática
sudo certbot renew --dry-run

# Renovação automática (o certbot adiciona um timer do systemd)
sudo systemctl list-timers | grep certbot

Saída:

TEXT
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Requesting a certificate for example.com and www.example.com
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/example.com/fullchain.pem

Found the following certs:
  Certificate Name: example.com
    Expiry Date: 2026-10-05 10:23:45+00:00 (VALID: 89 days)

Congratulations, all simulated renewals succeeded:
  /etc/letsencrypt/live/example.com/fullchain.pem

certbot.timer  certbot.service  Sat 2026-07-08 00:00:00 UTC  13h left

(5) ▶ Exemplo: Script de Health Check

BASH
#!/bin/bash
# health-check.sh - Health check multi-serviço

check_service() {
    local name="$1"
    local url="$2"
    local expect="${3:-200}"

    local status=$(curl -s -o /dev/null -w "%{http_code}" "$url" 2>/dev/null)

    if [ "$status" = "$expect" ]; then
        echo "[OK] $name: $status (saudavel)"
        return 0
    else
        echo "[FAIL] $name: $status (com problema)"
        return 1
    fi
}

echo "=== Health Check do Sistema ==="
echo "Horario: $(date)"
echo ""

# Recursos do sistema
echo "CPU: $(top -bn1 | grep "Cpu(s)" | awk '{print $2}')%"
echo "Memoria: $(free -h | grep Mem | awk '{print $3 "/" $2}')"
echo "Disco: $(df -h / | tail -1 | awk '{print $3 "/" $2 " (" $5 ")"}')"
echo ""

# Serviços web
check_service "Nginx" "http://localhost/nginx_status" 200
check_service "WebApp" "http://localhost:3000/health" 200
check_service "HTTPS" "https://example.com/" 200

echo ""
echo "=== Check Concluido ==="

Saída:

TEXT
=== Health Check do Sistema ===
Horario: Tue Jul  7 10:30:00 UTC 2026

CPU: 2.3%
Memoria: 1.2Gi/3.9Gi
Disco: 12G/50G (24%)

[OK] Nginx: 200 (saudavel)
[OK] WebApp: 200 (saudavel)
[OK] HTTPS: 200 (saudavel)

=== Check Concluido ===

(6) ▶ Exemplo: Script Completo de Deploy

⚠️ Atenção: O padrão curl -fsSL URL | bash - executa um script remoto direto na sua máquina, o que traz risco de ataque na cadeia de suprimentos — se a fonte for comprometida ou o DNS for sequestrado, você pode executar código malicioso. Em produção, a abordagem mais segura é baixar e revisar o script antes, e depois executar: curl -fsSL URL -o setup.sh && less setup.sh && bash setup.sh.

BASH
#!/bin/bash
# setup-server.sh - Monta um servidor Web dev do zero
# Uso: sudo ./setup-server.sh example.com

set -euo pipefail

DOMAIN="${1:-example.com}"
APP_DIR="/opt/webapp"
APP_PORT=3000
ADMIN_USER="admin"

echo "========================================"
echo "    Montando o Servidor Web Dev do Zero"
echo "    Dominio: $DOMAIN"
echo "========================================"

# 1. Atualizar o sistema
echo ""
echo ">>> 1/10 Atualizando o sistema..."
apt update && apt upgrade -y

# 2. Criar usuário comum
echo ""
echo ">>> 2/10 Criando o usuario admin..."
if ! id "$ADMIN_USER" &>/dev/null; then
    useradd -m -s /bin/bash "$ADMIN_USER"
    usermod -aG sudo "$ADMIN_USER"
    echo "Defina a senha para $ADMIN_USER:"
    passwd "$ADMIN_USER"

    # Obs: adicione manualmente sua chave SSH pública em /home/$ADMIN_USER/.ssh/authorized_keys
    mkdir -p /home/$ADMIN_USER/.ssh
    cp /root/.ssh/authorized_keys /home/$ADMIN_USER/.ssh/ 2>/dev/null || true
    chown -R $ADMIN_USER:$ADMIN_USER /home/$ADMIN_USER/.ssh
    chmod 700 /home/$ADMIN_USER/.ssh
    chmod 600 /home/$ADMIN_USER/.ssh/authorized_keys
fi

# 3. Hardening do SSH
echo ""
echo ">>> 3/10 Fazendo o hardening do SSH..."
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup
sed -i 's/^PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
sed -i 's/^#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sed -i 's/^#PubkeyAuthentication yes/PubkeyAuthentication yes/' /etc/ssh/sshd_config
systemctl restart sshd

# 4. Firewall
echo ""
echo ">>> 4/10 Configurando o firewall..."
ufw default deny incoming
ufw default allow outgoing
ufw allow 22/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw --force enable

# 5. fail2ban
echo ""
echo ">>> 5/10 Instalando o fail2ban..."
apt install -y fail2ban
cat > /etc/fail2ban/jail.d/sshd.conf << EOF
[sshd]
enabled = true
maxretry = 3
bantime = 86400
findtime = 600
EOF
systemctl enable --now fail2ban

# 6. Instalar o Nginx
echo ""
echo ">>> 6/10 Instalando o Nginx..."
apt install -y nginx
systemctl enable --now nginx

# 7. Instalar o Node.js
echo ""
echo ">>> 7/10 Instalando o Node.js..."
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
apt install -y nodejs
npm install -g pm2

# 8. Configurar proxy reverso do Nginx
echo ""
echo ">>> 8/10 Configurando o Nginx..."
cat > /etc/nginx/sites-available/$DOMAIN << EOF
server {
    listen 80;
    server_name $DOMAIN www.$DOMAIN;

    location / {
        proxy_pass http://127.0.0.1:$APP_PORT;
        proxy_http_version 1.1;
        proxy_set_header Upgrade \$http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host \$host;
        proxy_cache_bypass \$http_upgrade;
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto \$scheme;
    }
}
EOF

ln -sf /etc/nginx/sites-available/$DOMAIN /etc/nginx/sites-enabled/
rm -f /etc/nginx/sites-enabled/default
nginx -t && systemctl reload nginx

# 9. Certificado HTTPS
echo ""
echo ">>> 9/10 Configurando HTTPS..."
apt install -y certbot python3-certbot-nginx
certbot --nginx --non-interactive --agree-tos \
    --email admin@$DOMAIN \
    -d $DOMAIN -d www.$DOMAIN \
    || echo "Atencao: certbot falhou, rode manualmente: sudo certbot --nginx -d $DOMAIN"

# 10. Script de health check
echo ""
echo ">>> 10/10 Configurando o health check..."
mkdir -p /opt/scripts

cat > /opt/scripts/health-check.sh << 'EOF'
#!/bin/bash
WEBHOOK="https://hooks.slack.com/services/YOUR/WEBHOOK"

for svc in nginx sshd fail2ban; do
    if ! systemctl is-active --quiet "$svc"; then
        echo "[$(date)] FAIL: $svc esta fora" >> /var/log/health.log
    fi
done

DISK=$(df / | tail -1 | awk '{print $5}' | tr -d '%')
[ "$DISK" -gt 85 ] && echo "[$(date)] WARNING: Uso de disco ${DISK}%" >> /var/log/health.log
EOF

chmod +x /opt/scripts/health-check.sh

# Adicionar ao cron
(crontab -l 2>/dev/null; echo "*/10 * * * * /opt/scripts/health-check.sh > /dev/null 2>&1") | crontab -

echo ""
echo "========================================"
echo "Setup do servidor concluido!"
echo ""
echo "Informacoes do deploy:"
echo "  Usuario admin: $ADMIN_USER"
echo "  Nginx: http://$DOMAIN"
echo "  HTTPS: https://$DOMAIN (se o certbot deu certo)"
echo "  Node.js: $(node --version)"
echo "  PM2: $(pm2 --version)"
echo ""
echo "Proximos passos:"
echo "  1. Faca o deploy do codigo da sua aplicacao em $APP_DIR"
echo "  2. Inicie a aplicacao: pm2 start $APP_DIR/server.js --name webapp"
echo "  3. Faca login como $ADMIN_USER (login de root esta desabilitado)"
echo "========================================"

Saída:

TEXT
========================================
    Montando o Servidor Web Dev do Zero
    Dominio: example.com
========================================

>>> 1/10 Atualizando o sistema...
...
========================================
Setup do servidor concluido!
Usuario admin: admin
Nginx: http://example.com
Node.js: v20.11.0
========================================

(7) ▶ Exemplo Abrangente: Verificação Pós-Deploy

BASH
#!/bin/bash
# verify-deploy.sh - Verificação pós-deploy

echo "========================================"
echo "    Verificacao do Deploy"
echo "    Horario: $(date)"
echo "========================================"
echo ""

errors=0

check() {
    local desc="$1"
    shift
    if "$@" &>/dev/null; then
        echo "  [OK] $desc"
    else
        echo "  [FAIL] $desc"
        errors=$((errors + 1))
    fi
}

echo "1. Servicos do Sistema"
echo "-----------"
check "Nginx rodando" systemctl is-active nginx
check "SSH rodando" systemctl is-active sshd
check "fail2ban rodando" systemctl is-active fail2ban
echo ""

echo "2. Rede"
echo "--------"
check "Porta 80 em escuta" ss -tlnp grep -q ":80 "
check "Porta 443 em escuta" ss -tlnp grep -q ":443 "
check "ufw ativo" ufw status grep -q active
echo ""

echo "3. Servico HTTP"
echo "-------------"
check "Nginx local respondendo" curl -s -o /dev/null -w "%{http_code}" http://localhost grep -q 200
check "Processo da app rodando" pm2 list 2>/dev/null grep -q "online" || pgrep -f "node server" > /dev/null
echo ""

echo "4. Seguranca"
echo "--------"
check "SSH root desabilitado" grep "^PermitRootLogin" /etc/ssh/sshd_config grep -q "no"
check "Login por senha desabilitado" grep "^PasswordAuthentication" /etc/ssh/sshd_config grep -q "no"
echo ""

echo "5. Recursos"
echo "--------"
echo "  CPU: $(top -bn1 | grep 'Cpu(s)' | awk '{print $2"%"}' )"
echo "  Memoria: $(free -h | grep Mem | awk '{print $3"/"$2}')"
echo "  Disco: $(df -h / | tail -1 | awk '{print $3"/"$2"("$5")"}')"
echo ""

echo "========================================"
if [ $errors -eq 0 ]; then
    echo "Todas as verificacoes passaram!"
else
    echo "$errors verificacao(oes) falhou(aram) - investigue"
fi
echo "========================================"

Saída:

TEXT
========================================
    Verificacao do Deploy
    Horario: Tue Jul  7 10:45:00 UTC 2026
========================================

1. Servicos do Sistema
-----------
  [OK] Nginx rodando
  [OK] SSH rodando
  [OK] fail2ban rodando

2. Rede
--------
  [OK] Porta 80 em escuta
  [OK] Porta 443 em escuta
  [OK] ufw ativo

3. Servico HTTP
-------------
  [OK] Nginx local respondendo
  [OK] Processo da app rodando

4. Seguranca
--------
  [OK] SSH root desabilitado
  [OK] Login por senha desabilitado

5. Recursos
--------
  CPU: 2.3%
  Memoria: 1.2Gi/3.9Gi
  Disco: 12G/50G(24%)

========================================
Todas as verificacoes passaram!
========================================

❓ Perguntas Frequentes

P: Qual é a primeira coisa a fazer ao colocar um servidor em produção? R: Atualizar o sistema (apt update && apt upgrade), em seguida criar um usuário comum e configurar a autenticação por chave SSH. Nunca trabalhe como root por muito tempo.

P: Qual a relação entre o proxy reverso do Nginx e a aplicação? R: O Nginx é a "porta da frente" e a aplicação são "as pessoas lá dentro". Os usuários acessam o Nginx nas portas 80/443 → o Nginx decide pra qual app de backend encaminhar a requisição. O Nginx cuida dos arquivos estáticos, terminação SSL e balanceamento de carga; a app foca na lógica de negócio.

P: Os certificados HTTPS precisam de renovação periódica? R: Os certificados da Let's Encrypt têm validade de 90 dias. O certbot adiciona automaticamente um timer do systemd pra renovar. Verifique com: systemctl list-timers | grep certbot. Renovação manual: sudo certbot renew.

P: Quais métricas devo monitorar num servidor? R: Métricas essenciais: uso de CPU, consumo de memória, espaço em disco (alerta em >80%), I/O de disco, tráfego de rede, status dos serviços e vencimento do certificado SSL.

P: Como verificar a segurança depois do deploy? R: Rode ferramentas de scan de segurança: 1) sudo ufw status pra conferir as portas. 2) ss -tlnp pra ver os endereços de escuta dos serviços. 3) grep "Failed password" /var/log/auth.log | wc -l pra medir o volume de ataques. 4) Use https://www.ssllabs.com/ssltest/ pra testar a configuração SSL.


📖 Resumo


📝 Exercícios

  1. Básico (⭐): Usando uma VM ou servidor na nuvem, execute o script setup-server.sh do zero, faça deploy de uma app Web simples em Node.js ou Python e acesse ela através do proxy reverso do Nginx
  2. Intermediário (⭐⭐): Configure um certificado HTTPS da Let's Encrypt (use --dry-run pra testar), escreva e faça deploy de um script de health check e configure alertas (e-mail ou webhook)
  3. Desafio (⭐⭐⭐⭐⭐): Configure uma estratégia completa de backup (cron + rsync remoto) e verifique se os backups podem ser restaurados, depois escreva um script automatizado de verificação de deploy que confira status de todos os serviços, configurações de segurança e métricas de performance, e gere um relatório de aceitação formatado
Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%