Troubleshooting GeoIP
Organised by what you see. Start with the API's own log, which names most causes in a sentence. From the folder that holds docker-compose.yml:
sudo docker compose logs geoip --tail 200
sudo docker compose logs geoip-ui --tail 200
GET /status (with your X-Api-Key) shows the databases, their build dates and the last refresh,
and whether the service is answering with placeholders. The console's Dashboard shows the same.
Lookups and databases
| Symptom | Cause | Fix |
|---|---|---|
Every lookup answers unknown, and /status reports the service unavailable | No MaxMind credential is in force, so no database has been downloaded | Set the account on the Databases page or with PUT /credentials. See Databases and credentials |
Every answer is Nullhaven, Placeholder Province with "synthetic": true | The service is not licensed, or its license lapsed | Open the License page, which says why. See Licensing and the license rows below |
| A refresh fails and the Databases page says Not reached | A firewall or a proxy between this host and MaxMind | Let the host reach MaxMind's download service over HTTPS. Check with MaxMind (POST /credentials/test) tells you when it can, without downloading anything |
| A refresh fails and the Databases page says Refused | The credential: a wrong account id or license key, or an account past MaxMind's daily download limit | Correct the credential. A credential set through the API stays in force until you change or remove it, even when it is wrong |
| One edition is refused, the others download | The MaxMind account is not entitled to that edition | Remove it from GeoIp__EditionIds, or change what the account is entitled to at MaxMind |
The build dates on /status are weeks old | The scheduled refresh keeps failing, or the service is unlicensed and skips it. The log says Skipping the GeoLite2 refresh ... this installation is not licensed for the second | Read the last refresh's message on the Databases page, then fix the credential, the network or the license. Set up notifications so the next failure reaches you |
POST /update answers that it did nothing | The service is not licensed | Install a license, then refresh again |
GET /databases/{edition} answers 403 License required | The service is not licensed, so it serves no database files | Install a license. Lookups still answer, with placeholders |
| Lookups answer 429 | The rate limit is on and the key went over it | Wait the Retry-After seconds, or raise the limit on the Options page. See Rate limits |
| A host name in a batch answers nothing | It resolves only to private, loopback or link-local addresses, which are skipped by default | Set GeoIp__ResolvePrivateNames=true if those names are meant to be looked up |
Licensing
| Symptom | Cause | Fix |
|---|---|---|
| The License page says the license is bound to another machine | The license was activated on another host, or /etc/machine-id is not mounted and the recreated container looks like a new machine | Mount /etc/machine-id read-only as in the compose file. Moving a license to another host: see Moving a license |
| The hardware challenge on the License page changes after every recreate | /etc/machine-id is not mounted | Mount it, recreate the container, and activate again if the license was activated for the old challenge |
| The license worked for two weeks, then stopped | It was never activated, or no check-in has got through for 14 days | Activate online on the License page. Let the container reach the internet for its daily check-in |
| A license restored from a backup is not in force | A license that arrives with a restore is read at the next start | Restart the container: sudo docker compose restart geoip |
The start-up log says running unlicensed | The reason follows in brackets: no license of its own, a sponsorship that no longer holds, or a refused offer | Install or activate a license, or, when another product sponsors this service, look at that product's license |
API keys and sign-in
| Symptom | Cause | Fix |
|---|---|---|
| Every call answers 401 | The X-Api-Key header is missing, or the key is wrong, revoked or expired | Send a configured key (Api__Keys__<name>) or a live issued one. A configured key always works: it cannot be revoked through the API |
A POST, PUT or DELETE answers 403 This API key is read-only, so it may only issue GET requests. | The key was issued read-only | Use a key that is not read-only |
| A call with a session answers 401 | The person's session has ended | Sign in again |
| A call or a console action answers 403 | The signed-in account's role does not allow it | An administrator changes the role on the Users page. See Roles |
| A settings change answers 409, naming a variable | The service runs with GeoIp__Storage=environment, which keeps every setting in the environment | Set the variable it names, and restart. See Settings from the environment only |
| Nobody can sign in to the console as admin | The password is forgotten, or the account is locked | Change GEOIP_SEED_ADMIN_PASS and restart the API. On a first start with no value set, read the generated one with sudo docker compose exec geoip cat /data/first-admin-password |
The console says Too many wrong passwords: this account is locked for fifteen minutes. | Five wrong passwords in a row | Wait fifteen minutes, or have an administrator lift the lock on the Users page |
| Signing in works over an SSH tunnel but not on the server's own name | The console keeps a sign-in only over HTTPS or on localhost | Put a reverse proxy with HTTPS in front of the console. Ui__AllowPlainHttp=true is the alternative for a trusted network only. See the reference |
Every sign-in says The sign-in could not be confirmed. Try again. | Cloudflare Turnstile is refusing: a wrong key, a hostname the widget does not list, or the console cannot reach challenges.cloudflare.com | Start the console with the bypass, fix the cause, and remove the bypass. See Locked out by the check |
| The API or the console does not start | An invalid value: an authenticator secret in GEOIP_SEED_ADMIN_TOTP that is not base32 of at least 26 characters, a trusted proxy entry that is not an address or network, or an unknown GeoIp__Storage | The log's last line, The service did not start or stopped on an error, names the setting. Correct it and start again |
Mail and proxies
| Symptom | Cause | Fix |
|---|---|---|
| No notification arrives | Send mail is off (Smtp__Enabled is false by default), Send to is empty, or the settings are incomplete. The SMTP page names what is missing | Switch it on, fill in the server, the from address and a recipient, and press the test button. Remember that the service mails only when the scheduled refresh starts failing and when it works again |
| The test message fails | The mail server refused it, or cannot be reached | The page shows the server's own words. Check the port and the security setting: StartTls on 587, SslOnConnect on 465 |
| Settings in the compose file have no effect on mail | Settings saved on the SMTP page replace the environment's entirely | Change them on the SMTP page, or remove the saved set (DELETE /smtp) to hand control back to the environment |
| The audit log and the session list show one address for everyone | A reverse proxy in front of the console or the API is not named as trusted | Set Ui__TrustedProxies__0 or Api__TrustedProxies__0 to its address and restart that container. The notice on every page names the address. See A proxy that is not trusted |
| Everybody behind the proxy is throttled together at sign-in | The same cause: every visitor is judged as the proxy | The same fix |
Recording what you did
A bug report describes a problem from memory. A session trace records it.
Start one on the Support page, reproduce the problem, and stop it with the recording button that appears beside your name. What you did is stored by the service and can be attached to a bug report.
A trace lists the pages you opened, the controls you used, and anything that went wrong. It can also save a copy of each page as it looked, which is the only thing that answers it rendered wrong.
A trace records which field you filled, never what you put in it, and the places that show a secret are blanked before anything is written down. A copy of a page still shows whatever that page showed - names, host names, addresses - so read a trace before you send it, as you would a log or a support bundle.
A trace belongs to the tab it was started in, and it names the user it belongs to, so a file can be read back to a person.
What an administrator decides
The Support page carries a Configuration card, and what is set there is what every user gets: whether the recording button sits beside your name at all, how much a trace writes down, and how many session traces the service keeps. Lowering a keep count deletes the files above it as soon as the card is saved.
Attaching it
Download the trace from the Support page and send it to whoever asked for it, privately. Never attach it to a public post: see Getting help.
Getting help
Without a license, ask on the community forum on antelao.io, like any free product: say what you did, what you saw, and quote the error. With a license, write to support@antelao.io.
Never post a backup, a log export or your configuration on the forum or in a public issue. They hold your accounts, your settings and visitors' addresses. When Antelao asks for one, send it privately to support@antelao.io.