多数据源聚合的 IP 地理位置、网络信息、安全检测查询系统。支持 AbuseIPDB、iplocate.io、ip2location.io、ipdata.co 四数据源实时对比分析,内嵌 OpenStreetMap 地图定位。
A multi-source IP geolocation, network info, and security detection system with AbuseIPDB, iplocate.io, ip2location.io, and ipdata.co comparison plus embedded OpenStreetMap positioning.
- 🔍 IP 信息查询 — 输入任意 IPv4/IPv6 地址,聚合多源数据
- 📊 多源对比 — 四数据源并排对比,差异高亮
- 🛡️ 安全检测 — VPN / 代理 / Tor / 威胁检测,AbuseIPDB 滥用评分
- 🗺️ 地图定位 — Leaflet + OpenStreetMap 嵌入式地图,深色/浅色主题自动切换 Tile
- 📍 街道地址 — Nominatim 反向地理编码,精确到街道级别
- 🌐 多语言 — 支持 English、简体中文、繁體中文、日本語
- 💻 浏览器标识 — 自动检测并展示访客浏览器、操作系统、设备类型
- 🎨 主题切换 — 深色 / 浅色主题一键切换
- 📱 响应式 — 完美适配桌面端和移动端
- 🔐 密码认证 — Token 鉴权,24h 自动过期
- 📝 SEO 设置 — 按语言配置网站标题、描述、关键词
- 🔑 API Key 管理 — 在线管理四个数据源的多 Key 随机轮询
- 🔗 接口地址配置 — 自定义各数据源 API 端点地址,方便接入代理或新数据源
- 🗺️ 地图设置 — 配置 Nominatim 联系邮箱
- 🔒 安全设置 — 修改管理密码
- 📢 广告位管理 — Head、顶部、搜索区、结果区、底部和左右对联七个位置,支持重复脚本独立实例、HTML / 纯 JS 和旧式脚本兼容加载
- ⚡ 实时生效 — 所有设置修改即时生效,无需重启服务
进入 /admin → 广告,勾选对应广告位,粘贴代码并保存,然后刷新前台。
| 广告位 | 前台位置 / 加载时机 |
|---|---|
| Head | 服务端注入 <head>,适合平台初始化、统计或验证;本身不是可见横幅 |
| 顶部 | 标题下方,首页加载 |
| 搜索区 | 搜索框下方,首页加载 |
| 结果区 | 查询结果顶部,查询成功、结果容器可见后才执行;重复查询不重复初始化 |
| 底部 | 页脚上方,首页加载 |
| 左侧对联 | 宽屏桌面左侧固定,宽度至少 1500px 时加载,可单独关闭 |
| 右侧对联 | 宽屏桌面右侧固定,宽度至少 1500px 时加载,可单独关闭 |
代码类型:含 <script> 标签的完整代码、文字、图片或 iframe 选 HTML / 脚本标签;不带 <script> 标签的 JavaScript 选 纯 JavaScript。旧配置默认按 HTML 加载,保留原有启用状态和代码。
加载方式:
- 自动:通常在主页面执行;代码中直接出现
document.write/document.writeln,或多个启用广告位使用相同普通 HTML/JS 脚本时,使用各自独立的 iframe。所有广告位(包括尚未显示的结果位和窄屏隐藏的侧栏位)在执行前统一识别重复代码,避免重复 ID、全局变量和单次初始化标记只给顶部填充广告。AdSense / GPT 识别为主页面 SDK,保持页面内执行;识别是启发式的,其他依赖主页面的 SDK 请显式选择页面内。 - 页面内:适合 AdSense 等需要主页面 DOM 的现代 SDK;普通外部脚本加载完后再执行后续初始化,显式
async保留异步语义。显式选择会覆盖自动隔离;同一固定容器 ID 的普通广告代码不适合在多个位置同时用页面内模式。现代平台仍需按平台要求配置不同广告单元/容器,不能保证重复同一单元都获得填充。 - iframe 兼容:同一代码可在各广告位分别解析和初始化,支持自动调整高度。脚本型旧式加载器恢复解析器顺序以支持
document.write;带容器的原生异步组件保留async,避免脚本在其后面的容器解析前运行。不同内容但共享全局状态的脚本,或无法自动识别的外部旧脚本,请手动选择此模式。要求直接操作主页面 DOM 的 SDK 不适合此模式。
左右对联:分别保存代码、启用状态和加载方式;升级旧配置后默认关闭,不影响已有四个可见广告位。侧栏位宽 160–280px,建议使用 160×600 或自适应竖幅素材,不要直接粘贴固定宽度的大横幅。视口小于 1500px 时不执行侧栏脚本;变宽后首次初始化。关闭只影响当前页面的一侧,刷新后恢复。侧栏超出可视高度时可滚动,始终留在主内容两边。
所有广告代码具有脚本执行权限,iframe 模式是兼容隔离而不是安全沙箱;只允许可信管理员配置可信平台代码,不要粘贴未知来源脚本。
排查不显示:
- 确认广告位已启用、代码非空,后台保存成功;结果区必须先完成一次查询。
- 浏览器 Network 检查
/api/ads的启用状态、代码类型和加载方式;Head 从首页 HTML 检查。广告接口与首页禁止缓存,静态资源使用版本参数规避旧缓存。 - 检查广告拦截插件、脚本请求失败、HTTPS 页面中的 HTTP 资源、平台域名审核或无广告填充。这些情况无法仅靠网站代码解决。
- 查看浏览器控制台
[Ads:广告位ID]提示,以及容器data-ad-status/data-ad-error。pending表示等待结果区显示或侧栏有足够空间;loaded仅表示配置/脚本加载完成,不代表平台一定返回了广告。data-ad-mode和data-ad-frame-reason可区分页面内、显式 iframe、document.write 或重复代码隔离。
回归测试(开发测试环境需要 Node.js 20+;测试使用临时目录,不修改实际 data/settings.json):
npm install
npm test
# macOS 默认可复用已安装的 Google Chrome;其他环境先安装测试浏览器
npx playwright install chromium
npm run test:browser可通过 PLAYWRIGHT_CHROMIUM_EXECUTABLE 指定 Chromium / Chrome 可执行文件。测试覆盖配置保存与旧配置迁移、权限及格式校验、HTML / JS / iframe、重复代码与全局变量隔离、旧式加载器和原生异步组件、结果区延迟加载、左右对联的宽屏布局与独立关闭、错误隔离和后台到前台的完整操作。
| 组件 Component | 技术 Technology |
|---|---|
| 后端 Backend | Node.js + Express |
| 前端 Frontend | 原生 HTML/CSS/JS |
| 数据源 Sources | AbuseIPDB / iplocate.io / ip2location.io / ipdata.co |
| 地图 Map | Leaflet + OpenStreetMap + CARTO Tiles |
| 地理编码 Geocoding | OpenStreetMap Nominatim |
| CDN | cdn.jsdelivr.net (Inter font, Leaflet) |
| 配置 Config | JSON 文件持久化 |
git clone https://github.com/logdns/ip-query.git
cd ip-querynpm installcp .env.example .env编辑 .env 文件,填入你的 API Key:
# 服务端口
PORT=3008
# AbuseIPDB API Keys (支持多个,逗号分隔)
ABUSEIPDB_KEYS=your_key_1,your_key_2
# iplocate.io API Keys (多个 key 轮询使用,逗号分隔)
IPLOCATE_API_KEY=your_iplocate_key_1,your_iplocate_key_2
# ip2location.io API Keys (多个 key 轮询使用,逗号分隔;留空则使用免费额度)
IP2LOCATION_API_KEY=your_ip2location_key_1,your_ip2location_key_2
# ipdata.co API Keys (多个 key 轮询使用,逗号分隔)
IPDATA_API_KEYS=your_ipdata_key_1,your_ipdata_key_2
# 管理后台密码
ADMIN_PASSWORD=your_admin_password
# Nominatim 联系邮箱 (可选)
NOMINATIM_EMAIL=your-email@example.com注意: 首次启动时,系统会自动从
.env迁移配置到data/settings.json。之后可通过管理后台在线修改,无需编辑文件。
# 开发模式
npm run dev
# 生产模式
npm start服务器启动后访问:
- 登录宝塔面板,进入 软件商店
- 安装 PM2 管理器(Node.js 进程管理)
- 安装 Nginx(如果尚未安装)
- 在 PM2 管理器中确认 Node.js 版本 >= 16
方式一:Git 克隆(推荐)
cd /www/wwwroot
git clone https://github.com/logdns/ip-query.git
cd ip-query
npm install --production方式二:宝塔文件管理器上传
- 打开宝塔 文件 管理器,进入
/www/wwwroot/ - 上传项目压缩包并解压到
/www/wwwroot/ip-query/ - 在终端执行
cd /www/wwwroot/ip-query && npm install --production
cd /www/wwwroot/ip-query
cp .env.example .env编辑 .env 文件,填入你的 API Key 和管理密码。
方式一:宝塔 PM2 管理器界面
- 打开 PM2 管理器
- 点击 添加项目
- 填写信息:
- 项目名称:
ip-query - 启动文件:
/www/wwwroot/ip-query/server.js - 运行目录:
/www/wwwroot/ip-query
- 项目名称:
- 点击 提交
方式二:命令行
cd /www/wwwroot/ip-query
pm2 start server.js --name ip-query
pm2 save
pm2 startup- 在宝塔面板 网站 中添加站点,填写你的域名
- 点击 设置 → 反向代理 → 添加反向代理
- 填写:
- 代理名称:
ip-query - 目标 URL:
http://127.0.0.1:3008
- 代理名称:
- 点击 提交
点击 设置 → 配置文件,在 server {} 块内添加:
# 获取真实 IP (重要!)
set_real_ip_from 0.0.0.0/0;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
# 静态文件缓存
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
root /www/wwwroot/ip-query/public;
expires 7d;
add_header Cache-Control "public, immutable";
}
# 反向代理到 Node.js
location / {
proxy_pass http://127.0.0.1:3008;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
proxy_connect_timeout 60s;
proxy_read_timeout 60s;
}- 在宝塔面板 网站 → 设置 → SSL
- 选择 Let's Encrypt 免费证书
- 点击 申请
- 访问
https://你的域名查看前台 - 访问
https://你的域名/admin进入管理后台 - 默认管理密码为
.env中设置的ADMIN_PASSWORD
# 查看运行状态
pm2 status
# 查看日志
pm2 logs ip-query
# 重启
pm2 restart ip-query
# 停止
pm2 stop ip-query
# 更新代码后重启
cd /www/wwwroot/ip-query
git pull
npm install --production
pm2 restart ip-query系统支持后台一键在线更新,也可手动更新。无论哪种方式,用户配置数据都会自动保留,无需手动迁移。
| 数据 | 存储位置 | 是否纳入 Git | 更新时是否保留 |
|---|---|---|---|
| API 密钥 / 管理密码 / SEO / 接口地址 | data/settings.json |
❌ 已被 .gitignore 忽略 |
✅ 自动保留 |
| 环境变量(仅首次启动用于初始化) | .env |
❌ 已被 .gitignore 忽略 |
✅ 自动保留 |
| 程序代码 | 各源码文件 | ✅ | 🔄 被新版本覆盖 |
核心机制:
data/settings.json与.env都在.gitignore中,git pull永远不会覆盖它们。所有在管理后台修改的配置都持久化在data/settings.json,因此升级是无损的。
后台更新基于 GitHub Releases:只有维护者发布正式 Release 时才会提示更新,版本号语义化(如 v1.1.0),并附完整更新说明。
- 进入管理后台 → 在线更新 标签页
- 点击 检查更新,系统会调用 GitHub API 获取最新 Release,对比当前版本,展示版本号、发布时间与更新说明
- 若有新版本,点击 更新到 vX.Y.Z,系统会:
git fetch --tags后强制对齐(git reset --hard)到该 Release 对应的 tag;本地代码改动会被覆盖,但data/settings.json、.env已被 gitignore,用户配置不受影响- 自动
pm2 restart重启进程使新代码生效 - 轮询健康检查,服务恢复后自动刷新页面
若未运行在 PM2 下,后台会提示需手动重启进程(前端文件已生效,刷新即可)。 私有仓库可在
.env中配置GITHUB_TOKEN以访问 Release API。
本项目直接运行 Node.js 和静态前端,没有编译或打包依赖。发布构建是从已审核的固定 tag生成源码归档,不从脏工作区复制文件。重复广告与左右对联的升级说明见 v1.1.13 发布记录;前次广告对接修复与部分审计记录保留在 v1.1.12 发布记录。
# 1. 提交并推送代码到 main
git push origin main
# 2. 打 tag 并发布 Release (需安装 gh CLI)
gh release create v1.1.0 --title "v1.1.0" --notes "## 更新内容
- 新增 XXX 功能
- 修复 YYY 问题"发布后,所有部署方在后台「检查更新」即可看到 v1.1.0 及其更新说明。
正式发布时,先更新 package.json / package-lock.json 版本和静态资源缓存参数,完成测试与审查,提交所有新增运行模块;为该提交创建未使用的 annotated tag,并核对远端没有漂移。将分支和 tag 一并推送,Release 必须引用该 tag。
源码附件采用单一版本目录前缀,提供 .tar.gz、.zip 和 SHA256SUMS。归档必须与 tag 的 Git 文件树逐文件一致,不包含 .env、实际 data/settings.json、node_modules 或测试输出;.env.example 仅允许经审查的示例占位值。发布后下载附件,核对本地构建摘要与归档内容,并验证远端分支和 tag 都指向已审核提交。
cd /www/wwwroot/ip-query
git fetch --tags # 拉取最新 tag(不会动 data/settings.json)
git checkout v1.1.0 # 切换到目标版本
npm install --production # 如有新依赖
pm2 restart ip-query # 重启使后端代码生效lib/settings.js 在读取时使用 deepMerge 将已存在的 settings.json 与新版默认配置合并:
- 新版本新增的配置字段 → 自动补上默认值
- 你已有的配置值 → 原样保留,不被覆盖
因此从旧版本升级后,无需手动编辑 settings.json,新功能所需的配置项会自动出现。
升级生产环境前,建议先备份配置(一行命令即可):
cp data/settings.json data/settings.json.bak # 备份当前配置
# 如更新后出现异常,可随时回滚:
# cp data/settings.json.bak data/settings.json && pm2 restart ip-query若需回退到某个旧版本代码:
git log --oneline # 查看历史版本
git checkout <commit-hash> # 切到指定版本(data/settings.json 不受影响)
pm2 restart ip-queryip-query/
├── server.js # Express 后端服务
├── package.json # 项目依赖
├── .env.example # 环境变量模板
├── nginx.conf # Nginx 配置参考
├── lib/
│ ├── settings.js # 设置管理模块
│ └── ads.js # 广告配置校验与 Head 代码包装
├── test/ # 临时配置的接口和浏览器回归测试
├── docs/releases/ # 版本发布记录与验证限制
├── data/
│ └── settings.json # 持久化设置 (自动生成)
└── public/
├── index.html # 前台页面 (中英双语)
├── admin.html # 管理后台页面
├── css/
│ ├── style.css # 前台样式
│ └── admin.css # 管理后台样式
└── js/
├── app.js # 前台逻辑 (含 Leaflet 地图)
├── ads.js # 独立广告加载、执行与兼容模式
└── admin.js # 管理后台逻辑
| 路由 Route | 方法 Method | 说明 Description | 认证 Auth |
|---|---|---|---|
/api/myip |
GET | 获取访客公网 IP / Get visitor IP | 否 No |
/api/useragent |
GET | 获取浏览器标识 / Get browser info | 否 No |
/api/query?ip=x.x.x.x |
GET | 聚合查询 IP 信息 / Query IP info | 否 No |
/api/geocode?lat=xx&lon=xx |
GET | 反向地理编码 / Reverse geocode | 否 No |
/api/seo |
GET | 获取 SEO 配置 / Get SEO config | 否 No |
/api/admin/login |
POST | 管理员登录 / Admin login | 否 No |
/api/admin/settings |
GET/PUT | 获取/更新设置 / Get/Update settings | ✅ |
/api/admin/logout |
POST | 登出 / Logout | ✅ |
- 需要 API Key(免费注册 / Free registration)
- 提供安全威胁评分、举报次数、Tor 检测
- 支持多 Key 轮询,提升限额
- 注册: https://www.abuseipdb.com/account/plans
- 需要 API Key(免费注册 / Free registration)
- 提供详细信息:地理位置、ASN、VPN/Proxy/Tor/威胁检测、公司信息、托管商信息
- 支持多 Key 随机轮询
- API 格式:
GET https://iplocate.io/api/lookup/{ip}?apikey=YOUR_KEY - 文档: https://www.iplocate.io/docs
- 可配置 API Key;留空时使用官方免费额度
- 提供地理位置、ASN、代理/VPN/数据中心与欺诈评分信息
- 支持多 Key 随机轮询
- API 格式:
GET https://api.ip2location.io/?key=YOUR_KEY&ip={ip} - 文档: https://www.ip2location.io/ip2location-documentation
- 需要 API Key
- 提供地理位置、ASN、公司、时区与威胁检测信息
- 支持多 Key 随机轮询
- API 格式:
GET https://api.ipdata.co/{ip}?api-key=YOUR_KEY - 文档: https://docs.ipdata.co/docs/getting-started
- 免费,无需 API Key
- 反向地理编码,将经纬度转换为街道地址
- 限制: 每秒 1 次请求
- 文档: https://nominatim.org/release-docs/develop/api/Reverse/
MIT © logdns