← Blog

Hospede o Umami analytics

Railyard

19 de maio de 2026 · 9 min de leitura

Siga isso no seu próprio servidor. Comece grátis, sem cartão

Você quer saber quantas pessoas visitaram seu site hoje e de onde vieram, sem enviar cada pageview para uma empresa de anúncios e sem banner de cookies. O Umami faz exatamente isso: um painel de analytics open-source que roda como um único container contra um único banco Postgres. Este guia leva você de um servidor vazio ao Umami no seu próprio domínio via HTTPS, rastreando seu primeiro site, com um backup que você sabe restaurar e um plano para upgrades. A última parte mostra a versão de um clique no Railyard.

Este guia usa o Umami 3.4.1, a release atual, com Postgres 16. O Umami 3 só suporta Postgres (versão 12.14 ou posterior), então não há opção de MySQL aqui.

O que você vai precisar

  • Um servidor. Umami e Postgres são leves, então um servidor pequeno já basta. Um Hetzner CX23 (2 vCPUs, 4 GB de RAM, 40 GB NVMe) custa €5,99/mês sem VAT e deixa espaço para outros apps. Use Ubuntu 24.04 ou outra imagem recente baseada em Debian.
  • Um domínio ou subdomínio que você possa apontar para o servidor. Este guia usa analytics.example.com.
  • Acesso SSH como root ou um usuário com sudo.

Etapa 1: Aponte o DNS para o servidor e atualize-o

Crie o servidor, anote o IPv4 público dele, e adicione um registro A para analytics.example.com apontando para esse endereço no seu provedor de DNS. Faça isso primeiro: o Caddy só consegue obter um certificado depois que o nome resolver para o seu servidor, e o DNS pode levar alguns minutos para atualizar.

Depois entre e atualize o sistema:

ssh root@203.0.113.10
apt update && apt upgrade -y

Confira o registro na sua própria máquina:

dig +short analytics.example.com

Você deve ver o endereço IP do seu servidor. Se ainda não aparecer nada, continue e confira de novo antes da Etapa 5.

Etapa 2: Instale o Docker

Umami, Postgres e Caddy rodam todos como containers, então o Docker Engine com o plugin Compose é a única coisa para instalar. O script de conveniência do Docker configura o repositório oficial e os pacotes:

curl -fsSL https://get.docker.com | sh
systemctl enable --now docker
docker --version
docker compose version

Você deve ver uma linha de versão para o Docker e outra para o Docker Compose.

Etapa 3: Crie os segredos

Crie um diretório para a stack e gere três valores num arquivo .env ao lado dele:

mkdir -p /opt/umami/backups
cd /opt/umami
echo "DB_PASSWORD=$(openssl rand -hex 24)" >> .env
echo "APP_SECRET=$(openssl rand -hex 32)" >> .env
echo "TWO_FACTOR_ENCRYPTION_KEY=$(openssl rand -hex 32)" >> .env
chmod 600 .env

Para que serve cada um, direto da própria documentação do Umami:

  • DATABASE_URL é a única variável que o Umami exige estritamente. Você vai montar ela a partir de DB_PASSWORD no arquivo Compose.
  • APP_SECRET protege os tokens de autenticação. Toda instalação deve ter o seu próprio.
  • TWO_FACTOR_ENCRYPTION_KEY é uma string hexadecimal de 64 caracteres que criptografa os segredos de dois fatores. openssl rand -hex 32 produz exatamente isso. O próprio arquivo Compose do Umami a define, e você precisa dela se planeja ativar o login de dois fatores.

Confira o arquivo:

cat /opt/umami/.env

Você deve ver três linhas, cada uma com um valor aleatório longo.

Etapa 4: Escreva o arquivo Compose e o Caddyfile

Salve isto como /opt/umami/compose.yaml. Ele segue a estrutura do próprio docker-compose.yml do Umami, com versões fixadas em vez de latest e o Caddy na frente:

services:
  caddy:
    image: caddy:2
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy-data:/data
      - caddy-config:/config
    depends_on:
      - umami

  umami:
    image: ghcr.io/umami-software/umami:3.4.1
    restart: unless-stopped
    init: true
    environment:
      DATABASE_URL: postgresql://umami:${DB_PASSWORD}@db:5432/umami
      APP_SECRET: ${APP_SECRET}
      TWO_FACTOR_ENCRYPTION_KEY: ${TWO_FACTOR_ENCRYPTION_KEY}
    depends_on:
      db:
        condition: service_healthy
    healthcheck:
      test: ["CMD-SHELL", "curl -f http://localhost:3000/api/heartbeat"]
      interval: 5s
      timeout: 5s
      retries: 5

  db:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      POSTGRES_DB: umami
      POSTGRES_USER: umami
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - umami-db-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U umami -d umami"]
      interval: 5s
      timeout: 5s
      retries: 5

volumes:
  umami-db-data:
  caddy-data:
  caddy-config:

Algumas coisas que valem saber sobre ele:

  • Só o Caddy publica portas. O Umami escuta na 3000 e o Postgres na 5432 dentro da rede do Compose, então nenhum dos dois é acessível pela internet.
  • O Compose lê ${DB_PASSWORD} e os outros valores a partir do arquivo .env no mesmo diretório.
  • O Umami espera o Postgres reportar saudável antes de iniciar, e cria suas tabelas no primeiro boot.
  • O volume caddy-data guarda seus certificados, então um restart não solicita novos.

Agora salve isto como /opt/umami/Caddyfile, com o seu próprio domínio:

analytics.example.com {
	encode zstd gzip
	reverse_proxy umami:3000
}

O Caddy lê o domínio a partir do endereço do site, obtém um certificado Let’s Encrypt para ele, redireciona HTTP para HTTPS, e passa as requisições para o container umami. Confira os dois arquivos:

cd /opt/umami
docker compose config --quiet && echo "compose ok"
docker compose run --rm --no-deps caddy caddy validate --config /etc/caddy/Caddyfile

Você deve ver compose ok, depois Valid configuration no final da saída do Caddy.

Etapa 5: Inicie a stack

docker compose up -d
docker compose ps

Você deve ver db e umami marcados como (healthy) depois de vinte ou trinta segundos, e caddy como Up. Confira o app de dentro do próprio container:

docker compose exec umami curl -s http://localhost:3000/api/heartbeat

Você deve ver {"ok":true}. Depois observe o Caddy obter o certificado:

docker compose logs -f caddy

Você deve ver uma linha dizendo que o certificado foi obtido para analytics.example.com. Pressione Ctrl+C, e abra https://analytics.example.com no seu navegador. Você deve ver a página de login do Umami com um certificado válido.

Etapa 6: Faça login e troque a senha padrão

Toda instalação nova do Umami cria a mesma conta: usuário admin, senha umami. Faça login com ela e troque a senha imediatamente nas configurações do seu perfil. Até você fazer isso, qualquer um que encontre sua página de login pode entrar como admin, então não deixe uma instalação nova rodando de um dia para o outro com o padrão.

Depois adicione seu site. Clique em Websites no menu lateral, depois em Add website, digite um nome e o domínio do seu site, e salve. Clique em Edit no site novo e copie o código da seção Tracking code para o <head> do seu site.

Carregue seu site em outra aba. Você deve ver a visita no painel do Umami em poucos segundos. Se não ver, tente um navegador sem bloqueador de anúncios: a documentação do Umami observa que bloqueadores de anúncios podem impedir o script de rastreamento de carregar.

Etapa 7: Faça backup do banco de dados

Tudo que importa está no Postgres: sua conta, seus sites e cada pageview. Salve isto como /opt/umami/backup.sh:

#!/usr/bin/env bash
set -euo pipefail
cd /opt/umami
docker compose exec -T db pg_dump -U umami umami | gzip > "backups/umami-$(date +%F).sql.gz"
find backups -name 'umami-*.sql.gz' -mtime +14 -delete

Torne executável, rode uma vez, e agende diariamente às 03:00 com crontab -e:

chmod +x /opt/umami/backup.sh
/opt/umami/backup.sh
ls -lh /opt/umami/backups
0 3 * * * /opt/umami/backup.sh

Você deve ver um arquivo .sql.gz de alguns kilobytes numa instalação nova, crescendo conforme os dados chegam. O script mantém quatorze dias. Copie os arquivos para fora do servidor também (object storage, ou outra máquina com rsync), já que um backup no mesmo disco não sobrevive a perder o servidor.

Um backup só conta depois que você o restaurou. Para restaurar numa instalação nova, inicie só o banco de dados, carregue o dump, depois inicie o Umami:

docker compose up -d --wait db
gunzip -c backups/umami-2026-05-19.sql.gz | docker compose exec -T db psql -q -U umami umami
docker compose up -d

Carregar num banco de dados vazio antes de o Umami iniciar evita conflitos com as tabelas que o Umami cria no primeiro boot. Você deve ver o Umami logar No pending migrations to apply, e seu login e dados antigos devem estar de volta.

Etapa 8: Faça upgrade

O Umami roda suas migrações de banco de dados quando inicia, então um upgrade é uma nova tag de imagem e um restart. Leia as release notes no GitHub primeiro, faça um backup, depois mude a tag no compose.yaml (por exemplo, de 3.4.1 para a próxima release) e rode:

/opt/umami/backup.sh
docker compose pull umami
docker compose up -d umami
docker compose logs -f umami

Você deve ver as migrações aplicarem, depois o Next.js reportar que está pronto. Se algo der errado, volte para a tag antiga e restaure o backup da Etapa 7. Mantenha o Caddy e o Postgres atualizados da mesma forma: docker compose pull e docker compose up -d para o Caddy, enquanto um upgrade de versão maior do Postgres (16 para 17) precisa de um dump e restauração, não só uma nova tag.

O caminho curto: faça com o Railyard

As Etapas 2 a 5 são o que o template de Umami do Railyard faz por você: faça o deploy do Umami no Railyard. Escolha um servidor, e o Railyard constrói o Umami, cria um banco Postgres para ele, conecta os dois para que não haja nada para ligar à mão, e gera APP_SECRET. O app recebe um endereço HTTPS na hora, e você pode adicionar seu próprio domínio na aba Domains dele com os registros de DNS que ele mostra (Domains and HTTPS).

A Etapa 6 ainda se aplica: faça login com admin / umami e troque a senha imediatamente. Os backups (Etapa 7) se tornam backups agendados do Postgres com restauração de um clique, descritos em Databases and backups.

O template roda num servidor na sua própria conta de nuvem ou numa que você já tenha, então o custo fica só no preço do servidor. O plano Free do Railyard cobre um servidor mais um servidor de banco de dados e três apps, sem cartão. O Pro é US$19/mês e o Team, US$49/mês, por equipe.

Solução de problemas

O Caddy não consegue obter um certificado. Quase sempre é DNS. Rode dig +short analytics.example.com e confirme que retorna o IP do seu servidor. Confira também se as portas 80 e 443 estão abertas no firewall do seu provedor, porque o Let’s Encrypt conecta ao servidor para validá-lo. O Caddy tenta de novo por conta própria, então depois que o DNS estiver certo, observe docker compose logs -f caddy.

address already in use na porta 80 ou 443. Alguma outra coisa está escutando, geralmente um Nginx ou Apache instalado com a imagem. Encontre com ss -tlnp | grep -E ':(80|443)\s', pare e desative, depois rode docker compose up -d de novo.

O Umami fica reiniciando. Rode docker compose logs umami. A causa usual é um DATABASE_URL que não corresponde ao banco de dados. Se você mudou DB_PASSWORD depois do primeiro start, o Postgres ainda tem o antigo: a senha só é aplicada quando o volume é criado. Ou coloque o valor antigo de volta, ou mude dentro do Postgres com ALTER USER.

O painel não mostra nenhuma visita. Confira se o código de rastreamento está no <head> da página que você carregou, se o domínio na entrada do site corresponde ao seu site, e tente um navegador sem bloqueador de anúncios. A aba de rede do seu navegador deve mostrar o script.js carregando do seu domínio do Umami.

O servidor fica sem memória. Umami e Postgres são pequenos, mas num servidor compartilhado com outros apps, o out-of-memory killer do kernel pode parar um container. Confira com dmesg | grep -i "out of memory" e docker stats, depois mova algo para fora do servidor ou redimensione.

Perguntas frequentes

O Umami usa cookies? O Umami é feito para coletar analytics sem cookies, que é por isso que muitos sites o rodam sem um banner de consentimento. Se você precisa de um ainda depende das regras que se aplicam a você, então confira elas.

Uma única instalação do Umami pode rastrear vários sites? Sim. Adicione cada um em Websites e cada um recebe seu próprio código de rastreamento e painel.

Posso rodar sem Docker? Sim. A documentação do Umami descreve uma instalação a partir do código-fonte com Node.js 18.18 ou mais novo, pnpm e um banco Postgres, rodado sob um gerenciador de processos como o PM2. O Docker é mais simples de atualizar, que é por isso que este guia usa ele.

Como eu migro do Google Analytics? O Umami começa a contar a partir do momento em que o código de rastreamento está no seu site. Mantenha os dois scripts nas suas páginas por um tempo se quiser comparar números antes de remover o do Google.

O Umami é um dos apps self-hosted mais fáceis de rodar bem: um container, um banco de dados e uma configuração pequena de proxy. Independente de como você configurar, os hábitos que importam são os mesmos: troque a senha padrão no primeiro dia, e restaure um backup uma vez para saber que funciona.

Por que escolhem o Railyard para isso

  • Sua própria conta de cloud. Faça deploy no DigitalOcean, Hetzner, Vultr, AWS, OVHcloud, ou em qualquer servidor Linux via SSH, cobrado direto pelo seu provedor, sem markup.
  • Um preço fixo por equipe. O Free é grátis para sempre: um servidor mais um servidor de banco de dados, três apps, sem cartão. O Pro custa US$19 por mês para até cinco servidores e apps ilimitados. O Team custa US$49 por mês com servidores ilimitados. Sem cobrança por app, por deploy, por assento ou por gigabyte.
  • Templates de um clique. Faça deploy de apps open source, como bancos de dados, analytics e ferramentas de dev, no seu próprio servidor em um clique.
  • Bancos de dados gerenciados. Postgres, MySQL e Redis com backups programados, verificados por restauração, e recuperação point-in-time.
  • Push-to-deploy. Faça deploy a partir do GitHub, GitLab ou da CLI, com HTTPS automático e releases sem downtime.

Suba o Umami com um clique

O template do Railyard roda o Umami com Postgres conectado e APP_SECRET gerado, num servidor que é seu.

Plano grátis, sem cartão, e 14 dias de Pro para cada equipe nova. Um preço fixo por equipe.