Sem Docker, sem PaaS, sem magia. Node.js plus systemd e Nginx é uma pilha que sobrevive a reinícios, falhas e tráfego — e você pode ler tudo.
apt update && apt install -y curl
curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
apt install -y nodejs
node --version
Nunca execute uma aplicação web como root. Um usuário separado limita o dano caso o aplicativo seja comprometido.
adduser --system --group --home /opt/myapp app
mkdir -p /opt/myapp
chown app:app /opt/myapp
Do seu laptop, com rsync sobre SSH — nenhum servidor Git necessário:
rsync -avz --exclude node_modules ./app/ root@YOUR_SERVER_IP:/opt/myapp/
No servidor, instale dependências e teste uma vez no primeiro plano:
cd /opt/myapp
sudo -u app npm ci --omit=dev
sudo -u app PORT=3000 node server.js
O aplicativo deve ouvir 127.0.0.1:3000 — não na interface pública. Nginx vai enfrentar a internet.
cat > /etc/systemd/system/myapp.service <<'EOF'
[Unit]
Description=My Node.js app
After=network-online.target
[Service]
User=app
WorkingDirectory=/opt/myapp
Environment=NODE_ENV=production
Environment=PORT=3000
ExecStart=/usr/bin/node server.js
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now myapp
systemctl status myapp
Acidente? Reinicia em três segundos. Reiniciar? Começa automaticamente. Lançar uma nova versão? rsync, então systemctl restart myapp.
apt install -y nginx
cat > /etc/nginx/sites-available/myapp <<'EOF'
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
EOF
ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/myapp
nginx -t && systemctl reload nginx
Em seguida, aponte o registro A do seu domínio no servidor e adicione HTTPS — o passe completo está no Guia Nginx e HTTPS.
journalctl -u myapp -f --no-pager
tail -f /var/log/nginx/error.log
A saída do console do seu aplicativo fica no diário automaticamente — não há arquivos de registro para configurar.
Nem por isso. systemd faz tudo que o PM2 faz para um único servidor — auto-iniciar, iniciar o arranque, registar — sem uma dependência extra. PM2 faz sentido principalmente se você executar vários processos Node com clustering.
Um aplicativo Express típico fica ocioso em torno de 80–150 MB. Um servidor de 2 GB executa-o confortavelmente ao lado de Nginx e PostgreSQL; construir etapas como webpack são a parte com fome de memória, então construir em CI ou em seu laptop.
rsync o novo código, em seguida, reiniciar — o gap está em um segundo, porque o sistema reinicia o processo imediatamente. Para zero-downtime você executaria duas portas e alternaria Nginx upstream, mas a maioria dos projetos nunca precisa dele.
Esta pilha encaixa confortavelmente em Buran-1 em €6.5/mês.