Xray Checker: a Prometheus exporter that probes Xray proxy nodes
Xray Checker: A Prometheus exporter for monitoring Xray proxies
At a glance
- What is it?
- Xray Checker is a Go service that reads proxy nodes from subscriptions, tests each one through Xray Core, and exposes the results as Prometheus metrics, a REST API and a web interface. It fits operators of self-hosted Xray, Marzban or Remnawave deployments, and it does not fit a team that wants a proxy client rather than a monitoring probe.
- Who is it for?
- Adopt Xray Checker when you operate Xray based infrastructure and already have Prometheus in place, and when you can supply nodes through a subscription URL or share links. Skip it if you are an end user looking for a client, if you need to test protocols other than VLESS, VMess, Trojan and Shadowsocks, or if AGPL-3.0 does not fit your distribution model.
- Can I use it commercially?
- Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
- Is it still maintained?
- Yes. The repository last received commits 43 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The probe is the product
Xray Checker is described as a tool for monitoring proxy server availability with support for VLESS, VMess, Trojan and Shadowsocks protocols. It automatically tests connections through Xray Core and then provides metrics for Prometheus, along with API endpoints for integration with monitoring systems.
That framing matters, because there are two different things people want here. A client wants to route traffic through a working node. A checker wants to know, continuously and without disturbing traffic, which nodes answer and which have quietly died. The second job is the one this project does, and the tooling around it, a Prometheus exporter, a scheduled sweep, a REST API and a web interface, all point the same way.
The repository layout matches the pipeline. There are directories for checker/, subscription/, xray/, metrics/, web/, config/ and models/, plus logger/ and a main.go entry point, with go.mod at the root and a Dockerfile for the container build. The service is written in Go, requires Go 1.26.3 per go.mod, and pulls in github.com/xtls/xray-core and github.com/xtls/libxray for the protocol handling, github.com/prometheus/client_golang for the metrics, github.com/go-co-op/gocron for scheduling and github.com/alecthomas/kong for the command line parser.
Repository topics mention Marzban and Remnawave, which tells you the ecosystem this is built for: operators of panel-managed proxy fleets who already have a subscription format and want per-node health in their existing monitoring.
Configuration arrives as a subscription, not as a file
The configuration loading is flexible by design, and the feature list spells out the accepted shapes: URL subscriptions in base64 or JSON, share links in vless://, vmess://, trojan:// and ss:// form, JSON configuration files, and folders containing configurations. Multiple subscriptions are supported, and configuration updates are automatic rather than something you re-trigger by hand.
That is the part of the design with real consequences. An exporter whose input is a URL is a scraper that trusts a remote endpoint. The subscription URL is a credential in practice, since it usually enumerates your paid or private nodes, and the service holds it in an environment variable. Anyone who can reach the container's environment or read the mounted configuration can obtain the full node list, including connection details.
The countermeasure listed in the features is Basic Auth protection for the metrics and the web interface, plus a public status page for VPN services that requires no authentication. Those two together mean the status page is deliberately open while the operational surfaces are guarded. That is a reasonable split for a service whose whole purpose is to advertise which nodes are up, but it also means the public page is a live inventory of your infrastructure, which is worth a deliberate decision rather than a default.
Starting the container on port 2112
The documented quick start is a single docker run with the subscription in the environment and one published port:
docker run -d \
-e SUBSCRIPTION_URL=https://your-subscription-url/sub \
-p 2112:2112 \
kutovoys/xray-checkerThe Compose form carries the same two settings:
services:
xray-checker:
image: kutovoys/xray-checker
environment:
- SUBSCRIPTION_URL=https://your-subscription-url/sub
ports:
- "2112:2112"After that, the container serves the web interface and the metrics endpoint on port 2112. The Dockerfile explains how the image is built, and it is a careful one. The build stage is golang:1.26-alpine with CGO_ENABLED=0, the module files are copied and downloaded separately for layer caching, and the binary is built with version and commit stamped in through ldflags, then compressed with UPX using the best and lzma settings. The runtime stage is alpine:3.21, and the image installs ca-certificates, curl and tzdata, creates a non-root user with uid 1000 named appuser, and creates an /app directory owned by that user with a geo subdirectory for the geoip.dat and geosite.dat files the project manages automatically. The container then runs as appuser with the binary as its entrypoint.
The uid 1000 detail matters in practice: on a host where another service already owns uid 1000, the container still starts, but bind-mounted host directories have to be writable by that uid.
Metrics, a REST API, and integration points
The output side is what the tool is for. Prometheus metrics export is listed with Pushgateway support, so a short-lived sweep can push results to a Pushgateway rather than relying on Prometheus to scrape a value that only changes every few minutes. The REST API comes with OpenAPI and Swagger documentation, and there are endpoints specifically aimed at monitoring system integration, with Uptime Kuma named as an example.
The distinction between push and pull matters for how you deploy this. A pull model wants the exporter to expose a current value on request. A sweep-and-push model, which is what testing a list of remote nodes naturally is, wants to publish a result with a timestamp attached. Xray Checker does both, so you can pick whichever fits your alerting setup.
The web interface adds a dark and light theme and allows full customization, including a custom logo, styles or an entire template. For a status page that end users or customers look at, that customisation surface is the point of the feature rather than a nicety. The documentation site holds the complete feature list, which the README deliberately does not duplicate.
Limits of the check and of the protocol coverage
An availability check is a narrow measurement, and the documentation does not expand it into a full quality assessment. Nothing in the feature list describes latency percentiles, throughput measurement, packet loss or jitter across a sustained transfer. What is described is whether the connection test succeeds.
That has direct consequences for how you use the metrics. A node that answers a connection test can still be slow, throttled or degraded, and it will look healthy in Prometheus. If your operational question is which nodes to steer users toward, an availability signal may not be enough, and you would have to add your own measurement layer on top. The exported metric tells you the node is reachable, not that it is good.
Protocol coverage is equally bounded. VLESS, VMess, Trojan and Shadowsocks are the four named protocols, and share links for those four schemes are what the loader parses. Any other transport a subscription might contain is outside what this project claims to handle.
One operational note from the Dockerfile deserves repeating: the image installs ca-certificates, which matters because the service fetches subscription URLs over HTTPS. If you point it at an internal endpoint with a private certificate authority, the trust store inside the container is the one that has to accept it, and that is a common source of a subscription that silently loads nothing.
AGPL-3.0, release cadence, and the build story
The licence is AGPL-3.0, which is the part of this project most likely to need a decision before adoption rather than after. AGPL is a strong copyleft licence, and its network clause is the reason it is chosen or rejected in practice: the obligations it imposes reach to software offered to users over a network, which is exactly the shape of a monitoring service. Whether that affects you depends on how you distribute and whether you modify the code, so treat it as a question for your own counsel rather than something this article can settle.
On the engineering side the project is in good order. The repository is not archived, the last push was on 2026-09-10, and the release history shows v1.2.4 on 2026-03-15, v1.3.0 on 2026-06-28 and v1.3.1 on 2026-07-01. That is a steady pace of point releases on a 1.x version line, which usually means additive changes rather than breaking ones.
The release process itself is visible in the tree. There is a .goreleaser.yaml for building published binaries, a GitHub Actions workflow named build-publish.yml referenced by the badges, a Dockerfile, and a SECURITY.md plus a CODE_OF_CONDUCT.md and CONTRIBUTING.md. The dependency on xray-core is the one to watch on upgrade: the pinned version in go.mod is a pseudo-version tied to a specific commit, and a core update can change behaviour underneath a checker that was working fine, so a version bump is worth testing against your own node list rather than applying blind.
Editorial conclusion
Adopt Xray Checker when you operate Xray based infrastructure and already have Prometheus in place, and when you can supply nodes through a subscription URL or share links. Skip it if you are an end user looking for a client, if you need to test protocols other than VLESS, VMess, Trojan and Shadowsocks, or if AGPL-3.0 does not fit your distribution model. Verify first that the subscription URL returns something the loader understands, since a silently empty node list produces a healthy-looking exporter with nothing to report.
Frequently asked questions
What does Xray Checker actually test?
It monitors Xray proxy servers running VLESS, VMess, Trojan and Shadowsocks protocols, testing connections automatically through Xray Core. The output is availability information: metrics for Prometheus, REST API endpoints and a web interface, rather than a throughput or latency assessment.
How do I run Xray Checker with Docker?
Run the published image with the subscription URL in the environment and port 2112 published, for example docker run -d -e SUBSCRIPTION_URL=https://your-subscription-url/sub -p 2112:2112 kutovoys/xray-checker. A Docker Compose service with the same environment variable and port mapping is also documented.
What configuration formats can Xray Checker load?
The documented options are URL subscriptions in base64 or JSON form, share links in vless://, vmess://, trojan:// and ss:// form, JSON configuration files, and folders of configurations. Multiple subscriptions are supported and updates are fetched automatically.
Can I integrate Xray Checker with Prometheus and Uptime Kuma?
Yes. It exports Prometheus metrics with Pushgateway support, exposes a REST API documented with OpenAPI and Swagger, and provides endpoints aimed at monitoring system integration, with Uptime Kuma named in the feature list. Basic Auth protection is available for the metrics and web interface.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/kutovoys-xray-checker)Was this useful?