# zu1k/nali: An Offline CLI for IP Geolocation and CDN Provider Lookup

> nali annotates IP addresses with geographic and CDN information directly in your terminal, using local databases and pipe-friendly output. It is a small Go tool for anyone who reads dig or nslookup output all day, and its main constraint is that the data quality depends entirely on which database you choose.

**zu1k/nali** — An offline tool for querying IP geographic information and CDN provider. 一个查询IP地理信息和CDN服务提供商的离线终端工具.

- Repository: https://github.com/zu1k/nali
- Website: https://github.com/zu1k/nali
- Stars: 4,106 · Forks: 374
- Language: Go
- License: MIT
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/zu1k-nali

## What nali solves for people who stare at IP addresses

Reading raw IP addresses is tedious. A log line, a dig answer or an nslookup result gives you a number and nothing else, and the next step is usually a browser tab and an online lookup service. nali removes that step. According to the README, it is "一个查询IP地理信息和CDN提供商的离线终端工具", an offline terminal tool for querying IP geographic information and CDN providers. The word offline matters: the lookup happens against databases stored on your own disk, so the addresses you are investigating are not sent to a remote service. That is the whole pitch, and it is a narrow one. nali is for network engineers, SREs, and anyone debugging DNS or CDN behaviour who wants the annotation to appear inline, in the same terminal, next to the output they already have. It is not a monitoring system, not a database, and not a replacement for a proper IP intelligence product. The README lists its supported sources plainly: Chunzhen IPv4, ZX IPv6, and optional GeoIP2, IPIP, ip2region, DB-IP and IP2Location DB3 LITE databases. That list is also the honest summary of its limits, because whichever of those you enable determines how accurate any given answer will be.

## How nali annotates piped input and interactive queries

The mechanism is textual, not structural. nali reads IP addresses from arguments, from standard input, or from an interactive prompt, resolves each one against the configured database, and prints the original line with a bracketed annotation inserted after the address. The README describes it as inserting geographic information after the IP and CDN provider information after the CDN domain. That design is why it composes with anything: because it never parses the surrounding format, it does not need to understand dig, nslookup or an arbitrary shell script. The cost is that it also cannot reformat or filter, and it will annotate any string that looks like an IP address, including ones that are not what you meant. Internally the repository is a Go module, github.com/zu1k/nali, built with Cobra for the command line and Viper for configuration, with database parsers pulled in per format: geoip2-golang for mmdb, ipdb-go for IPIP, ip2region for its own format, and ip2location-go for DB3. The Dockerfile builds a static binary in a golang:alpine stage and copies it into a plain alpine:latest image with ca-certificates, which is the shape you would expect from a tool that has no runtime service dependencies. Configuration is generated on first run as config.yaml, and nali info prints where that file and the databases live.

## Installing nali and running a first lookup

There are three documented installation routes. Building from source requires Go 1.19 or newer, per the README. The command below installs the latest version into your Go binary directory; afterwards nali should be on your PATH and nali --help should print the Cobra usage block.

```bash
go install github.com/zu1k/nali@latest
```

If you would rather not install a Go toolchain, the release page hosts precompiled executables for multiple systems and architectures. Download the archive matching your OS and CPU, unpack it, and run the binary directly. Arch-family Linux users have a third option: the README states that three AUR packages exist, nali-go (release version, compiled at install time), nali-go-bin (release version, precompiled binary) and nali-go-git (latest master, compiled at install time).

The Dockerfile builds an image whose entrypoint is the nali binary, so container users can run the same query without installing anything on the host.

```bash
docker build -t nali .
docker run --rm nali 1.2.3.4
```

A first real query is a single argument. The README gives this exact example and its output, which shows the annotation format you should expect.

```bash
nali 1.2.3.4
# 1.2.3.4 [澳大利亚 APNIC Debogon-prefix网络]
```

The more useful pattern is piping. Anything that emits IP addresses can be fed in, and nali will annotate each one in place.

```bash
dig nali.zu1k.com +short | nali
```

The README shows that this produces lines such as 104.28.2.115 followed by a bracketed CloudFlare annotation, and notes that dig must already be installed on your system. The same applies to nslookup. Finally, nali update refreshes the databases that support automatic updates; the README's example downloads the Chunzhen IP database and saves it to the local nali directory, and you can restrict the scope with nali update --db qqwry,cdn.

## Where nali's answers are weaker than they look

The output format is confident, but the underlying data is not uniform. nali supports several databases with different coverage, licensing and update cadence, and the default depends on which one the configuration resolves to. The README states plainly that you can add databases by editing config.yaml carefully, and that if you have problems you should open an issue, which is a candid admission that the configuration surface is not fully documented. The languages and types fields in the config determine which languages and query types a database supports, and multilingual output is only available through GeoIP2, so a user who sets NALI_LANG to a non-Chinese value is effectively locked into that one backend. IPv6 is a second weak point in practice: the README lists ZX IPv6 as the offline IPv6 source, and the example output for a Google IPv6 address carries a country and city label, but the accuracy of that record is a property of the ZX database, not of nali. The tool has no way to tell you that an answer is uncertain. It prints whatever the database returns. If you need defensible geolocation for fraud checks, content licensing or legal review, nali is the wrong instrument; it is a terminal convenience, and the README never claims otherwise.

## nali against a hosted IP geolocation API

The obvious alternative is a hosted lookup API, and the difference is architectural rather than a matter of features. A hosted service keeps the database on its own infrastructure and returns a response over HTTP, which means you get fresher data without maintaining anything locally, but every query leaves your machine and rate limits, keys and availability become part of your workflow. nali inverts all of that. Lookups are local, so they work on an air-gapped host or inside a container with no egress, and there is no per-query cost or quota. In exchange you own the update problem: the README's nali update command exists precisely because the bundled databases go stale, and it only covers the sources that support automatic updates. If you want GeoIP2 or IP2Location data, you are responsible for obtaining and placing those files yourself. A second alternative is the database library directly, for example the geoip2-golang parser that nali itself depends on. That gives you structured records and full control over formatting, at the cost of writing and maintaining the glue code that nali already provides. Choose nali when the value is in the pipeline integration; choose a library when you need the raw fields.

## Maintenance, licensing and what the release history shows

The repository is not archived, and the last push was on 2026-05-12, which is recent enough that the codebase is still receiving changes. That is not the same as a steady release cadence: the most recent release listed is v0.8.1 from 2023-12-11, preceded by v0.8.0 in 2023-10-02 and v0.7.3 in 2023-05-01. Anyone pinning a version should therefore expect to run master or build from source if they want the newest database handling, and anyone pinning the binary should be aware that the tagged releases are older than the branch. The project is MIT licensed, which is permissive and imposes no copyleft obligation on your own code. The databases are a separate question, and the README's acknowledgements list their origins: Chunzhen, ZX, MaxMind GeoIP2, IPIP, ip2region, IP2Location and the CDN provider database from SukkaLab. Each of those carries its own terms, and several are commercial products with free tiers or registration requirements. Bundling nali into a product does not automatically grant you the right to redistribute the data files it can consume. Read the terms of whichever database you actually ship.

## Choosing a database with NALI_DB_IP4 and NALI_DB_IP6

Database selection is done through environment variables, not flags. The README documents NALI_DB_IP4 and NALI_DB_IP6, which can be set independently or together, and lists the accepted values per backend: geoip or geoip2, chunzhen or qqwry, ipip, ip2region or i2r, dbip or db-ip, and ip2location. On Linux the syntax is a plain export, and on Windows the README gives both the set form and the PowerShell equivalent.

```bash
export NALI_DB_IP4=geoip
```

Setting only NALI_DB_IP4 leaves IPv6 on whatever the configuration defaults to, which is a quiet way to end up with inconsistent answers between the two families. Set both if you care about the comparison. Working directories are controlled by NALI_HOME, NALI_CONFIG_HOME and NALI_DB_HOME; when none are set, nali follows the XDG specification and places configuration under $XDG_CONFIG_HOME/nali and databases under $XDG_DATA_HOME/nali. That matters for containers and for read-only root filesystems, because the default data directory may not be writable. The README gives the Windows example set NALI_HOME=D:\nali and the Linux equivalent export NALI_HOME=/var/nali. Run nali info first to see which paths are in effect before you go looking for the files.

## Conclusion

Adopt nali if you want IP context inside a shell pipeline without sending queries to a third-party API, and if you are willing to run nali update to keep the bundled databases current. Skip it if you need authoritative geolocation for compliance decisions, since the default Chunzhen database is community-maintained and the README itself points to several optional commercial or third-party sources. Before relying on it, run nali info to see where the config and database files live on your machine, then test one known IPv4 and one known IPv6 address to confirm which database is actually answering.

## FAQ

### Does nali send my IP addresses to an external server?

No. The README describes nali as a fully offline query tool, and lookups run against databases stored on your own machine. The only documented network activity is the nali update command, which downloads updated database files.

### How do I install nali with Go?

The README requires Go 1.19 or newer and gives the command go install github.com/zu1k/nali@latest. Precompiled binaries are also available from the release page for users who do not want a Go toolchain.

### Does nali support IPv6 addresses?

Yes. The README states that IPv6 usage is identical to IPv4, and lists the ZX IPv6 offline database as the IPv6 source. The nslookup example in the README includes an IPv6 result with a country and city annotation.

### How do I change which database nali uses?

Set the NALI_DB_IP4 or NALI_DB_IP6 environment variables to one of the documented values, such as geoip, chunzhen, qqwry, ipip, ip2region, dbip or ip2location. The README shows export NALI_DB_IP4=geoip on Linux and the set or PowerShell equivalents on Windows.

### Can nali show results in a language other than Chinese?

The README documents the NALI_LANG environment variable for this, but notes that non-Chinese output is only supported by the GeoIP2 database. The README's example is NALI_LANG=en nali 1.1.1.1, which returns a country name only.

## Sources

- [License: MIT](https://github.com/zu1k/nali/blob/master/LICENSE)
- [Project website](https://github.com/zu1k/nali)
- [README](https://github.com/zu1k/nali/blob/master/README.md)
- [Releases](https://github.com/zu1k/nali/releases)
- [zu1k/nali on GitHub](https://github.com/zu1k/nali)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/zu1k-nali
