> 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/fr/reference/faq.md).

# FAQ

Chaque réponse ci-dessous décrit le comportement réel dans le code, pas des suppositions. Si quelque chose ici ne correspond pas à votre instance, vous êtes probablement sur une version différente.

## Déploiement

<details>

<summary>Chaque appel API renvoie 403 « Access denied » ou « What are you doing? »</summary>

Le filtre global du referer a rejeté la requête. Deux messages distincts :

* `{"error":"What are you doing?"}` — la requête contenait **sans** `Referer` l’en-tête.
* `{"error":"Access denied"}` — un `Referer` a été envoyé, mais son nom d’hôte n’est pas autorisé.

Les noms d’hôte autorisés sont `localhost` ainsi que tout ce qui figure dans `ALLOWED_DOMAINS`. Définissez-le sur le ou les noms d’hôte à partir desquels vos utilisateurs chargent réellement le site :

{% code title=".env" %}

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

{% endcode %}

Puis redémarrez le backend. Trois choses piègent souvent les gens :

1. **La correspondance est exacte.** `example.com` ne couvre pas `sub.example.com`. Listez chaque nom d’hôte.
2. **L’accès via IP brute compte comme un nom d’hôte.** Naviguer vers `http://192.168.1.10:18966` envoie cette IP comme nom d’hôte du referer — ajoutez-la, ou utilisez un nom d’hôte.
3. **Le port et le schéma sont sans importance**, seul le nom d’hôte est comparé.

Voir [Options de sécurité](/developer/fr/configuration/security-options.md).

</details>

<details>

<summary>Ma variable VITE_* n’a aucun effet après le redémarrage du conteneur</summary>

`VITE_*` Les variables sont lues par Vite pendant `pnpm run build` et **incluses dans le bundle JavaScript**. Elles ne sont pas lues à l’exécution. Redémarrer le serveur ne peut pas changer une valeur déjà compilée dans `dist/`.

L’image officielle `jason5ng32/myip:latest` a été construite sans vos valeurs — `.env` se trouve dans `.dockerignore`, donc aucun `.env` n’était présent lors de cette construction non plus. Passer `-e VITE_CURL_IPV4_DOMAIN=...` à l’image précompilée ne change rien pour le frontend. Pour utiliser des variables au moment de la construction dans Docker, vous devez créer votre propre image. Dans un déploiement Node, relancez `pnpm run build`.

Deux `VITE_*` variables sont aussi lues à l’exécution et *le* répondent à `-e`: `VITE_SENTRY_DSN_FRONTEND` (qui monte `/api/monitoring`) et `VITE_SITE_URL` (qui construit la `User-Agent`). Détail complet dans [Variables d'environnement](/developer/fr/reference/environment-variables.md).

</details>

<details>

<summary>Le port 18966 est déjà utilisé, ou je veux des ports différents</summary>

MyIP exécute deux écouteurs : le serveur statique / SPA sur `FRONTEND_PORT` (par défaut `18966`) et le serveur API sur `BACKEND_PORT` (par défaut `11966`). Le serveur frontend fait le proxy de `/api` vers le backend, donc seul le port du frontend doit être accessible de l’extérieur.

**Déploiement Node** — définissez `BACKEND_PORT` et `FRONTEND_PORT` dans `.env` et redémarrez. Les deux sont lus par `backend-server.js`, `frontend-server.js` et `vite.config.js`, donc modifier l’un sans l’autre casse le proxy.

**Docker** — ne changez pas le port interne du conteneur ; remappez-le plutôt côté hôte. L’image `EXPOSE`s `18966`:

{% code title="shell" %}

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

{% endcode %}

</details>

<details>

<summary>La carte API curl n’apparaît jamais</summary>

Le `curlDomainsHadSet` dans le getter `frontend/store.js` fait un AND des trois domaines, donc la carte ne s’affiche que lorsque **les trois** sont non vides. N’en définir qu’un ou deux n’affiche rien. Définissez `VITE_CURL_IPV4_DOMAIN`, `VITE_CURL_IPV6_DOMAIN` et `VITE_CURL_IPV64_DOMAIN` ensemble — et rappelez-vous qu’ils sont `VITE_*`, ils nécessitent donc une recompilation, pas seulement un redémarrage.

Ces variables fournissent uniquement des noms d’hôte à afficher. MyIP ne sert pas ces points de terminaison ; vous pointez les enregistrements DNS vers votre propre service d’écho d’IP en texte brut.

</details>

<details>

<summary>Les utilisateurs reçoivent 429 « Too Many Requests »</summary>

`SECURITY_RATE_LIMIT` est défini et le client l’a dépassé. La fenêtre est **20 minutes** par IP client, et le dépasser renvoie `429 {"message":"Trop de requêtes"}`.

{% hint style="info" %}
La bannière de démarrage indique `🛡️ Limiteur de débit activé — N requêtes par 60 minutes`, mais la fenêtre configurée dans `backend-server.js` est `20 * 60 * 1000` ms. Le message de log est erroné ; 20 minutes est la vraie fenêtre.
{% endhint %}

Augmentez le nombre, ou définissez-le sur `0` pour désactiver complètement le limiteur. `SECURITY_DELAY_AFTER` est un mécanisme distinct, plus doux — il ne rejette jamais, il ajoute seulement `hits × 400 ms` de latence après N requêtes dans une **fenêtre de 60 minutes** .

Un seul chargement de page MyIP déclenche de nombreuses `/api` requêtes, donc une limite basse affectera les utilisateurs ordinaires. Les journaux comportent un avertissement `IP soumise à une limitation de débit` avec l’IP fautive — une fois par transition vers l’état limité, et non par requête bloquée. Définissez `SECURITY_BLACKLIST_LOG_FILE_PATH` si vous voulez aussi un registre persistant sur disque.

</details>

## MaxMind

<details>

<summary>Les journaux indiquent « MaxMind API will return 503 until databases are loaded successfully »</summary>

Le backend n’a pas pu ouvrir `common/maxmind-db/GeoLite2-City.mmdb` et `GeoLite2-ASN.mmdb`. Il démarre quand même, mais `GET /api/maxmind` renvoie 503 et les badges de pays dans l’interface restent vides.

Vous voyez généralement cet avertissement en premier :

{% code title="journal" %}

```
⚠️  Les bases MaxMind sont manquantes et MAXMIND_ACCOUNT_ID / MAXMIND_LICENSE_KEY ne sont pas configurés.
  Définissez les identifiants dans .env et redémarrez, ou déposez GeoLite2-City.mmdb + GeoLite2-ASN.mmdb
  dans common/maxmind-db/. Démarrage du serveur quand même ; l’API MaxMind renverra 503 jusqu’à
  ce que les bases de données soient disponibles.
```

{% endcode %}

La correction est exactement ce que le message indique — définissez les identifiants, ou préchargez les fichiers :

{% code title=".env" %}

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

{% endcode %}

Le succès ressemble à `📦 MaxMind databases loaded (startup)`. Procédure complète dans [Configuration de MaxMind](/developer/fr/getting-started/maxmind-setup.md).

</details>

<details>

<summary>Un conteneur Docker fraîchement créé a un répertoire maxmind-db vide</summary>

C’est volontaire. Les bases GeoLite2 ne peuvent pas être redistribuées sous la licence MaxMind, et `.dockerignore` exclut `common/maxmind-db/*.mmdb` afin qu’une build locale n’intègre jamais des fichiers qu’une build CI n’aurait pas.

Les déploiements Docker doivent donc utiliser le chemin par identifiants — passez `MAXMIND_ACCOUNT_ID`, `MAXMIND_LICENSE_KEY` et `MAXMIND_AUTO_UPDATE="true"` avec `-e`. Sans eux, le conteneur démarre, sert l’interface, et renvoie 503 sur `/api/maxmind` à chaque démarrage.

Le premier téléchargement a lieu au démarrage et est limité à 5 minutes. S’il expire, le serveur continue d’écouter — vérifiez les journaux et redémarrez. Voir [Déployer avec Docker](/developer/fr/getting-started/deploy-with-docker.md).

</details>

<details>

<summary>MAXMIND_AUTO_UPDATE est "false" mais les bases de données ont quand même été téléchargées</summary>

Fonctionnement normal. `MAXMIND_AUTO_UPDATE` ne concerne que le planificateur périodique **seul le planificateur périodique**. Le chemin de démarrage « download if missing » ne le consulte pas : si des identifiants valides sont présents et que les `.mmdb` fichiers `.env` expriment déjà l’intention « Je veux que MaxMind fonctionne ».

Avec `MAXMIND_AUTO_UPDATE="true"` vous obtenez en plus une première vérification 60 s après le démarrage et un rafraîchissement toutes les 24 h. `CAIDA_AUTO_UPDATE` se comporte de la même manière pour les jeux de données CAIDA.

</details>

## Réseau et API

<details>

<summary>curl sur /api/... renvoie 403, mais le site fonctionne dans un navigateur</summary>

curl n’envoie pas `Referer` d’en-tête, donc le filtre global répond `403 {"error":"Que faites-vous ?"}`. Ce n’est pas un bug — c’est précisément le but du filtre.

Pour tester un point de terminaison à la main, fournissez un referer autorisé :

{% code title="shell" %}

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

{% endcode %}

Utilisez un nom d’hôte listé dans `ALLOWED_DOMAINS` (ou `localhost`, qui est toujours autorisé) et accédez directement au port du backend.

</details>

<details>

<summary>Certaines sources de données IP sont absentes de l’interface</summary>

Le frontend masque les sources dont le backend ne possède pas la clé API. `GET /api/configs` renvoie un booléen par fonctionnalité — jamais les valeurs de clé. Récupérez-le (avec un `Referer`valide) pour voir exactement ce que votre instance considère comme configuré : `map` nécessite `GOOGLE_MAP_API_KEY`, `ipapiis` nécessite `IPAPIIS_API_KEY`, `Cloudflare` nécessite `CLOUDFLARE_API_KEY`, et ainsi de suite. La liste complète des champs se trouve dans [Points de terminaison API](/developer/fr/reference/api-endpoints.md); les clés se trouvent dans [Clés API facultatives](/developer/fr/configuration/optional-api-keys.md).

Notez que cette route est mise en cache en périphérie pendant 1 heure, donc une clé nouvellement ajoutée peut mettre autant de temps à apparaître derrière un CDN.

</details>

<details>

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

Ces deux gestionnaires construisent leur URL amont en appelant `.split(',')` sur la clé sans vérification de null, donc une clé non définie lève une exception et produit un 500 plutôt qu’une erreur propre. Définissez `IPAPIIS_API_KEY` ou `IP2LOCATION_API_KEY`.

En usage normal, vous ne voyez jamais cela : `/api/configs` signale la source comme indisponible et le frontend ne l’appelle pas.

</details>

<details>

<summary>Le partage de rapports renvoie 503 « Report sharing is not configured »</summary>

`POST /api/report` et `GET /api/report/:id` nécessitent **les trois** les variables Cloudflare Workers KV : `CLOUDFLARE_API_KEY`, `CLOUDFLARE_ACCOUNT_ID` et `CLOUDFLARE_KV_NAMESPACE_ID`. En manquer une seule signifie un 503 sur les deux routes et `reportSharing: false` dans `/api/configs`, ce qui masque complètement l’interface de partage.

Deux erreurs fréquentes : le jeton nécessite l’autorisation **Workers KV Storage : Edit** (permission) (le jeton Radar simple ne suffit pas), et `CLOUDFLARE_KV_NAMESPACE_ID` est l’ **ID hexadécimal** du namespace dans le tableau de bord, et non son nom d’affichage.

</details>

<details>

<summary>Les événements Sentry du frontend renvoient 404 sur /api/monitoring</summary>

`backend-server.js` monte la route du tunnel uniquement lorsque `VITE_SENTRY_DSN_FRONTEND` est défini **sur le processus serveur**. Si vous avez intégré le DSN dans une image construite par vous au moment de la build mais ne l’avez pas aussi passé à l’exécution, le bundle envoie des enveloppes à une route qui n’a jamais été montée.

Passez la même valeur aux deux endroits. Voir [Surveillance des erreurs (Sentry)](/developer/fr/configuration/error-monitoring.md).

</details>

## Développement

<details>

<summary>npm install casse le projet</summary>

MyIP est **pnpm uniquement**. La version est verrouillée via `packageManager` dans `package.json`, `pnpm-lock.yaml` est versionné, et `pnpm-workspace.yaml` contient les autorisations de scripts d’installation nécessaires aux dépendances natives. npm ou yarn produiraient un lockfile concurrent et manqueraient ces autorisations.

{% code title="shell" %}

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

{% endcode %}

Le Dockerfile fait la même chose via `corepack enable`, qui installe exactement la version de pnpm verrouillée.

</details>

<details>

<summary>Le serveur de développement ne peut pas atteindre le backend</summary>

`pnpm dev` exécute Vite et le backend simultanément. Vite sert le frontend sur `FRONTEND_PORT` et fait le proxy de `/api` vers `http://localhost:${BACKEND_PORT}`. Si vous avez modifié un port mais pas l’autre — ou les avez définis seulement dans le shell et pas dans `.env` — le proxy pointe vers rien.

Les deux `vite.config.js` et `backend-server.js` lisent les deux mêmes variables depuis `.env`, donc gardez-les là. Voir [Environnement de développement](/developer/fr/development/dev-environment.md).

</details>

<details>

<summary>Rien n’est consigné à part les erreurs</summary>

`LOG_LEVEL` par défaut `info`, donc `debug` les lignes sont supprimées. La journalisation HTTP par requête est complètement désactivée sauf si vous l’activez :

{% code title=".env" %}

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

{% endcode %}

`LOG_HTTP=true` consigne une ligne par `/api/*` requête avec la méthode, l’URL et le statut. Il est monté avant le limiteur de débit, donc les 429 apparaissent aussi. Définissez `LOG_FORMAT="json"` si un collecteur de journaux consomme la sortie. Voir [Journalisation](/developer/fr/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/fr/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.
