Saltar para o conteúdo principal
50% de desconto todos os planos, tempo limitado. A partir de $2.48/mo
14 min left
Ferramentas de desenvolvimento e DevOps

Como montar uma stack de monitorização Grafana + Prometheus no seu VPS (guia Docker Compose)

C Por Chike 14 min de leitura
Prometheus and Grafana monitoring stack illustration: a central dashboard panel showing Prometheus and Grafana logos over metric graphs, with three server nodes feeding metrics into it

Se ainda não tem a certeza do que são o Prometheus e o Grafana, leia o nosso artigo sobre Prometheus vs Grafana. Se já sabe a diferença, veja aqui como executá-los em conjunto.

Este artigo é a parte prática. Instala o Prometheus, o Grafana e o Node Exporter num único VPS com Docker Compose, coloca HTTPS à frente do Grafana com o Caddy, importa o painel Node Exporter Full (ID 1860) e mostra como recolher métricas de um segundo VPS através de WireGuard.

O teste original de abril de 2026 correu em Ubuntu 24.04 LTS com Docker Engine 27.x e Docker Compose v2.30. As versões fixadas na configuração abaixo foram entretanto atualizadas para as versões atualmente suportadas. Nesse teste original com cinco hosts, o hub usava cerca de 300 MB de RAM em repouso e entre 530 e 650 MB durante a recolha contínua.

TL;DR

  • O VPS hub corre o Prometheus, o Grafana e o Node Exporter numa única stack de Compose, com o Caddy instalado no host como proxy inverso.
  • O Prometheus e o Grafana escutam apenas em 127.0.0.1. O acesso público passa pelo Caddy com HTTPS automático.
  • Adicione mais servidores instalando o Node Exporter em cada um e acrescentando entradas a prometheus.yml.
  • O WireGuard é o caminho de rede recomendado entre o hub e os nós. A rede privada funciona bem quando os seus servidores já partilham uma rede privada.
  • Um VPS de 2 GB chegou para o teste com cinco hosts abaixo, mas encare isso como referência e não como regra fixa por número de hosts.

O que vai construir

Diagram of monitoring traffic boundaries: ports 80 and 443 are public, Grafana on 3000, Prometheus on 9090 and Node Exporter on 9100 stay on loopback, and a remote Node Exporter on 10.10.0.2:9100 is reachable only over the private network

Eis, em traços gerais, o aspeto que a instalação terá quando terminar.

                 +-------------------+
                 |  Your laptop      |
                 +---------+---------+
                           | HTTPS
                           v
+--------------------------+----------------------------+
| MONITORING HUB VPS    (2 GB RAM starting point) |
|  Caddy        (reverse proxy, auto HTTPS)             |
|  Grafana      (port 3000, only via Caddy)             |
|  Prometheus   (port 9090, internal only)              |
|  Node Exporter (port 9100, scraped on localhost)      |
+----+---------------------------------+----------------+
     |                                 |
     | scrape over WireGuard           | scrape over WG
     v                                 v
+----+--------+                  +-----+-------+
|  App VPS 1  |                  |  App VPS 2  |
|  Node Expo. |                  |  Node Expo. |
+-------------+                  +-------------+

Um único VPS hub aloja toda a stack de monitorização. Cada um dos outros VPS que quiser vigiar corre apenas o Node Exporter. O Prometheus no hub recolhe as métricas de cada um, o Grafana visualiza-as e o Caddy trata do HTTPS.

O que você precisa

Para esta configuração em concreto, precisa de um VPS com Ubuntu para o hub, um domínio e acesso sudo.

  • Um VPS com pelo menos 2 GB de RAM a correr Ubuntu 24.04 LTS.
  • Um nome de domínio com um registo A a apontar para o IP público do VPS (por exemplo, grafana.example.com). É necessário para o HTTPS.
  • Acesso root ou sudo por SSH.

Ao longo deste guia, substitua grafana.example.com pelo subdomínio que realmente apontou para o seu VPS de monitorização. Use o mesmo domínio na variável de ambiente do Grafana, na verificação de DNS e no Caddyfile.

Se só quiser monitorizar um servidor e ainda não precisar de HTTPS, pode correr a stack de Compose no VPS que já tem, sem a secção do proxy inverso. O resto do guia mantém-se válido.

Implantar VPS Ubuntu

Lance um VPS Ubuntu instantaneamente com acesso root e armazenamento NVMe.

Implantar VPS Ubuntu

Passo 1: preparação do servidor

Ligue-se por SSH ao VPS hub com um utilizador com sudo. Comece por atualizar o sistema.

sudo apt update && sudo apt upgrade -y

Instale o Docker Engine e o plugin do Compose a partir do repositório oficial do Docker.

# Install prerequisites
sudo apt install -y ca-certificates curl gnupg lsb-release

# Add Docker's official GPG key
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
  sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

# Add the Docker repository
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
  https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Verifique se ambos estão instalados.

docker --version
docker compose version

Ambos os comandos devem devolver uma versão sem erros. As versões exatas do Docker Engine e do Compose dependem do que o repositório oficial disponibiliza quando os instalar.

sudo usermod -aG docker $USER

Termine a sessão e volte a entrar antes de continuar, para que a nova pertença ao grupo tenha efeito. O grupo docker concede na prática privilégios de root, por isso adicione apenas administradores de confiança.

Configure o UFW para permitir SSH, HTTP e HTTPS no hub de monitorização. A porta 80 trata do redirecionamento de HTTP para HTTPS e da validação ACME. O Grafana em si continua atrás do Caddy.

sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status

Não abra as portas 3000, 9090 ou 9100 à internet pública. Os serviços de monitorização escutam em 127.0.0.1 por uma razão.

Passo 2: a stack de Compose

Crie um diretório para a stack e a configuração do Prometheus.

mkdir -p ~/monitoring/prometheus
cd ~/monitoring

Escreva o ficheiro de Compose.

# ~/monitoring/docker-compose.yml
services:
  prometheus:
    image: prom/prometheus:v3.13.2
    container_name: prometheus
    restart: unless-stopped
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--storage.tsdb.retention.time=15d'
      - '--web.enable-lifecycle'
      - '--web.listen-address=127.0.0.1:9090'
    volumes:
      - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - prometheus_data:/prometheus
    network_mode: host
  node-exporter:
    image: prom/node-exporter:v1.12.1
    container_name: node-exporter
    restart: unless-stopped
    pid: host
    network_mode: host
    command:
      - '--path.rootfs=/host'
      - '--web.listen-address=127.0.0.1:9100'
      - '--collector.filesystem.mount-points-exclude=^/(dev|proc|sys|var/lib/docker/.+|var/lib/kubelet/.+)($$|/)'
    volumes:
      - '/:/host:ro,rslave'
  grafana:
    image: grafana/grafana:13.1.3
    container_name: grafana
    restart: unless-stopped
    environment:
      - GF_SECURITY_ADMIN_USER=admin
      - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD}
      - GF_USERS_ALLOW_SIGN_UP=false
      - GF_SERVER_ROOT_URL=https://grafana.example.com
      - GF_SERVER_HTTP_ADDR=127.0.0.1
    volumes:
      - grafana_data:/var/lib/grafana
    network_mode: host
    depends_on:
      - prometheus
volumes:
  prometheus_data:
  grafana_data:

Agora escreva a configuração do Prometheus.

# ~/monitoring/prometheus/prometheus.yml
global:
  scrape_interval: 15s
  evaluation_interval: 15s
  external_labels:
    monitor: 'monitoring-hub'
scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['127.0.0.1:9090']
  - job_name: 'node'
    static_configs:
      - targets: ['127.0.0.1:9100']
        labels:
          host: 'monitoring-hub'

Crie um ficheiro .env com a palavra-passe de administrador do Grafana. Use uma palavra-passe forte e não faça commit deste ficheiro no git.

cat > ~/monitoring/.env <<'EOF'
GRAFANA_ADMIN_PASSWORD='replace-with-a-strong-password'
EOF
chmod 600 ~/monitoring/.env

Algumas das opções acima merecem uma frase de explicação.

  • --web.listen-address=127.0.0.1:9090 faz o Prometheus escutar apenas na interface de loopback do host. Assim a porta 9090 fica fora da rede pública, mas continua acessível ao Grafana e à administração local.
  • --web.enable-lifecycle ativa POST /-/reload, para que possa aplicar alterações à configuração do Prometheus sem reiniciar o contentor.
  • pid: host, network_mode: host, o bind mount da raiz do host e --path.rootfs=/host dão ao Node Exporter em contentor o contexto do host de que precisa, em vez de monitorizar apenas o seu próprio ambiente de contentor.
  • GF_USERS_ALLOW_SIGN_UP=false impede que os visitantes criem as suas próprias contas no Grafana. Isso não torna o Grafana privado: a página de início de sessão continua acessível publicamente através do Caddy.

Dica profissional: Se preferir saltar a instalação manual, a Cloudzy tem implementações com um clique de Grafana e Prometheus . A implementação do Prometheus também pode instalar o Node Exporter.

Passo 3: primeiro arranque e verificação

Arranque a stack.

cd ~/monitoring
docker compose up -d

Espere alguns segundos e verifique se os três contentores estão a correr.

docker compose ps

Os três serviços devem aparecer em estado running.

Abra um túnel SSH a partir do seu portátil para verificar a página de targets do Prometheus.

ssh -L 9090:localhost:9090 your-user@your-vps-ip

Depois abra http://localhost:9090/targets no navegador. Deverá ver dois targets, ambos em estado UP:

prometheus            UP    http://127.0.0.1:9090/metrics
node                  UP    http://127.0.0.1:9100/metrics

Se algum estiver DOWN, avance para a secção Problemas comuns. Não continue enquanto ambos não estiverem UP.

Feche o túnel quando acabar de verificar os targets. De fora do VPS, o Prometheus continuará acessível apenas por este túnel SSH. O passo seguinte expõe o Grafana através de HTTPS.

Passo 4: proxy inverso com HTTPS usando o Caddy

O Caddy é um único binário e trata do HTTPS automaticamente. Para um proxy inverso de um só site, a configuração é mais curta do que o bloco equivalente do Nginx.

Instale o Caddy a partir do repositório oficial.

sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | \
  sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | \
  sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo chmod o+r /usr/share/keyrings/caddy-stable-archive-keyring.gpg
sudo chmod o+r /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install -y caddy

Antes do passo seguinte, confirme que o registo DNS A de grafana.example.com aponta para o IP público do VPS. Sem isso, a validação ACME falha.

dig +short grafana.example.com
# Should print the VPS public IP

Edite o Caddyfile.

# /etc/caddy/Caddyfile
grafana.example.com {
    reverse_proxy 127.0.0.1:3000
    encode gzip
}

Recarregue o Caddy.

sudo systemctl reload caddy

O Caddy obtém e renova automaticamente certificados TLS publicamente fiáveis através de ACME, assim que o domínio aponte para o seu servidor e as portas 80 e 443 estejam acessíveis. Abra https://grafana.example.com no navegador: deverá ver a página de início de sessão do Grafana numa ligação HTTPS válida. Entre com admin e a palavra-passe do seu ficheiro .env.

Passo 5: adicionar o Prometheus como fonte de dados e importar o painel 1860

Na interface do Grafana, vá a Conexões > Fontes de dados > Adicionar fonte de dados e escolha Prometheus.

Defina o URL para:

http://127.0.0.1:9090

Nesta configuração, o Grafana e o Prometheus partilham a rede do host, enquanto o Prometheus escuta apenas em loopback. Clique em Save & test e confirme que o Grafana consegue consultar a API do Prometheus. Deverá ver "Successfully queried the Prometheus API".

Agora importe o painel. O Node Exporter Full (ID 1860, de rfmoz) é um painel comunitário muito usado para as métricas do Node Exporter. Cobre CPU, memória, E/S de disco, rede, descritores de ficheiros e temperaturas do hardware quando o host as expõe. Tem também variáveis para job e instance, por isso funciona em hub-and-spoke sem qualquer alteração.

Ir para Painéis > Novo > Importar painel, introduza o ID de painel 1860, selecione a sua fonte de dados Prometheus e importe-o.

O painel deverá preencher-se assim que o seu target do Node Exporter estiver UP. O painel 1860 usa também métricas dos coletores opcionais systemd e processes em alguns gráficos, por isso um gráfico vazio não significa necessariamente que o target esteja avariado.

Passo 6: adicionar um segundo VPS (hub-and-spoke)

Antes de arrancar o Node Exporter, certifique-se de que o IP privado ao qual pretende ligá-lo já existe no segundo VPS. Se estiver a usar WireGuard, conclua primeiro a sua configuração.

No segundo VPS, instale o Docker seguindo a parte de instalação do Docker do passo 1, mas não abra as portas 80 ou 443 só por causa da monitorização. Depois execute apenas o Node Exporter.

mkdir -p ~/node-exporter
cd ~/node-exporter

cat > docker-compose.yml <<'EOF'
services:
  node-exporter:
    image: prom/node-exporter:v1.12.1
    container_name: node-exporter
    restart: unless-stopped
    pid: host
    command:
      - '--path.rootfs=/host'
      - '--web.listen-address=10.10.0.2:9100'  # bind to the private monitoring IP, never 0.0.0.0
    volumes:
      - '/:/host:ro,rslave'
    network_mode: host
EOF

docker compose up -d

Substitua 10.10.0.2 pelo IP privado de monitorização deste servidor. Se usar WireGuard, use o respetivo IP de WireGuard; se usar a rede privada da Cloudzy, use o IP da interface privada do VPS. Se o UFW já estiver ativo neste VPS, permita que apenas o hub de monitorização alcance o Node Exporter. Por exemplo, se o IP privado do hub for 10.10.0.1:

sudo ufw allow proto tcp from 10.10.0.1 to any port 9100
sudo ufw status

Substitua 10.10.0.1 pelo IP privado real do hub. Se o UFW estiver inativo, a opção explícita --web.listen-address continua a manter o Node Exporter fora da interface pública, mas outras máquinas com acesso a essa rede privada também podem alcançar a porta 9100.

Duas boas opções para o caminho de rede entre o hub e os nós:

  1. Rede WireGuard. Cada VPS junta-se a uma rede WireGuard e o Prometheus recolhe métricas de IPs privados. É a opção mais segura depois da configuração inicial do WireGuard. Oferecemos WireGuard como implementação com um clique e temos também um tutorial de configuração já existente sobre ele.
  2. Rede privada da Cloudzy. As instâncias VPS da Cloudzy na mesma região recebem uma interface privada para tráfego este-oeste, por isso pode recolher métricas desse endereço em vez de montar um túnel WireGuard à parte.

Assim que o Node Exporter estiver a correr no segundo VPS e acessível no seu IP privado, substitua o job node existente em prometheus.yml no hub pelo bloco abaixo.

# Update the existing 'node' job in ~/monitoring/prometheus/prometheus.yml
  - job_name: 'node'
    static_configs:
      - targets: ['127.0.0.1:9100']
        labels:
          host: 'monitoring-hub'
      - targets: ['10.10.0.2:9100']
        labels:
          host: 'app-vps-1'
          tier: 'production'

Recarregue o Prometheus sem reiniciar o contentor.

curl -X POST http://localhost:9090/-/reload

Volte a abrir o túnel SSH do passo 3 e aceda a http://localhost:9090/targets. O novo target deverá aparecer como UP. Abra o painel Node Exporter Full, mude a variável instance no topo para o novo servidor e verá os respetivos gráficos.

Consumo de recursos e quando fazer upgrade

Observed five-host baseline from the April 2026 test: Prometheus 250 to 350 MB, Grafana 200 MB, Caddy 40 MB, hub Node Exporter 15 to 20 MB, total hub 530 to 650 MB RAM on a 2 GB VPS with a 1.5 GB fifteen-day working set

Estes números vêm do teste original de abril de 2026, num VPS Ubuntu de 2 GB com cinco hosts monitorizados. Encare-os como referência para esta carga de trabalho e não como garantia de dimensionamento para versões mais recentes.

ComponenteRAM em repousoRAM em atividade (1 host)RAM com 5 hostsDisco (retenção de 15 d, 5 hosts)
Prometheus~100 MB~150 MB~250-350 MB~500 MB a 1,5 GB
Grafana~150 MB~180 MB~200 MB~50 MB
Node Exporter~15 MB~20 MBnão aplicávelinsignificante
Caddy~30 MB~40 MB~40 MBnão aplicável
Total do hub~300 MB~390 MB~530-650 MB~1,5 GB de conjunto de trabalho

Faça upgrade quando o hub começar a ficar sem memória ou sem folga de disco. O número de hosts, por si só, é um mau critério de dimensionamento, porque a cardinalidade das séries, os coletores ativados, o intervalo de recolha e a retenção alteram todos o consumo. Para armazenamento centralizado a longo prazo, o Prometheus suporta integrações de armazenamento remoto. O VictoriaMetrics é uma das opções compatíveis com o Prometheus.

Problemas comuns

Os sete problemas que surgem com mais frequência, com as respetivas soluções.

  1. O Prometheus está acessível a partir da internet pública. Um simples mapeamento de porta 9090:9090 expõe o Prometheus ao mundo inteiro. Solução: mantenha --web.listen-address=127.0.0.1:9090 no comando do Prometheus, como mostrado acima. Assim o Prometheus escuta apenas na interface de loopback do host.
  2. A fonte de dados do Grafana não consegue chegar ao Prometheus. Esta stack usa a rede do host, por isso o Grafana chega ao Prometheus em http://127.0.0.1:9090. Verifique se o Prometheus está a correr e continua a escutar em loopback.
  3. O painel do Node Exporter mostra "No data". Três causas habituais. (a) O Prometheus não está a recolher o target. Verifique /targets. (b) A etiqueta job na variável do painel não corresponde ao job_name na configuração de scrape. (c) Uma firewall bloqueia a porta 9100 entre o hub e o target.
  4. A palavra-passe de administrador do Grafana continua admin/admin em produção. Definir GF_SECURITY_ADMIN_PASSWORD a partir de um ficheiro .env antes do primeiro arranque. Se se esqueceu, mude-a no primeiro início de sessão e desative o registo.
  5. O Caddy dá "ACME challenge failed". O registo DNS A ainda não propagou, ou a porta 80 está bloqueada. Execute ufw allow 80,443/tcp, espere pelo DNS e execute sudo systemctl reload caddy. Use dig +short para confirmar a propagação.
  6. O disco do Prometheus enche. Etiquetas de cardinalidade elevada ou intervalos de recolha curtos com muitos hosts podem encher o volume depressa. Vigie prometheus_tsdb_head_series e o tamanho do volume. Mitigações: desative os coletores do Node Exporter que não usa, aumente o scrape_interval para 30s ou reduza a retenção.
  7. Erros de permissões nos bind mounts. Se montar um diretório do host em vez de um volume nomeado, o UID do contentor (65534 para o Prometheus, 472 para o Grafana) precisa de permissão de escrita. Os volumes nomeados, como no ficheiro de Compose acima, evitam isto.

Quando esta stack é exagero

Se tudo o que quer é um alerta quando um URL deixa de responder, esta stack é exagero. Uptime Kuma é uma opção bem mais leve se só precisar de verificações básicas de disponibilidade.

Perguntas frequentes

Qual é a diferença entre o Prometheus e o Grafana?

O Prometheus é uma base de dados de séries temporais: recolhe métricas dos targets configurados no intervalo que definir, guarda-as em disco e responde a consultas PromQL. O Grafana é uma camada de visualização que se liga ao Prometheus (e a muitas outras fontes de dados) e desenha painéis. Quase sempre vai querer os dois: o Prometheus para recolher e guardar, o Grafana para mostrar.

De quanta RAM precisa uma instalação de Prometheus + Grafana?

Um hub de monitorização a correr o Prometheus, o Grafana, o Node Exporter e um proxy inverso num único VPS usa cerca de 300 MB de RAM em repouso e entre 530 e 650 MB quando recolhe ativamente de cinco hosts a cada 15 segundos.

Posso monitorizar vários servidores com uma só instância do Grafana?

Sim. O padrão habitual é hub-and-spoke. Uma única instância do Prometheus num VPS hub recolhe do Node Exporter que corre em cada um dos outros servidores que quer vigiar. O Grafana no hub consulta apenas esse Prometheus. O painel Node Exporter Full (ID 1860) suporta uma variável instance, por isso alterna entre servidores a partir de um só painel.

Qual é o melhor painel do Grafana para o Node Exporter?

Para esta configuração, o Node Exporter Full (painel com o ID 1860, de rfmoz) é uma excelente escolha por omissão. Cobre as principais métricas de host do Node Exporter e suporta as variáveis job e instance para monitorizar vários servidores. Alguns gráficos dependem de coletores opcionais do Node Exporter, por isso um gráfico vazio não significa necessariamente que o target de recolha esteja avariado.

Como exponho o Grafana através de HTTPS?

Execute o Grafana ligado a 127.0.0.1:3000 e coloque à frente um proxy inverso que trate do HTTPS. O Caddy é a opção mais simples: um Caddyfile de quatro linhas com reverse_proxy 127.0.0.1:3000 e um bloco de domínio trata de tudo, incluindo a gestão automática dos certificados TLS.

O Prometheus + Grafana são gratuitos para uso comercial?

O Prometheus é licenciado sob a Apache 2.0. O Grafana OSS está sob AGPLv3. O uso interno e comercial do Grafana OSS não modificado é permitido, mas modificá-lo ou distribuí-lo, ou disponibilizar uma versão modificada através de uma rede, pode criar obrigações de partilha do código-fonte ao abrigo da AGPL. O Grafana Enterprise e o Grafana Cloud têm termos comerciais próprios.

Quando devo mudar do Prometheus para o VictoriaMetrics?

Considere o VictoriaMetrics quando uma retenção mais longa, uma cardinalidade de séries elevada ou várias instâncias do Prometheus tornarem mais difícil operar a TSDB local do Prometheus dentro do orçamento de memória e disco do seu servidor. O VictoriaMetrics consegue receber dados do Prometheus e expor uma API de consulta compatível, por isso pode servir de armazenamento de longo prazo ou de backend de métricas para o Grafana. Teste-o com a sua própria carga de trabalho em vez de mudar a partir de um limiar fixo de RAM.

Partilhar

Mais do blogue

Continue a ler.

Pronto para implantar? A partir de $2,48/mês.

Cloud independente, desde 2008. AMD EPYC, NVMe, 40 Gbps. Reembolso em 14 dias.