Introduction
As a self-hosting enthusiast, I have a home infrastructure:
Orange Pi—a media server;
Synology—a file dump;
Neptune 4—a 3D printer with a web interface and a camera feed.
And I'd like to have secure remote access to it via my phone and PC, while also having internet access from outside of Russia.
I used to use OpenVPN for these purposes, but it's no longer reliable. So I started studying the documentation for an excellent tool from our Chinese comrades—Xray!
What you'll need:
A server with an external IP and the infrastructure. In my case, it's an Orange Pi, hereinafter—
BridgeThe server you want to access—
ServerA server outside of Russia for internet access. Hereinafter—
ProxyA client of your choice. Hereinafter—
ClientClient and server on Linux—Xray-core, which can be installed via the official Xray installation script
Client on Android—v2rayNG
You can find more clients in the Xray-core repository
We'll use the VLESS-TCP-XTLS-Vision-REALITY configuration file as a base and start reading the Xray documentation
Routing happens on the client. If the client accesses the xray.com domain, for example, we direct the traffic to the Bridge, and for all other connections—to the Proxy. The Bridge then directs the traffic to the Server if the client accessed server.xray.com.
It looks like this:

The Xray configuration file is located at
/usr/local/etc/xray/config.json, and after each change to this file, the service must be restarted viasystemctl restart xray.service
Installation
Install Xray on the
BridgeandProxy:
bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install
Open port
443on theBridgeandProxy. For example, usingufw:
ufw allow 443
Generate server keys on the
BridgeorProxy:
xray x25519
The private key is added to the Xray server's configuration file, and the public key—to the client's config
Generate a
UUIDfor each client and come up with ashortIdfor it:
xray uuid
The
UUIDandshortIdare added to both the server and client configs
shortIdmust be a hex number no longer than 16 characters and with a length that is a multiple of 2, for example,a0,b1,ff
Add the private key,
UUID,shortId, and the server hostname you will use to connect to theBridge's configuration file at/usr/local/etc/xray/config.json:
`/usr/local/etc/xray/config.json`
{ "log": { "loglevel": "debug" }, "inbounds": [Add to the file { "tag": "external", "port": 443, "protocol": "vless", "settings": { "clients": [ { "id": "client_uuid_0", // run `xray uuid` to generate "flow": "xtls-rprx-vision" }, { "id": "client_uuid_1", "flow": "xtls-rprx-vision" } ], "decryption": "none" }, "streamSettings": { "network": "tcp", "security": "reality", "realitySettings": { "dest": "google.com:443", // You can also use `1.1.1.1:443` as dest "serverNames": [ "google.com" // If you use `1.1.1.1:443` as dest, then you can leave `serverNames` empty, it is a possible ways to bypass Iran's internet speed restrictions. ], "privateKey": "bridge_privateKey", // run `xray x25519` to generate. Public and private keys need to be corresponding. "shortIds": [ // Required, list of shortIds available to clients, can be used to distinguish different clients "client_shortId_0", // If this item exists, client shortId can be empty "client_shortId_1", "0123456789abcdef" // 0 to f, length is a multiple of 2, maximum length is 16 ] } }, "sniffing": { "enabled": true, "destOverride": [ "http", "tls", "quic" ], "routeOnly": true } } ], "outbounds": [ { "tag": "out", "protocol": "freedom" }, { "tag": "server", "protocol": "freedom", "settings": { "redirect": "server_lan_ip:0" // Forward all traffic to web server } } ], "routing": { "rules": [ { "type": "field", "domain": [ "server.xray.com" ], "outboundTag": "server" } ] } }
For the
Proxy, it's a bit simpler—just add the private key,UUID, andshortId:
spoiler
{ "log": { "loglevel": "debug" }, "inbounds": [ { "tag": "proxy", "port": 443, "protocol": "vless", "settings": { "clients": [ { "id": "client_uuid_0", // run `xray uuid` to generate "flow": "xtls-rprx-vision" }, { "id": "client_uuid_1", "flow": "xtls-rprx-vision" } ], "decryption": "none" }, "streamSettings": { "network": "tcp", "security": "reality", "realitySettings": { "dest": "google.com:443", // You can also use `1.1.1.1:443` as dest "serverNames": [ "google.com" // If you use `1.1.1.1:443` as dest, then you can leave `serverNames` empty, it is a possible ways to bypass Iran's internet speed restrictions. ], "privateKey": "proxy_privateKey", // run `xray x25519` to generate. Public and private keys need to be corresponding. "shortIds": [ // Required, list of shortIds available to clients, can be used to distinguish different clients "client_shortId_0", // If this item exists, client shortId can be empty "client_shortId_1", "0123456789abcdef" // 0 to f, length is a multiple of 2, maximum length is 16 ] } }, "sniffing": { "enabled": true, "destOverride": [ "http", "tls", "quic" ], "routeOnly": true } } ], "outbounds": [ {Add to the file "protocol": "freedom", "tag": "direct" } ] }
Restart the
xrayservice on theBridgeandProxy:
systemctl restart xray.service
Connecting with a Client
The configuration file is common for all clients.
Add the UUID, shortId, the Proxy and Bridge hostnames or IPs, and the domain to which you will redirect traffic to the configuration file:
spoiler
{ "log": { "loglevel": "debug" }, "routing": { "rules": [ { "type": "field", "domain": [ "xray.com" ], "outboundTag": "bridge" } ] }, "inbounds": [ { "listen": "127.0.0.1", "port": 10808, "protocol": "socks", "settings": { "udp": true }, "sniffing": { "enabled": true, "destOverride": [Add to the file "http", "tls", "quic" ], "routeOnly": true } } ], "outbounds": [ { "protocol": "vless", "settings": { "vnext": [ { "address": "proxy_hostname_or_ip", "port": 443, "users": [ { "id": "client_uuid_0", // Needs to match server side "encryption": "none", "flow": "xtls-rprx-vision" } ] } ] }, "streamSettings": { "network": "tcp", "security": "reality", "realitySettings": { "fingerprint": "chrome", "serverName": "google.com", // If your dest is `1.1.1.1:443`, then leave it empty "publicKey": "proxy_publicKey", // run `xray x25519` to generate. Public and private keys need to be corresponding. "spiderX": "", // If your dest is `1.1.1.1:443`, then you can fill it with `/dns-query/` or just leave it empty "shortId": "client_shortId_0" // Required } }, "tag": "proxy" }, { "protocol": "vless", "settings": { "vnext": [ { "address": "bridge_hostname_or_ip", "port": 443, "users": [ { "id": "client_uuid_0", // Needs to match server side "encryption": "none", "flow": "xtls-rprx-vision" } ] } ] }, "streamSettings": { "network": "tcp", "security": "reality", "realitySettings": { "fingerprint": "chrome", "serverName": "google.com", // If your dest is `1.1.1.1:443`, then leave it empty "publicKey": "bridge_publicKey", // run `xray x25519` to generate. Public and private keys need to be corresponding. "spiderX": "", // If your dest is `1.1.1.1:443`, then you can fill it with `/dns-query/` or just leave it empty "shortId": "client_shortId_0" // Required } }, "tag": "bridge" } ] }
Linux
Install Xray:
bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install
Write the configuration file to
/usr/local/etc/xray/config.jsonRestart the service:
systemctl restart xray.service
A local SOCKS5 proxy is now running on the client, which you can connect to through a browser. For example, in Firefox:
Settings->Network Settings->Settings->Manual proxy configuration:
SOCKS Host: 127.0.0.1 Port: 10808
Check the SOCKS v5 option
Android
Install v2rayNG
Upload the configuration file to your phone
Add the configuration file in the app via
Custom config->Import custom config from locallyTurn it on
You can choose which apps to route through Xray via
Settings->VPN Settings->Per-app proxy
Conclusion
Now we have access to our infrastructure by domain name and a normal internet connection.
As a bonus:
You can connect to the Server via SSH through Xray. In a single line:
ssh root@server.xray.com -o "ProxyCommand=nc -X connect -x 127.0.0.1:10808 %h %p"
Or add the following to ~/.ssh/config:
Host server Hostname server.xray.com User root ProxyCommand nc -X 5 -x 127.0.0.1:10808 %h %p ServerAliveInterval 10