xray-core as a Local SOCKS Gateway for Scrapers
For scraping, the useful shape of a VLESS line is not a VPN client with a connect button. It is a small daemon on the scraping host that turns each line into a local SOCKS5 port, so every worker, container and library talks to 127.0.0.1 and never sees a credential. That is what xray-core does on its own, with one JSON file. This guide builds that config from the link in your WeProx dashboard, shows how to fan it out to several lines, and gives the client snippets for Python requests, Scrapy and Playwright.
Read the link
In the WeProx dashboard, open My proxies and copy the VLESS / Xray row from the line. It is a URL with a fixed shape: the part between vless:// and the at sign is your user id, then the host and port, then query parameters. The ones that matter are security, which is reality on our lines, sni, pbk, sid, fp and flow. Everything below maps those onto Xray's outbound fields. VLESS is available on our server-based lines; tick VLESS / Xray in the filters when ordering.
Two things are worth knowing before you build on it. The id in the link is minted by the server for your line, and it is replaced whenever the line is moved to another location or its modem is switched, so a config copied into a repository will go stale after those events; read the link from the dashboard at deploy time or keep it in a secret you can rotate. And the tunnel terminates on our server, not on the carrier, which is why rotation never disturbs it: the modem behind the tunnel takes a new address and the next request simply exits on it.
Install the core
Grab the release for your platform, or use the install script on a Linux host. Both put a single static binary on the machine; there are no runtime dependencies.
# Linux
bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install
# macOS
brew install xray
One line, one local port
Replace HOST, PORT, UUID, SNI, PBK and SID with the values from your link. The inbound listens on 127.0.0.1 only, so nothing outside the box can reach it.
The socks inbound with udp enabled lets tools that resolve DNS remotely do so through the line. The http protocol is also available as an inbound if a library only speaks HTTP proxies; add a second inbound on another port with protocol set to http and route it to the same outbound. Keep loglevel at warning in production so the log stays readable and only errors and rejected handshakes appear in it.
{
"log": {"loglevel": "warning"},
"inbounds": [
{"tag": "in-1", "listen": "127.0.0.1", "port": 1081,
"protocol": "socks", "settings": {"udp": true}}
],
"outbounds": [
{"tag": "line-1", "protocol": "vless",
"settings": {"vnext": [{"address": "HOST", "port": PORT,
"users": [{"id": "UUID", "encryption": "none", "flow": "xtls-rprx-vision"}]}]},
"streamSettings": {"network": "tcp", "security": "reality",
"realitySettings": {"serverName": "SNI", "fingerprint": "chrome",
"publicKey": "PBK", "shortId": "SID"}}}
]
}
xray run -c config.json
curl -x socks5h://127.0.0.1:1081 https://api.ipify.org
Several lines, one process
Add one inbound and one outbound per line, then a routing block that ties each inbound tag to its outbound tag. Port 1081 goes to line one, 1082 to line two, and so on. Your scraper picks a line by picking a port, which makes per-line concurrency limits and per-line rotation trivial to reason about.
Two conventions make a multi-line config easier to live with. Name every inbound and outbound tag after the line's dashboard note rather than a number, so a log line about line-houston-2 means something at three in the morning. And keep one config file per host rather than one per line, so a restart brings every tunnel back in one step and the routing rules are in a single place where a missing or duplicated rule is obvious.
"routing": {"rules": [
{"type": "field", "inboundTag": ["in-1"], "outboundTag": "line-1"},
{"type": "field", "inboundTag": ["in-2"], "outboundTag": "line-2"}
]}
Pointing the tools at it
Use socks5h rather than socks5 in Python so DNS is resolved through the line and the target sees a carrier-side lookup. In Docker, run xray as its own service on the compose network and point workers at its service name instead of 127.0.0.1, with the inbound listening on 0.0.0.0 inside that private network only.
Concurrency is per line, not per port. If a line allows a certain number of simultaneous connections, every worker on that port shares them, so size the worker pool for the line rather than for the machine. A pool that opens more connections than the line permits sees the extra ones refused at the modem, which shows up in your logs as connection errors from the proxy rather than as slow responses from the target.
# Python requests
proxies = {"http": "socks5h://127.0.0.1:1081", "https": "socks5h://127.0.0.1:1081"}
requests.get(url, proxies=proxies, timeout=30)
# Scrapy: set per request
request.meta["proxy"] = "socks5h://127.0.0.1:1081"
# Playwright
browser = p.chromium.launch(proxy={"server": "socks5://127.0.0.1:1081"})
Rotation, restarts and failures
- Rotation is unchanged: call the line's rotation link or the API between batches. The tunnel stays up; only the modem's carrier IP changes. Retry the request that was in flight.
- If a line is moved or its modem switched, the server issues a new user id and xray logs an invalid request user id error. Copy the current link and restart xray.
- Run xray under systemd or supervisord so it comes back after a crash or reboot. Its exit codes are honest and its log says which outbound failed.
- Keep the host clock synced. REALITY checks real certificates and a drifted clock fails every handshake at once.
Frequently asked
Why use VLESS instead of the SOCKS5 login for scraping?
Credentials never leave the box, every worker gets a single local port, and the connection to the modem is encrypted end to end. The exit IP and rotation are identical.
Can the local port be shared across a fleet of workers?
Yes, within the line's connection limit. Bind the inbound to the private network address and let the workers reach it there.
Does xray add latency?
The Vision flow used on our lines is designed to be cheap; the mobile network round trip dominates. Measure it with your own requests rather than trusting anyone's number.