> 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/getting-started/maxmind-setup.md).

# MaxMind Setup (Required)

Set up the required MaxMind GeoLite2 databases for IP geolocation and ASN lookups.

MyIP reads two free **GeoLite2** databases from MaxMind — `GeoLite2-City.mmdb` and `GeoLite2-ASN.mmdb` — for local, offline IP geolocation and ASN lookups.

They are **not** in the repository and **not** in the Docker image. MaxMind's GeoLite2 license does not allow redistribution, so every deployment has to bring its own copy.

## What breaks without them

The server still starts. But:

* `/api/maxmind` returns **503** on every request, so the MaxMind IP source produces nothing.
* Features built on that source — including the country badges shown for WebRTC ICE candidates — stay empty.
* The Bulk IP Lookup tool cannot look anything up: `POST /api/bulk-lookup` answers **503** too.
* Every boot logs `❌ MaxMind API will return 503 until databases are available: …`.

Other IP sources keep working, so the app looks half-broken rather than broken. That is exactly why this page is required reading.

## Get credentials

{% stepper %}
{% step %}

#### Create a free GeoLite2 account

Sign up at [maxmind.com/en/geolite2/signup](https://www.maxmind.com/en/geolite2/signup). No payment details are required.
{% endstep %}

{% step %}

#### Note your account ID

MaxMind shows it in your account dashboard. It is a number, not your email address.
{% endstep %}

{% step %}

#### Generate a license key

Open **Manage License Keys** and create a new key. Copy it immediately — MaxMind shows it only once.
{% endstep %}
{% endstepper %}

## Option A — Automatic download (recommended)

Set your credentials and let MyIP fetch and refresh the databases itself.

{% code title=".env" %}

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

{% endcode %}

`DATASET_AUTO_UPDATE` is on by default. Spelling it out keeps an older `.env` that still has `MAXMIND_AUTO_UPDATE="false"` from holding the refresh off. In Docker, pass the same three with `-e` — see [Deploy with Docker](/developer/getting-started/deploy-with-docker.md).

What happens then:

| When                                              | What happens                                                                                                                                                                                                                                     |
| ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| At startup, files missing or unreadable           | The backend starts listening at once and downloads both databases in the background, capped at 5 minutes. Until they land, `/api/maxmind` answers `503`. This runs whenever credentials are present, even if `DATASET_AUTO_UPDATE` is `"false"`. |
| At startup, files present                         | Nothing is downloaded; the existing files are loaded before the backend starts listening.                                                                                                                                                        |
| Daily at 04:30, server-local time                 | The updater checks MaxMind and downloads only when a new release is out. Change the time with [`DATASET_UPDATE_CRON`](/developer/reference/environment-variables.md#dataset-update-cron).                                                        |
| \~60 seconds after startup, if a check was missed | A daily check that fell while the server was down runs now instead.                                                                                                                                                                              |

{% hint style="success" %}
**Updates are safe by construction.** New files are downloaded to a temp directory and validated, then City and ASN are published together, rolled back if any step fails. The in-memory readers are swapped afterwards, so a database refresh never restarts the server and never serves a half-written file. A lock prevents two processes (for example two pm2 instances) from updating at once; the others reload what was published.
{% endhint %}

{% hint style="warning" %}
**Docker deployers must use Option A.** A fresh container has no `.mmdb` files at all, and there is nothing to copy them into unless you build your own image.
{% endhint %}

## Option B — Manual placement

For air-gapped hosts, or if you would rather not give the app outbound access to MaxMind. This only works when you [deploy from source](/developer/getting-started/deploy-with-nodejs.md).

{% stepper %}
{% step %}

#### Download the databases

From your MaxMind account, download the **GeoLite2 City** and **GeoLite2 ASN** archives in `.mmdb` (binary) form and extract them.
{% endstep %}

{% step %}

#### Put them in place

Copy both files into `common/maxmind-db/`, keeping their exact names:

```
common/maxmind-db/GeoLite2-City.mmdb
common/maxmind-db/GeoLite2-ASN.mmdb
```

{% endstep %}

{% step %}

#### Leave the credentials unset

Without `MAXMIND_ACCOUNT_ID` and `MAXMIND_LICENSE_KEY`, MyIP never downloads or refreshes the MaxMind databases, so your files stay as you placed them. Start the backend. It finds the files and loads them.
{% endstep %}
{% endstepper %}

{% hint style="info" %}
With Option B you refresh the files yourself as MaxMind publishes new releases. You do not need to restart the server after replacing them — the file watcher notices the change, checks that both files open, and reloads the readers within a few seconds. A file that fails that check is ignored and the current readers stay in place.
{% endhint %}

## Verifying

A healthy startup logs:

```
📦 MaxMind databases loaded (startup)
```

On a first boot that downloaded them, the line ends in `(bootstrap)` instead. With auto-update on, you also get the schedule, listing `maxmind` among the datasets:

```
🗓️  Dataset auto update: maxmind, as2org, as-rel at cron 30 4 * * * (next ...)
```

## Troubleshooting

<details>

<summary>❌ MaxMind API will return 503 until databases are available</summary>

The backend could not open both `.mmdb` files once its boot downloads had finished. Scroll up in the log — the line `Failed to load MaxMind databases` carries the specific reason. Common causes:

* The credentials never reached the process, so nothing was downloaded — there is no `📥 Dataset maxmind …` line above. Check that your `.env` sits in the project root and you restarted after editing it, that in Docker the `-e` flags are on the `docker run` command (or in the `environment:` block) rather than on `docker exec`, and that the variable names are spelled exactly as above.
* The download failed (see the entries below).
* Only one of the two files is present. MyIP needs **both** City and ASN.

</details>

<details>

<summary>Failed to check GeoLite2-City: HTTP 401</summary>

MaxMind rejected the credentials. The account ID and license key are used as HTTP Basic auth against `download.maxmind.com`, so a 401 means one of them is wrong.

* Confirm the account ID is the numeric ID, not your email.
* Regenerate the license key — keys can be revoked, and a copy/paste that dropped a character looks identical to a valid key.
* Make sure the key was created for **GeoLite2**, under the same account.

</details>

<details>

<summary>Dataset maxmind initial download failed: did not complete within 5 min</summary>

The startup download hit its time cap. This is a network problem, not a credential problem — check that the host can reach `download.maxmind.com` (firewall, egress rules, proxy). The server keeps running; the next boot tries again, and so does the daily refresh.

</details>

<details>

<summary>Dataset auto update: off — or maxmind missing from its list</summary>

`DATASET_AUTO_UPDATE` is `"false"`. Or it is unset and an older `.env` still has `MAXMIND_AUTO_UPDATE` set to something other than `"true"`, which keeps MaxMind's refresh off. MaxMind is also left out whenever either credential is empty — both are required.

Note this affects the **daily refresh** only. The startup download still runs when the files are missing and credentials are present.

</details>

<details>

<summary>dataset update skipped: another process holds the lock</summary>

Expected when you run several backend instances — one holds the update lock, the others step aside. Harmless.

The lock carries a heartbeat, so one left behind by a crashed process goes stale on its own after 10 minutes. There is nothing to delete by hand.

</details>

## Next steps

* [Deploy with Docker](/developer/getting-started/deploy-with-docker.md) — where the databases live inside the container
* [Optional API Keys](/developer/configuration/optional-api-keys.md) — additional IP data sources beyond MaxMind
* [IP Data Sources](/developer/architecture/ip-data-sources.md) — how MyIP combines its sources


---

# 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 by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.ipcheck.ing/developer/getting-started/maxmind-setup.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

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.
