Go Uptime: monitoramento self-hosted derivado do Gatus

Mascote LinuxPro apontando uma falha no painel de status do Go Uptime num NOC, com o cachorro caramelo cyborg sentado ao lado

O Gatus é ótimo para monitoramento como código, mas deixa de fora duas coisas que muita equipe pede: cadastrar um monitor pela web sem editar o YAML, e publicar uma página de status aberta enquanto o painel continua protegido. O Go Uptime nasceu para cobrir essas lacunas. É um projeto derivado do Gatus, em um único binário Go, que mantém a configuração em YAML e acrescenta administração web, páginas de status públicas, push compatível com o Uptime Kuma, MySQL/MariaDB, tela de login e backup. Neste guia, você vai ver o que muda em relação ao Gatus, subir o Go Uptime com Docker ou systemd e configurar cada recurso novo.

De onde vem o Go Uptime

O Go Uptime começou em 2026 como fork do Gatus, de TwiN, a partir de um commit de 8 de setembro de 2026. Desde a v6.0.0 ele segue caminho próprio: o servidor HTTP e a linha de comando foram reescritos. Até a v6.3.0 o projeto era publicado como jniltinho/gatus. Na v7.0.0, lançada em 21 de setembro de 2026, ganhou o nome atual e a imagem jniltinho/go-uptime.

A licença continua a mesma do original, Apache 2.0. O arquivo NOTICE registra a origem e a modificação dos arquivos herdados. Na prática, o que importa para quem já usa Gatus: um arquivo de configuração do Gatus funciona sem alteração. As condições, os endpoints, os grupos e os provedores de alerta são os mesmos; os recursos novos entram como blocos opcionais.

Dashboard do Go Uptime no tema escuro, com barras das últimas checagens e tempo médio de resposta por endpoint

O que o Go Uptime tem além do Gatus

Tudo o que o Gatus faz continua lá: checagens HTTP, ICMP, TCP, DNS e outras, condições sobre status, tempo de resposta, corpo e certificado, janelas de manutenção, suítes e mais de 40 provedores de alerta. Por cima disso, o projeto acrescenta:

  • Administração pela web em /admin: criar, editar, desativar e remover endpoints sem reiniciar o serviço. No Gatus, endpoints só existem no arquivo de configuração (TwiN/gatus#1345).
  • Páginas de status públicas em /status/<slug>, abertas sem login, com o painel protegido. No Gatus, esse pedido foi fechado como not planned (TwiN/gatus#1311).
  • Push compatível com o Uptime Kuma: scripts e cron jobs reportam o próprio estado em /api/push/<token>, com as mesmas URLs e respostas do Kuma.
  • MySQL e MariaDB como armazenamento, além de SQLite e PostgreSQL. No Gatus, MySQL não é suportado.
  • Tela de login com logout e sessões no banco, em vez da janela de autenticação do navegador; curl -u continua funcionando.
  • Backup e restauração do que foi cadastrado pela web, opcionalmente cifrado.
  • Gráfico de tempo de resposta por endpoint, nos períodos Recent, 3h, 6h, 24h e 1w, com média, mínimo e máximo.
  • Linha de comando: config validate, password hash, version e healthcheck.
  • Três temas (escuro, claro e bio) e a fonte Inter servida pelo próprio binário, sem chamar serviços externos.

Se você quer uma interface para tudo e não se importa com Node.js, o Uptime Kuma continua sendo uma boa escolha. O Go Uptime fica no meio do caminho: YAML versionado no Git para o que é estável, web para o que muda toda semana.

Suba com Docker em um minuto

A imagem fica no Docker Hub, para amd64 e arm64. Não existe tag latest, de propósito: fixe a versão que você executa. Para uma primeira olhada, sem histórico persistente:

mkdir -p go-uptime/config && cd go-uptime
curl -sL -o config/config.yaml \
  https://raw.githubusercontent.com/jniltinho/go-uptime/main/config.yaml
docker run -d --name go-uptime -p 127.0.0.1:8080:8080 \
  -v "$PWD/config:/config" jniltinho/go-uptime:v7.0.0

Abra http://127.0.0.1:8080. O arquivo de exemplo já traz endpoints e as páginas /status/services e /status/infrastructure. Em poucos segundos, docker ps mostra o contêiner como healthy: a imagem não tem shell, e o HEALTHCHECK usa o próprio subcomando go-uptime healthcheck.

Produção com Docker Compose, SQLite e login

Para manter o histórico e ligar a administração, são necessários três blocos: um armazenamento SQL, um login e admin.enabled. Comece gerando o hash da senha do administrador:

printf 'troque-esta-senha' | docker run --rm -i jniltinho/go-uptime:v7.0.0 password hash

O comando imprime o hash bcrypt em base64 esperado em password-bcrypt-base64. Rodado num terminal sem o printf, ele pede a senha duas vezes sem ecoar. Crie então config/config.yaml:

storage:
  type: sqlite
  path: /data/data.db

security:
  basic:
    username: admin
    password-bcrypt-base64: "COLE-AQUI-O-HASH"

admin:
  enabled: true

endpoints:
  - name: linuxpro
    group: sites
    url: "https://www.linuxpro.com.br"
    interval: 1m
    conditions:
      - "[STATUS] == 200"
      - "[RESPONSE_TIME] < 1000"
      - "[CERTIFICATE_EXPIRATION] > 168h"

  - name: dns-google
    group: infra
    url: "8.8.8.8"
    interval: 1m
    dns:
      query-name: "linuxpro.com.br"
      query-type: "A"
    conditions:
      - "[DNS_RCODE] == NOERROR"

E o compose.yaml, com a porta publicada só em 127.0.0.1 para ficar atrás de um proxy reverso:

services:
  go-uptime:
    image: jniltinho/go-uptime:v7.0.0
    restart: unless-stopped
    ports:
      - "127.0.0.1:8080:8080"
    volumes:
      - ./config:/config:ro
      - go-uptime-data:/data

volumes:
  go-uptime-data:

Antes de subir, valide a configuração. O config validate carrega o arquivo exatamente como o servidor faria, mas não abre banco nem faz requisições, e sai com código 1 se algo estiver errado. É o comando certo para colocar num pipeline antes do deploy:

docker run --rm -v "$PWD/config:/config:ro" jniltinho/go-uptime:v7.0.0 config validate &&
docker compose up -d
curl -s http://127.0.0.1:8080/health

A saída esperada é algo como:

The configuration is valid: 2 endpoints, 0 external endpoints, 0 suites
{"status":"UP"}

Com security.basic ativo, o painel e a API passam a exigir login. /login abre uma tela própria, a sessão fica no banco (só o hash SHA-256 do token é gravado) e o cookie é HttpOnly e SameSite=Strict. Scripts continuam usando curl -u admin:senha. Mudanças no arquivo não exigem restart: o Go Uptime recarrega a configuração sozinho em até 30 segundos.

Os exemplos do repositório sobem com a administração ligada, usuário admin e senha go-uptime. Essa senha é pública: os exemplos publicam a porta apenas em 127.0.0.1, e você deve trocá-la antes de colocar um proxy na frente.

Administração pela web

Com o login configurado, /admin lista os endpoints do YAML (somente leitura, marcados como YAML) e os cadastrados pela web (marcados como Web, com editar, pausar e remover). Os endpoints da web ficam na tabela managed_endpoints do banco e entram em vigor sem reinício. O formulário tem modo visual e modo YAML, com botão de teste antes de salvar para endpoints ativos.

Tela de administração de endpoints do Go Uptime, com endpoints vindos do YAML e cadastrados pela web

As abas Status pages, Push keys e Backup ficam na mesma tela. O backup baixa um JSON com endpoints, páginas de status e chaves de push. Esse arquivo inclui tokens, senhas e cabeçalhos; por isso existe a opção de cifrar com senha (AES-256-GCM). Na restauração, a tela mostra uma prévia do que vai mudar antes de aplicar.

Para cadastrar muitos hosts de uma vez, o repositório traz o script docs/manager-go-uptime.py, que usa a API da administração para importar um CSV, renomear grupos, listar endpoints e exportar tokens de push.

Páginas de status públicas

Uma página de status mostra só os grupos e endpoints escolhidos, sem login, enquanto o dashboard, a administração e a API continuam protegidos. Cada endpoint aparece com o estado atual, as barras das últimas checagens e o uptime de 24 horas, 7 dias e 30 dias. Clicar no nome abre uma página de detalhes com o gráfico de tempo de resposta.

status-pages:
  pages:
    - slug: publica
      title: "Status LinuxPro"
      description: "Disponibilidade dos serviços"
      groups: [sites]
      featured: [sites_linuxpro]
      show-certificate-expiration: true

A chave de um endpoint é <grupo>_<nome>, a mesma usada nos badges. featured destaca até 10 endpoints no topo, e show-certificate-expiration exibe quantos dias faltam para o certificado TLS vencer. Outras opções úteis: groups-collapsed para páginas com centenas de serviços e auth para exigir usuário e senha só naquela página. As páginas também podem ser criadas pela aba Status pages da administração.

Página de status pública do Go Uptime no tema claro, com grupos de serviços e uptime

Um detalhe de segurança que a documentação deixa explícito: o limite maximum-endpoints-per-page (400 por padrão) é regra de acesso, não só de exibição. Um endpoint que fica além do corte responde 404 em detalhes, gráfico e badges. Aumentar o limite, portanto, publica mais endpoints.

Detalhes de um endpoint no Go Uptime com o gráfico de tempo de resposta

Push: backups e cron jobs que avisam quando rodam

Nem tudo pode ser checado de fora. Um backup noturno, um job de cron ou um serviço atrás de firewall precisam avisar que rodaram. No Go Uptime, isso é um endpoint Push: ele não checa nada, apenas registra os avisos, e marca falha quando o intervalo de heartbeat passa sem nenhum push.

external-endpoints:
  - name: backup-noturno
    group: jobs
    token: "troque-por-um-token-longo-e-aleatorio"
    heartbeat:
      interval: 25h

No fim do script de backup, uma linha basta:

curl -fsS "https://status.exemplo.com/api/push/troque-por-um-token-longo-e-aleatorio?status=up&msg=backup%20ok&ping=" >/dev/null

A resposta é {"ok":true}; token desconhecido devolve 404 com {"ok":false,"msg":"Monitor not found or not active."}. O parâmetro status aceita up, pending (resultado amarelo, extensão do Go Uptime) ou qualquer outro valor como falha; msg aparece no painel e no alerta; ping é o tempo em milissegundos.

O formato é o mesmo dos monitores Push do Uptime Kuma: um script que já faz push para o Kuma funciona trocando só o endereço do servidor. Além do token por endpoint, a aba Push keys cria chaves globais (/api/push/<chave>/<grupo_nome>), guardadas como hash SHA-256 e revogáveis na hora. Endpoints ativos (HTTP, TCP etc.) também podem aceitar push, com push.enabled: true, útil para receber alertas de um sistema externo.

Aba de chaves de push da administração do Go Uptime

Alertas

Os provedores de alerta são os do Gatus: Slack, Telegram, Discord, Teams, Mattermost, PagerDuty, e-mail, webhooks personalizados e dezenas de outros. Um exemplo com Telegram, avisando também quando o serviço volta:

alerting:
  telegram:
    token: "TOKEN-DO-BOT"
    id: "ID-DO-CHAT"

endpoints:
  - name: linuxpro
    group: sites
    url: "https://www.linuxpro.com.br"
    interval: 1m
    conditions:
      - "[STATUS] == 200"
    alerts:
      - type: telegram
        send-on-resolved: true

O mesmo bloco alerts vale para endpoints Push: um backup que não reportou dentro do heartbeat dispara o alerta como qualquer outra falha.

MySQL, MariaDB ou PostgreSQL

SQLite atende bem uma instância única. Quando o banco precisa ficar separado, o Go Uptime aceita postgres e mysql, este último compatível com MySQL 8.4+ e MariaDB 10.11+. O storage.path passa a ser o DSN:

storage:
  type: mysql
  path: "go_uptime:${MARIADB_PASSWORD}@tcp(mariadb:3306)/go_uptime"

O repositório tem um exemplo completo em .examples/docker-compose-mariadb-storage, e a documentação de armazenamento em MySQL detalha usuário e permissões. O DSN segue o formato do driver go-sql-driver/mysql; parâmetros como parseTime e loc são forçados pelo próprio Go Uptime, e opções como tls=true ou timeout=5s podem ser acrescentadas.

Sem Docker: binário único com systemd

O Go Uptime é um binário estático, sem runtime nem bibliotecas. A instalação em Linux coloca tudo em /opt/go-uptime, com um usuário próprio:

VERSION=7.0.0
ARCH=amd64        # ou arm64

sudo useradd --system --home-dir /opt/go-uptime --shell /usr/sbin/nologin go-uptime
sudo install -d -o root -g go-uptime -m 0750 /opt/go-uptime /opt/go-uptime/config
sudo install -d -o go-uptime -g go-uptime -m 0750 /opt/go-uptime/data

curl -fsSL -o /tmp/go-uptime.tar.gz \
  "https://github.com/jniltinho/go-uptime/releases/download/v${VERSION}/go-uptime_${VERSION}_linux_${ARCH}.tar.gz"
sudo tar xzf /tmp/go-uptime.tar.gz -C /opt/go-uptime go-uptime
sudo chown root:go-uptime /opt/go-uptime/go-uptime && sudo chmod 0750 /opt/go-uptime/go-uptime
sudo -u go-uptime /opt/go-uptime/go-uptime version

Binário e configuração pertencem ao root e são apenas legíveis pelo grupo go-uptime: o serviço não consegue reescrever o próprio executável nem o arquivo que guarda o hash da senha. Crie /opt/go-uptime/config/config.yaml com web.address: 127.0.0.1, web.port: 8080 e storage.path: /opt/go-uptime/data/data.db, valide com config validate e instale a unit publicada no repositório:

sudo curl -fsSL -o /etc/systemd/system/go-uptime.service \
  https://raw.githubusercontent.com/jniltinho/go-uptime/v7.0.0/docs/systemd/go-uptime.service
sudo systemctl daemon-reload
sudo systemctl enable --now go-uptime
curl -s http://127.0.0.1:8080/health
journalctl -u go-uptime -f

A unit vem endurecida: roda sem root, com ProtectSystem=strict e escrita liberada só em /opt/go-uptime/data, e valida a configuração no ExecStartPre, o que impede um restart com YAML inválido de derrubar o processo que estava funcionando. A única capability é CAP_NET_RAW, necessária para endpoints ICMP; se você não monitora por ping, pode removê-la. Os logs vão para o journal, e o nível fica em GO_UPTIME_LOG_LEVEL. Para entender melhor esse modelo de serviço, veja nosso guia de comandos essenciais do systemd.

Atrás do Nginx

O painel usa um fluxo de eventos em tempo real para atualizar as telas. Essa rota não pode ser bufferizada pelo proxy, e a conexão fica aberta por minutos:

server {
    listen 443 ssl;
    server_name status.exemplo.com;
    # ssl_certificate ...;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    location ~ ^/api/v1/(endpoints|status-pages)/.*/events$ {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_buffering off;
        proxy_read_timeout 7m;
    }
}

Host e X-Forwarded-Proto não são enfeite: a administração usa esses cabeçalhos para aceitar alterações vindas do próprio endereço e para marcar o cookie de sessão como Secure.

Migrando do Gatus

Vindo do Gatus original, o caminho é trocar a imagem e reaproveitar o config.yaml: ele é aceito como está, e os recursos novos são opcionais. Faça backup do banco antes e teste numa cópia.

Vindo da série jniltinho/gatus v6, o guia de migração é ainda mais curto: no Docker, só o nome da imagem muda. O banco não precisa de migração, as variáveis GATUS_* continuam aceitas como apelidos das novas GO_UPTIME_*, e um backup feito na v6 restaura na v7. O que muda, se você depender disso:

  • métricas do Prometheus passam de gatus_ para go_uptime_; metrics-namespace: gatus mantém os nomes antigos;
  • o User-Agent das checagens passa a ser go-uptime/1.0, o que importa se um firewall ou WAF libera por esse cabeçalho;
  • o binário se chama go-uptime, mas a imagem mantém /gatus como link simbólico durante a série 7.x.

Para monitorar o servidor por dentro (CPU, memória, disco), o Go Uptime não substitui métricas: combine com Prometheus e Node Exporter, que também pode coletar as métricas go_uptime_* que o Go Uptime expõe em /metrics quando metrics: true está na configuração.

Vale a pena?

Se o seu time já gosta do Gatus e só sentia falta de uma página de status pública, de cadastrar um monitor sem abrir o servidor ou de acompanhar backups por push, o Go Uptime entrega isso sem trocar de ferramenta nem de configuração. O projeto é novo, com releases frequentes: fixe a tag, rode config validate antes de cada deploy e acompanhe as releases antes de atualizar. Código, documentação e exemplos estão no repositório no GitHub.