> For the complete documentation index, see [llms.txt](https://docs.ipcheck.ing/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ipcheck.ing/developer/pt-br/reference/faq.md).

# Perguntas Frequentes

Respostas para os problemas mais comuns de implantação e configuração.

Cada resposta abaixo descreve o comportamento real no código, não suposições. Se algo aqui não corresponder à sua instância, provavelmente você está em uma versão diferente.

## Implantação

<details>

<summary>Toda chamada de API retorna 403 "Access denied" ou "O que você está fazendo?"</summary>

A validação global de referer rejeitou a solicitação. Duas mensagens distintas:

* `{"error":"O que você está fazendo?"}` — a solicitação continha **nenhum** `Referer` cabeçalho.
* `{"error":"Acesso negado"}` — um `Referer` foi enviado, mas seu hostname não é permitido.

Os hostnames permitidos são `localhost` além de tudo em `ALLOWED_DOMAINS`. Defina-o para o(s) hostname(s) de onde seus usuários realmente carregam o site:

{% code title=".env" %}

```bash
ALLOWED_DOMAINS="myip.example.com,www.myip.example.com"
```

{% endcode %}

Então reinicie o backend. Três coisas costumam confundir as pessoas:

1. **A correspondência é exata.** `example.com` não cobre `sub.example.com`. Liste cada hostname.
2. **O acesso por IP bruto conta como um hostname.** Acessar `http://192.168.1.10:18966` envia esse IP como o hostname do referer — adicione-o, ou use um hostname.
3. **Porta e esquema são irrelevantes**, apenas o hostname é comparado.

Veja [Opções de Segurança](/developer/pt-br/configuration/security-options.md).

</details>

<details>

<summary>Minha variável VITE_* não tem efeito após reiniciar o container</summary>

`VITE_*` as variáveis são lidas pelo Vite durante `pnpm run build` e **incorporadas ao bundle JavaScript**. Elas não são lidas em tempo de execução. Reiniciar o servidor não pode alterar um valor que já esteja compilado em `dist/`.

A imagem oficial `jason5ng32/myip:latest` foi construída sem seus valores — `.env` está em `.dockerignore`, então nenhum `.env` estava presente durante essa build também. Passar `-e VITE_CURL_IPV4_DOMAIN=...` para a imagem pré-construída não faz nada no frontend. Para usar variáveis em tempo de build no Docker, você precisa construir sua própria imagem. Em uma implantação com Node, execute novamente `pnpm run build`.

Duas `VITE_*` variáveis também são lidas em tempo de execução e *não* respondem a `-e`: `VITE_SENTRY_DSN_FRONTEND` (que monta `/api/monitoring`) e `VITE_SITE_URL` (que constrói o upstream `User-Agent`). Detalhamento completo em [Variáveis de Ambiente](/developer/pt-br/reference/environment-variables.md).

</details>

<details>

<summary>A porta 18966 já está em uso, ou eu quero portas diferentes</summary>

O MyIP executa dois listeners: o servidor estático / SPA em `FRONTEND_PORT` (padrão `18966`) e o servidor da API em `BACKEND_PORT` (padrão `11966`). O servidor frontend faz proxy `/api` para o backend, então apenas a porta do frontend precisa estar acessível externamente.

**Implantação com Node** — defina `BACKEND_PORT` e `FRONTEND_PORT` em `.env` e reinicie. Ambos são lidos por `backend-server.js`, `frontend-server.js` e `vite.config.js`, então alterar um sem o outro quebra o proxy.

**Docker** — não altere a porta interna do container; remapeie no lado do host em vez disso. A imagem `EXPOSE`s `18966`:

{% code title="shell" %}

```bash
docker run -d -p 8080:18966 --name myip --restart always jason5ng32/myip:latest
```

{% endcode %}

</details>

<details>

<summary>O cartão da API do curl nunca aparece</summary>

A `curlDomainsHadSet` getter em `frontend/store.js` faz AND entre os três domínios, então o cartão é renderizado somente quando **todos os três** não estão vazios. Definir um ou dois não mostra nada. Defina `VITE_CURL_IPV4_DOMAIN`, `VITE_CURL_IPV6_DOMAIN` e `VITE_CURL_IPV64_DOMAIN` juntos — e lembre-se de que eles são `VITE_*`, então precisam de uma nova build, não apenas de uma reinicialização.

Essas variáveis apenas fornecem hostnames para exibir. O MyIP não serve esses endpoints; você aponta os registros DNS para o seu próprio serviço de eco de IP em texto puro.

</details>

<details>

<summary>Os usuários estão recebendo 429 "Too Many Requests"</summary>

Primeiro, verifique o corpo da resposta. `429 {"message":"Muitas solicitações"}` é `SECURITY_RATE_LIMIT`: o cliente ultrapassou o limite, cuja janela é **20 minutos** por IP de cliente. Um 429 com `código: "quota_exceeded"` é algo completamente diferente — uma cota mensal por conta do upstream repassada por `/api/invisibility` ou `/api/dnsleaktest/session/:token` — e nenhuma configuração local afeta isso.

{% hint style="info" %}
O banner de inicialização diz `🛡️ Limitador de taxa ativado — N solicitações por 60 minutos`, mas a janela configurada em `backend-server.js` é `20 * 60 * 1000` ms. A mensagem de log está incorreta; 20 minutos é a janela real.
{% endhint %}

Aumente o número, ou defina-o como `0` para desativar completamente o limitador. `SECURITY_DELAY_AFTER` é um mecanismo separado e mais suave — ele nunca rejeita, apenas adiciona `acessos × 400 ms` de latência após N solicitações em uma **de 60 minutos** janela.

Um único carregamento de página do MyIP dispara muitas `/api` solicitações, então um limite baixo atingirá usuários comuns. Os logs exibem um aviso de `IP com limitação de taxa` com o IP infrator — uma vez por transição para o estado limitado, não por solicitação bloqueada. Defina `SECURITY_BLACKLIST_LOG_FILE_PATH` se você também quiser um registro persistente em disco.

</details>

## MaxMind

<details>

<summary>Os logs dizem "A API da MaxMind retornará 503 até que os bancos de dados sejam carregados com sucesso"</summary>

O backend não conseguiu abrir `common/maxmind-db/GeoLite2-City.mmdb` e `GeoLite2-ASN.mmdb`. Ele inicia mesmo assim, mas `GET /api/maxmind` responde com 503 e os emblemas de país na UI permanecem vazios.

Normalmente você vê este aviso primeiro:

{% code title="log" %}

```
⚠️  Os bancos de dados da MaxMind estão ausentes e MAXMIND_ACCOUNT_ID / MAXMIND_LICENSE_KEY não estão configurados.
  Defina as credenciais em .env e reinicie, ou coloque GeoLite2-City.mmdb + GeoLite2-ASN.mmdb
  em common/maxmind-db/. Iniciando o servidor mesmo assim; a API da MaxMind retornará 503 até que
  os bancos de dados estejam disponíveis.
```

{% endcode %}

A correção é exatamente o que a mensagem diz — defina as credenciais ou pré-carregue os arquivos:

{% code title=".env" %}

```bash
MAXMIND_ACCOUNT_ID="your-account-id"
MAXMIND_LICENSE_KEY="your-license-key"
MAXMIND_AUTO_UPDATE="true"
```

{% endcode %}

O sucesso se parece com `📦 Bancos de dados MaxMind carregados (inicialização)`. Tutorial completo em [Configuração da MaxMind](/developer/pt-br/getting-started/maxmind-setup.md).

</details>

<details>

<summary>Um container Docker recém-criado tem um diretório maxmind-db vazio</summary>

Isso é intencional. Os bancos de dados GeoLite2 não podem ser redistribuídos sob a licença da MaxMind, e `.dockerignore` exclui `common/maxmind-db/*.mmdb` então uma build local nunca incorpora arquivos que uma build de CI não teria.

Portanto, quem faz deploy com Docker precisa usar o caminho das credenciais — passe `MAXMIND_ACCOUNT_ID`, `MAXMIND_LICENSE_KEY` e `MAXMIND_AUTO_UPDATE="true"` com `-e`. Sem elas, o container inicia, serve a UI e retorna 503 em `/api/maxmind` a cada inicialização.

O primeiro download acontece durante a inicialização e tem limite de 5 minutos. Se expirar, o servidor ainda permanece ouvindo — verifique os logs e reinicie. Veja [Implantar com Docker](/developer/pt-br/getting-started/deploy-with-docker.md).

</details>

<details>

<summary>MAXMIND_AUTO_UPDATE está "false", mas os bancos de dados foram baixados mesmo assim</summary>

Funcionando como planejado. `MAXMIND_AUTO_UPDATE` restringe **apenas o agendador periódico**. O caminho de "baixar se estiver faltando" na inicialização não o consulta: se credenciais válidas estiverem presentes e os `.mmdb` arquivos estiverem ausentes, um ciclo de download é executado. A razão é que credenciais em `.env` já expressam a intenção de "quero a MaxMind funcionando".

Com `MAXMIND_AUTO_UPDATE="true"` você também obtém uma primeira verificação 60 s após a inicialização e uma atualização a cada 24 h. `CAIDA_AUTO_UPDATE` comporta-se da mesma forma para os conjuntos de dados CAIDA.

</details>

## Rede e API

<details>

<summary>curl para /api/... retorna 403, mas o site funciona no navegador</summary>

curl não envia nenhum `Referer` cabeçalho, então a validação global responde `403 {"error":"O que você está fazendo?"}`. Isso não é um bug — esse é justamente o propósito da validação.

Para testar um endpoint manualmente, forneça um referer permitido:

{% code title="shell" %}

```bash
curl -H "Referer: http://localhost/" http://localhost:11966/api/configs
```

{% endcode %}

Use um hostname listado em `ALLOWED_DOMAINS` (ou `localhost`, que é sempre permitido) e acesse a porta do backend diretamente.

</details>

<details>

<summary>Algumas fontes de dados de IP estão ausentes na UI</summary>

O frontend oculta fontes cuja chave de API o backend não tem. `GET /api/configs` retorna um booleano por recurso — nunca os valores das chaves. Busque-o (com um `Referer`) válido) para ver exatamente o que sua instância considera configurado: `map` precisa de `GOOGLE_MAP_API_KEY`, `ipapiis` precisa de `IPAPIIS_API_KEY`, `cloudFlare` precisa de `CLOUDFLARE_API_KEY`, e assim por diante. A lista completa de campos está em [Endpoints da API](/developer/pt-br/reference/api-endpoints.md); as chaves estão em [Chaves de API opcionais](/developer/pt-br/configuration/optional-api-keys.md).

Observe que essa rota é armazenada em cache na borda por 1 hora, então uma chave recém-adicionada pode levar esse tempo para aparecer por trás de uma CDN.

</details>

<details>

<summary>/api/ipapiis ou /api/ip2location retorna 500</summary>

Esses dois handlers constroem sua URL upstream chamando `.split(',')` na chave sem verificação de nulo, então uma chave não definida lança erro e produz um 500 em vez de um erro limpo. Defina `IPAPIIS_API_KEY` ou `IP2LOCATION_API_KEY`.

No uso normal, você nunca vê isso: `/api/configs` reporta a fonte como indisponível e o frontend não a chama.

</details>

<details>

<summary>O compartilhamento de relatório retorna 503 "O compartilhamento de relatórios não está configurado"</summary>

`POST /api/report` e `GET /api/report/:id` requer **todos os três** variáveis do Cloudflare Workers KV: `CLOUDFLARE_API_KEY`, `CLOUDFLARE_ACCOUNT_ID` e `CLOUDFLARE_KV_NAMESPACE_ID`. A ausência de qualquer um deles significa 503 em ambas as rotas e `reportSharing: false` em `/api/configs`, o que oculta completamente a interface de compartilhamento.

Dois erros comuns: o token precisa da **Workers KV Storage: Edit** permissão (o token Radar simples não é suficiente), e `CLOUDFLARE_KV_NAMESPACE_ID` é o **ID hexadecimal** do painel, não seu nome de exibição.

</details>

<details>

<summary>Eventos do Sentry no frontend retornam 404 em /api/monitoring</summary>

`backend-server.js` monta a rota do túnel somente quando `VITE_SENTRY_DSN_FRONTEND` está definido **no processo do servidor**. Se você incorporou o DSN em uma imagem construída por você no tempo de build, mas não o passou também em runtime, o bundle envia envelopes para uma rota que nunca foi montada.

Passe o mesmo valor nos dois lugares. Veja [Error Monitoring (Sentry)](/developer/pt-br/configuration/error-monitoring.md).

</details>

## Desenvolvimento

<details>

<summary>npm install quebra o projeto</summary>

O MyIP é **somente pnpm**. A versão é fixada via `packageManager` em `package.json`, `pnpm-lock.yaml` é commitado, e `pnpm-workspace.yaml` carrega as aprovações de scripts de instalação que dependências nativas precisam. npm ou yarn produziriam um lockfile concorrente e não teriam essas aprovações.

{% code title="shell" %}

```bash
npm install -g pnpm
pnpm install && pnpm run build
```

{% endcode %}

O Dockerfile faz a mesma coisa via `corepack enable`, que provisiona exatamente a versão fixa do pnpm.

</details>

<details>

<summary>O servidor de desenvolvimento não consegue alcançar o backend</summary>

`pnpm dev` executa o Vite e o backend simultaneamente. O Vite serve o frontend em `FRONTEND_PORT` e faz proxy de `/api` para `http://localhost:${BACKEND_PORT}`. Se você mudou uma porta mas não a outra — ou as definiu apenas no shell e não em `.env` — o proxy aponta para nada.

Ambos `vite.config.js` e `backend-server.js` leem as mesmas duas variáveis de `.env`, então mantenha-as lá. Veja [Ambiente de desenvolvimento](/developer/pt-br/development/dev-environment.md).

</details>

<details>

<summary>Nada é registrado exceto erros</summary>

`LOG_LEVEL` usa por padrão `info`, então `debug` as linhas são suprimidas. O registro HTTP por requisição fica totalmente desativado, a menos que você opte por ativá-lo:

{% code title=".env" %}

```bash
LOG_LEVEL="debug"
LOG_HTTP="true"
```

{% endcode %}

`LOG_HTTP=true` registra uma linha por `/api/*` solicitação com método, URL e status. Ele é montado antes do limitador de taxa, então 429s também aparecem. Defina `LOG_FORMAT="json"` se um coletor de logs estiver consumindo a saída. Veja [Logs](/developer/pt-br/configuration/logging.md).

</details>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.ipcheck.ing/developer/pt-br/reference/faq.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
