Fork of kutovoys/xray-checker with additional production-focused fixes and features.
xray-checker validates proxy availability (VLESS, VMess, Trojan, Shadowsocks) through Xray Core, exports Prometheus metrics, and provides a Web UI/API for monitoring.
Typical use cases:
- real-time VPN/proxy subscription monitoring;
- public status page for users;
- Prometheus scraping with optional Pushgateway push;
- integrations with Uptime Kuma and similar systems.
- Upstream:
https://github.com/kutovoys/xray-checker - This repository:
https://github.com/Sinicyn78/xray-checker - Core upstream behavior is preserved, with fork-specific improvements listed below.
- added concurrent check limiter:
PROXY_CHECK_CONCURRENCY; - added file logging:
LOG_FILE; - added remote subscription sources via API (add/remove/refresh URLs without manual file edits);
- improved
file://subscription directory handling and remote state location; - fixed proxy status mapping by
StableIDto prevent mismatch; - improved empty/unavailable subscription handling;
- improved fallback rendering in Web UI server tab;
- improved remote URL validation;
- normalized invalid stream security values.
- protocols:
vless,vmess,trojan,shadowsocks; - multiple subscription sources merged into one runtime set;
- supported sources:
- subscription URL;
- base64 string;
file://JSON file;folder://directory with JSON files;
- check methods:
ip(egress IP comparison);status(HTTP status endpoint);download(minimum download size verification);
- Prometheus metrics:
xray_proxy_status;xray_proxy_latency_ms;
- Web UI + REST API + Swagger (
/api/v1/docs); - public dashboard mode (
WEB_PUBLIC=true); - Basic Auth for API/metrics;
- UI customization with
WEB_CUSTOM_ASSETS_PATH; - Docker and native binary usage.
- Subscription sources are parsed into proxy configs.
xray_config.jsonis generated and Xray Core starts.- Checker validates each proxy (parallelized with concurrency limit).
- Status/latency are exposed via metrics and API.
- On subscription updates, config is rebuilt automatically.
docker run -d \
--name xray-checker \
-e SUBSCRIPTION_URL="https://example.com/subscription" \
-p 2112:2112 \
sinicyn/xray-checker:latestmkdir -p /opt/xray-checker/configs
chown -R 1000:1000 /opt/xray-checker
docker run -d \
--name xray-checker \
--restart unless-stopped \
--dns 9.9.9.9 --dns 1.1.1.1 --dns 8.8.8.8 \
--health-cmd='wget -qO- http://127.0.0.1:2112/api/v1/public/proxies >/dev/null || exit 1' \
--health-interval=30s --health-timeout=10s --health-retries=3 --health-start-period=40s \
--log-driver json-file --log-opt max-size=100m --log-opt max-file=1 \
-p 2112:2112 \
-v /opt/xray-checker/configs:/config/configs \
-e SUBSCRIPTION_URL="file:///config/configs/" \
-e PROXY_CHECK_METHOD="status" \
-e PROXY_STATUS_CHECK_URL="https://www.gstatic.com/generate_204" \
-e PROXY_CHECK_INTERVAL="300" \
-e SUBSCRIPTION_UPDATE_INTERVAL="300" \
-e PROXY_CHECK_CONCURRENCY="6" \
-e PROXY_TIMEOUT="50" \
-e LOG_FILE="/config/configs/xray-checker.log" \
-e WEB_TOP_BL_PATH="/api/v1/public/subscriptions/top-bl" \
sinicyn/xray-checker:latestIf your fork image is not published yet:
docker build -t xray-checker:local .
docker run -d \
--name xray-checker \
-e SUBSCRIPTION_URL="https://example.com/subscription" \
-p 2112:2112 \
xray-checker:localservices:
xray-checker:
image: sinicyn/xray-checker:latest
container_name: xray-checker
restart: unless-stopped
environment:
SUBSCRIPTION_URL: "https://example.com/subscription"
PROXY_CHECK_METHOD: "ip"
PROXY_CHECK_INTERVAL: "300"
PROXY_CHECK_CONCURRENCY: "16"
METRICS_PROTECTED: "true"
METRICS_USERNAME: "admin"
METRICS_PASSWORD: "change-me"
ports:
- "2112:2112"go build -o xray-checker .
./xray-checker --subscription-url="https://example.com/subscription"The app supports both CLI flags and environment variables. Only one field is required: subscription source.
SUBSCRIPTION_URL/--subscription-url
You can pass multiple sources:
- repeat
--subscription-urlmultiple times; - or use comma-separated values in
SUBSCRIPTION_URL.
SUBSCRIPTION_URL(--subscription-url) - config source(s)SUBSCRIPTION_UPDATE(--subscription-update, defaulttrue)SUBSCRIPTION_UPDATE_INTERVAL(--subscription-update-interval, default300)
PROXY_CHECK_INTERVAL(--proxy-check-interval, default300)PROXY_CHECK_CONCURRENCY(--proxy-check-concurrency, default16) - fork featurePROXY_CHECK_METHOD(--proxy-check-method,ip|status|download, defaultip)PROXY_IP_CHECK_URL(--proxy-ip-check-url)PROXY_STATUS_CHECK_URL(--proxy-status-check-url)PROXY_DOWNLOAD_URL(--proxy-download-url)PROXY_DOWNLOAD_TIMEOUT(--proxy-download-timeout, default60)PROXY_DOWNLOAD_MIN_SIZE(--proxy-download-min-size, default51200)PROXY_TIMEOUT(--proxy-timeout, default30)PROXY_RESOLVE_DOMAINS(--proxy-resolve-domains, defaultfalse)SIMULATE_LATENCY(--simulate-latency, defaulttrue)
XRAY_START_PORT(--xray-start-port, default10000)XRAY_LOG_LEVEL(--xray-log-level,debug|info|warning|error|none, defaultnone)
METRICS_HOST(--metrics-host, default0.0.0.0)METRICS_PORT(--metrics-port, default2112)METRICS_BASE_PATH(--metrics-base-path, default"")METRICS_PROTECTED(--metrics-protected, defaultfalse)METRICS_USERNAME(--metrics-username)METRICS_PASSWORD(--metrics-password)METRICS_INSTANCE(--metrics-instance)METRICS_PUSH_URL(--metrics-push-url, format:https://user:pass@host:port)
WEB_SHOW_DETAILS(--web-show-details, defaultfalse)WEB_PUBLIC(--web-public, defaultfalse)WEB_CUSTOM_ASSETS_PATH(--web-custom-assets-path)
Constraint: WEB_PUBLIC=true requires METRICS_PROTECTED=true.
LOG_LEVEL(--log-level,debug|info|warn|error|none, defaultinfo)LOG_FILE(--log-file) - fork featureRUN_ONCE(--run-once, defaultfalse)
Default bind: http://localhost:2112.
GET /health- healthcheckGET /metrics- Prometheus metricsGET /api/v1/status- aggregated statusGET /api/v1/proxies- proxy listGET /api/v1/proxies/{stableID}- proxy by IDGET /api/v1/public/proxies- public-safe proxy viewGET /api/v1/config- effective runtime configGET /api/v1/system/info- version/uptimeGET /api/v1/system/ip- current detected IPGET /api/v1/openapi.yaml- OpenAPI specGET /api/v1/docs- Swagger UI
Available when SUBSCRIPTION_URL uses a file:// source (file or directory).
GET /api/v1/subscriptions/remote- get remote source statePOST /api/v1/subscriptions/remote- add URL(s)DELETE /api/v1/subscriptions/remote?id=<id|url>- remove sourcePOST /api/v1/subscriptions/remote/refresh- force refreshPUT /api/v1/subscriptions/remote/interval- set refresh interval
Add source example:
curl -u admin:change-me \
-H "Content-Type: application/json" \
-X POST \
-d '{"urls":["https://example.com/sub1","https://example.com/sub2"]}' \
http://localhost:2112/api/v1/subscriptions/remoteip: lowest overhead, good default.status: stable HTTP-level availability check.download: validates real transfer path and throughput.
For large subscriptions, a typical baseline:
PROXY_CHECK_METHOD=ipPROXY_CHECK_INTERVAL=120..300PROXY_CHECK_CONCURRENCY=6..32(tune to CPU/network)
For unstable networks and large live sources, use:
PROXY_CHECK_METHOD=statusPROXY_STATUS_CHECK_URL=https://www.gstatic.com/generate_204PROXY_TIMEOUT=45..60PROXY_CHECK_INTERVAL=300SUBSCRIPTION_UPDATE_INTERVAL=300
Recommended in Docker: use engine log rotation (max-size/max-file) and keep one rotated file.
If you use LOG_FILE bind-mounted to host, add host-side logrotate (example in deploy/logrotate/xray-checker.conf).
Set WEB_CUSTOM_ASSETS_PATH and place files in that directory:
index.html- full template override;logo.svg- custom logo;favicon.ico- custom favicon;custom.css- extra style overrides;- any extra file is served at
/static/<filename>.
go test ./...
go build ./...Local debug run:
go run . \
--subscription-url="https://example.com/subscription" \
--log-level=debug- Most base ENV/API behavior remains upstream-compatible.
- Migration from upstream usually requires no config rewrite unless using fork-only features.
- For remote manager usage, ensure writable
file://storage path.
Recommended production baseline:
- set
METRICS_PROTECTED=true; - set custom
METRICS_USERNAMEandMETRICS_PASSWORD; - avoid
WEB_SHOW_DETAILSon public deployments; - place service behind TLS reverse proxy (Nginx/Caddy/Traefik).
Licensed under GNU GPLv3.
- Original project: kutovoys/xray-checker
- This repository maintains the fork and additional features.