Very simple set of scripts to use xray socks5 proxy as tun adapter and redirect all requests to specific ip list via socks5 proxy on router level.
I'm using it on Ubiquiti and OpenWRT routers, but i think it should work on any linux based platform with systemd/procd.
Download a snapshot of this repository onto the device where the proxy will run
and unpack it into /opt/tun-xray (the path the service files expect):
curl -L https://github.com/max619/tun-xray/archive/refs/heads/main.tar.gz -o tun-xray.tar.gz
tar xzf tun-xray.tar.gz
mv tun-xray-main /opt/tun-xray
cd /opt/tun-xrayThen run install.sh. It downloads the binaries and installs the services
interactively, detecting the CPU architecture and the init system (systemd or
procd) and creating the matching service symlinks:
./install.shIt asks:
- Client or Server.
- For a client, how the tun device is provided — xray tun inbound (preferred) or tun2socks.
and then downloads xray (plus tun2socks only when that mode is chosen) and symlinks the appropriate service files. Creating users and starting the services is still manual (see below).
The architecture is auto-detected; override it by passing the xray and tun2socks arch names explicitly (e.g. for MIPS, whose float ABI can't be detected):
./install.sh mips32 mips-hardfloatFirst decide which traffic should go through the proxy. There are two ways, and they can be combined.
List the domains to proxy in /opt/tun-xray/hosts.txt, one per line (a leading
dot also matches subdomains):
.openai.com
.chatgpt.com
Generate the dnsmasq config from that list:
./gen_dnsmasq_conf.shThis produces ipset.conf (for dnsmasq with ipset) and nfset.conf (for
dnsmasq with nftables). They make dnsmasq add the resolved IPs of those domains
to the ipset / nft set that setup_routing.sh matches on, so every address a
proxied domain resolves to is routed through the tunnel automatically — even
when it changes (CDNs, etc.). The set names are read from config (defaults:
XRAY_IPSET for ipset, inet xray freedom for nftables).
Include the generated file in your dnsmasq configuration and reload it. On
OpenWRT (which needs dnsmasq-full for ipset/nftset support):
# nftables backend
ln -s /opt/tun-xray/nfset.conf /etc/dnsmasq.d/nfset.conf
# or, for the ipset backend
ln -s /opt/tun-xray/ipset.conf /etc/dnsmasq.d/ipset.conf
/etc/init.d/dnsmasq restartIf you prefer to route fixed addresses, add them to /opt/tun-xray/iplist.txt,
one per line — both subnets and single IPs work:
220.181.174.0/24
220.181.174.32
setup_routing.sh seeds the set/routes from this file at startup. It is simpler
but only covers the exact addresses listed, so prefer the dnsmasq method for
anything that resolves to changing IPs.
You also choose how the tun device is provided. The xray tun inbound
mode is the preferred one — xray creates and owns the tun device itself, so only
a single service is needed. The older tun2socks mode is kept as an
alternative.
In this mode xray brings up the tun device, and the start_xray.sh wrapper
configures policy routing for it. No tun2socks process is involved.
Put an Xray config with a tun inbound into
/opt/tun-xray/xray_config.client.json, for example:
{
"protocol": "tun",
"settings": {
"name": "xray0",
"mtu": 1500,
"autoOutboundsInterface": "eth1"
}
}How it works:
xray.service/xray.initrunsstart_xray.sh xray_config.client.json.- The wrapper detects the
tuninbound, starts xray, and waits for the device (name, e.g.xray0) to come up and receive an IPv4 address. - It reads that address as
TUNIP, takesDEV/OUT_DEVfrom the xray config (name/autoOutboundsInterface), pulls the remaining routing parameters (SRC_DEV, marks, tables, …) fromconfig, and runssetup_routing.sh upto install the nftables (or iptables+ipset) rules and policy routing that steer theiplist.txtdestinations into the tunnel. - On stop, the wrapper's signal trap runs
setup_routing.sh downand stops xray (seeterm_signal/term_timeoutinxray.init).
Set at least SRC_DEV (your LAN interface) and, if needed, the marks/tables in
/opt/tun-xray/config. DEV, OUT_DEV and TUNIP are derived
automatically from the running tun device and do not need to be set here.
Run the installer and choose Client → xray tun inbound (this links only
the xray service), then create the user and start it:
./install.sh
useradd xray
systemctl start xray # or: /etc/init.d/xray startIn this mode xray only exposes a socks5 inbound (e.g. on 127.0.0.1:10808),
and a separate tun2socks process creates the tun device and forwards traffic
into that socks proxy. start_tun2socks.sh creates the device and delegates the
routing to setup_routing.sh.
Put an Xray config with a socks inbound into
/opt/tun-xray/xray_config.client.json, then run the installer and choose
Client → tun2socks (this links both the xray and tun2socks
services). Create the users and start both services:
./install.sh
useradd xray
useradd tun2socks
systemctl start xray && systemctl start tun2socks
# or: /etc/init.d/xray start && /etc/init.d/tun2socks startPut your Xray server config into /opt/tun-xray/xray_config.server.json, run the
installer and choose Server, then create the user and start it:
./install.sh
useradd xray
chown -R xray:xray /opt/tun-xray
systemctl start xray-serverOnly a systemd unit is provided for the server. On OpenWRT/procd the server config is not yet supported
You might need to allow forwarding in firewall. Replace tun0 below with your
tun device name — xray0 (the name from the xray config) in the preferred
mode, or tun0 (the DEV from config) in the tun2socks mode.
uci set firewall.proxy=zone
uci set firewall.proxy.name='proxy'
uci set firewall.proxy.input='ACCEPT'
uci set firewall.proxy.output='ACCEPT'
uci set firewall.proxy.forward='ACCEPT'
uci set firewall.proxy.masq='0'
uci add_list firewall.proxy.device='tun0'
uci add firewall forwarding
uci set firewall.@forwarding[-1].src='lan'
uci set firewall.@forwarding[-1].dest='proxy'
uci commit firewall
service firewall restart