thejohnd0e/VLESS-to-HTTP
thejohnd0e/VLESS-to-HTTP has 30 GitHub stars and 7 forks. GitHot measured 0 stars in 24 hours. Last checked 2026-11-15 05:22 UTC. Last push 2026-11-12.
What you can do
- VLESS + Reality client (Xray-core)
- Supports tcp and xhttp transports
- HTTP proxy inbound (works for HTTP and HTTPS via CONNECT)
- SOCKS5 proxy inbound
Measured star growth
- in 24h
- 0
- in 7 days
- Collecting history
- in 15 days
- Collecting history
- in 1 month
- Collecting history
Net star changes over overlapping periods, not daily totals. Missing measurements are left blank. Stars measure attention, not software quality.
About
A lightweight Dockerized **HTTP/SOCKS5 proxy** that forwards traffic through a **VLESS + Reality** server.
Developer ToolsREADME.md
OriginalVLESS-to-HTTP/SOCKS5 proxy
A lightweight Dockerized HTTP/HTTPS + SOCKS5 proxy that forwards traffic through a VLESS + Reality server.
Designed for simplicity: paste your VLESS link into vless.conf, run Docker, and you're done.
✨ Features
- VLESS + Reality client (Xray-core)
- Supports
tcpandxhttptransports - HTTP proxy inbound (works for HTTP and HTTPS via CONNECT)
- SOCKS5 proxy inbound
- Auto-generated
config.json; secrets stay out of the logs (optional masked dump withPRINT_CONFIG=1) - Optional login/password for both proxies (
PROXY_USER/PROXY_PASS) - Several links in
vless.conf= automatic failover (Xray observatory + balancer, no restarts) - Docker healthcheck that makes a real request through the tunnel
- Runs as a non-root user
- Minimal footprint, no host dependencies besides Docker
- Default host ports: 9000 (HTTP/HTTPS) and 1080 (SOCKS5) on all interfaces (shared with the whole LAN), configurable in
.env
Related Projects
These projects complement each other: the kits set up the servers, and the proxy containers bring a tunnel to your local network as a plain HTTP/SOCKS5 proxy.
- xray-vps-kit — installer, client manager and updater for an
Xray VLESS + REALITY + Vision server on your VPS.
xray-client show NAMEprints thevless://link you paste intovless.confhere, so the server and this proxy work together out of the box. - awg-vps-kit — one-shot AmneziaWG (UDP) server installer and client manager for Debian/Ubuntu. Use it next to the VLESS server when you want a UDP tunnel as well; the two are independent and can run on the same VPS.
- AmneziaWG-to-Proxy — the same idea as this project for AmneziaWG: a container that brings up an AmneziaWG tunnel and exposes it as an HTTP/SOCKS5 proxy. VLESS-to-HTTP does this for VLESS + REALITY.
📁 Project Layout
VLESS-to-HTTP/
├── docker-compose.yml # docker compose service
├── Dockerfile # image build (CI publishes it to ghcr.io; also usable locally)
├── entrypoint.sh # parses vless.conf → generates config.json
├── healthcheck.sh # Docker healthcheck: a request through the tunnel
├── .env.example # optional settings: bind address, ports, login, log level, failover
├── tests/run.sh # parser tests (synthetic links, Xray stubbed)
├── tests/e2e.sh # end-to-end test against a throwaway local server (CI)
└── vless.conf # your VLESS Reality link(s), one per line
✅ Requirements
- Docker & Docker Compose
docker --version docker compose version
⚙️ Configure
Edit vless.conf and paste your full VLESS URL in one line:
TCP example:
vless://UUID@HOST:PORT?security=reality&encryption=none&pbk=PUBLIC_KEY&fp=fingerprint&sni=servername&sid=shortid&spx=/&flow=xtls-rprx-vision
XHTTP example:
vless://UUID@HOST:PORT?security=reality&encryption=none&type=xhttp&path=%2Fmy-path&host=example.com&sni=example.com&pbk=PUBLIC_KEY&sid=SHORT_ID&fp=chrome&mode=auto
Supported link parameters:
security=reality(the only supported security; may be omitted)pbk,sni(required),sid(may be empty),fp(defaultchrome),spx(default/),pqv,flowencryption(defaultnone; a VLESS Encryption client string is passed to Xray as is)type=tcp/rawortype=xhttp(tcpis the default if omitted)- For
xhttp:pathis required;host,modeandextra(URL-encoded JSON object) are optional - The server may be a hostname, an IPv4 address or an IPv6 address in brackets:
@[2001:db8::1]:443 - Values may be percent-encoded (
%2F,%3F, ...)
Example:
vless://[email protected]:443?security=reality&encryption=none&pbk=6ECfTRNxRBiv7GLIIwOhwlkDs9NyYoZ7lHZrWeU1Q&fp=chrome&sni=github.com&sid=c8aa6a68a476c885&spx=/&flow=xtls-rprx-vision
Tip: each link must be on one line. Every line that starts with
vless://is used; other lines (e.g.# comments) are ignored. A#nameafter a link is shown in the startup log.
Several links: automatic failover
Put several links into vless.conf, one per line (e.g. two servers, or TCP and XHTTP to the same server):
# main server
vless://[email protected]:443?security=reality&pbk=...&sni=...&sid=...&flow=xtls-rprx-vision#main
# backup
vless://[email protected]:443?security=reality&pbk=...&sni=...&sid=...&type=xhttp&path=%2Fx#backup
Xray then probes every link through its tunnel (PROBE_URL, every PROBE_INTERVAL) and sends
traffic over a working one; the container is not restarted. With FAILOVER_STRATEGY=leastPing (default) the
fastest working link is used, so a dead link is skipped after its next failed probe and is used again
once it answers. random and roundRobin spread connections over the working links.
If every link is down, traffic fails (it never goes out directly) and the healthcheck turns unhealthy.
The probes are small regular requests to
PROBE_URLthrough each link. A very shortPROBE_INTERVALproduces a noticeable periodic pattern; the default1mis a reasonable trade-off.
🚀 Run
docker compose up -d
This pulls the prebuilt image ghcr.io/thejohnd0e/vless-to-http:latest; if it cannot be pulled, Docker
builds the image from the Dockerfile instead. Only docker-compose.yml and vless.conf are needed
to run the prebuilt image.
Stop and start:
docker compose stop # stop, keep the container
docker compose start # start it again
docker compose down # stop and remove the container
Logs (a short startup summary without the UUID or keys, then Xray warnings and errors):
docker logs -f vless-to-http
Logs are rotated (3 × 10 MB).
By default:
- HTTP/HTTPS proxy: http://HOST:9000
- SOCKS5 proxy: socks5://HOST:1080
HOST is the LAN address of the machine running the container (or 127.0.0.1 on that machine itself):
every device in your network can point its proxy settings there.
Health
The image has a Docker healthcheck that makes a real request to PROBE_URL through the tunnel every
minute (through the container's own HTTP proxy, with the login if one is set), so healthy means traffic
actually passes, not just that the port is open:
docker ps # STATUS shows (healthy) / (unhealthy)
docker inspect --format '{{json .State.Health}}' vless-to-http
docker exec vless-to-http /app/healthcheck.sh # run it now
Docker itself does not restart an unhealthy container; use the status for monitoring or with a tool such
as autoheal. With several links Xray already switches to a working link on its own.
🔐 Settings and optional login
Optional settings go into .env next to docker-compose.yml (cp .env.example .env):
| Variable | Default | Meaning |
|---|---|---|
BIND_ADDR |
empty | Host address the ports are published on: empty = all interfaces (IPv4 and IPv6), a LAN address = that network only, 127.0.0.1 = this machine only |
HTTP_PORT / SOCKS_PORT |
9000 / 1080 |
Host ports |
PROXY_USER / PROXY_PASS |
empty | Login for both proxies (set both or neither) |
LOG_LEVEL |
warning |
debug, info, warning, error, none. debug/info also log every visited destination |
PRINT_CONFIG |
0 |
1 prints the generated config.json at startup with UUID, keys and password masked |
FAILOVER_STRATEGY |
leastPing |
With several links: leastPing (fastest working), random, roundRobin |
PROBE_URL |
https://www.gstatic.com/generate_204 |
Requested through the tunnel by the failover probes and the healthcheck; must answer 2xx/3xx |
PROBE_INTERVAL |
1m |
Pause between failover probe rounds (30s, 1m, 5m, ...) |
HEALTH_TIMEOUT |
10 |
Seconds the Docker healthcheck request may take; raise it on a slow tunnel |
COMPOSE_FILE |
not set | docker-compose.yml:docker-compose.host.yml = host network mode for UDP, see below |
IMAGE_TAG |
latest |
Image tag, see "Versions and updates" |
Without a login, any device that can reach the ports can use the proxy, which is what you want in a home
LAN. If the host is also reachable from untrusted networks (a public IP, a guest Wi-Fi), set a login or
restrict BIND_ADDR:
PROXY_USER=me
PROXY_PASS=a-long-random-password
then docker compose up -d. Clients use http://me:PASSWORD@HOST:9000 or socks5://me:PASSWORD@HOST:1080.
📞 UDP (Telegram calls, games, QUIC) — host network mode
UDP works only through SOCKS5 (HTTP proxies carry TCP only), and only in host network mode: for every UDP session Xray hands the client a new random port, and Docker's port publishing cannot forward those. In the default mode TCP works for every client, UDP does not.
Host network mode (Linux only; on Docker Desktop for Windows/macOS LAN devices cannot reach it): add to .env
COMPOSE_FILE=docker-compose.yml:docker-compose.host.yml
and recreate the container: docker compose up -d. Then:
- Xray listens directly on the host:
HTTP_PORT(default 9000) andSOCKS_PORT(1080) onBIND_ADDR(default all IPv4 interfaces), nothing else. Pick any free ports in.env. A host firewall must allow TCP and UDP toSOCKS_PORTand UDP to high ports from the LAN. - In Telegram (mobile: Settings → Data and Storage → Proxy; desktop: Settings → Advanced → Connection type)
add a SOCKS5 proxy
HOST:1080(and the login if set) and enable Use proxy for calls. - If UDP still fails on a host with several addresses, set
BIND_ADDRto the host's LAN address. - Needs Docker Compose 2.24.4 or newer (
docker compose version).
UDP to port 443 (QUIC) is not sent through a Vision (flow=xtls-rprx-vision) link on purpose; browsers then
use HTTPS over TCP. Other UDP (calls, DNS, games) is carried.
🧪 Test
HTTP proxy (HTTPS target via CONNECT):
curl -x http://127.0.0.1:9000 https://api.ipify.org -m 10 -v
Expected: your VLESS server's egress IP.
Test plain HTTP (no TLS):
curl -x http://127.0.0.1:9000 http://neverssl.com -m 10 -v
Test SOCKS5:
curl --socks5-hostname 127.0.0.1:1080 https://api.ipify.org -m 10 -v
With a login: curl -x http://me:[email protected]:9000 ... / curl --socks5-hostname 127.0.0.1:1080 --proxy-user me:PASSWORD ....
Parser tests (needs sh and jq, no Docker, no real link): sh tests/run.sh.
End-to-end test (needs Docker; starts a throwaway local server with generated keys): bash tests/e2e.sh IMAGE.
🔄 Update / Change server
- Edit
vless.conf(add, remove or replace links) - Restart (the links are read when the container starts):
docker compose restart
🏷️ Versions and updates
Releases are tagged vX.Y.Z (Releases, with the
list of changes). CI publishes linux/amd64 and linux/arm64 images to ghcr.io/thejohnd0e/vless-to-http:
| Tag | What it is |
|---|---|
latest |
Newest release with the current stable Xray-core (default) |
1, 1.0 |
Newest release in that line |
1.0.0 |
That release, rebuilt with each new Xray-core and weekly (Alpine updates) |
1.0.0-xray26.10.31 |
That release with exactly that core; never changes, use it to pin or roll back |
26.10.31 |
Newest release with that core |
edge |
Current master, not a release |
The newest release is rebuilt daily when a new Xray-core is out and weekly anyway; an image is published only after the tests pass. Update:
docker compose pull
docker compose up -d
Pin a version (or roll back) with IMAGE_TAG in .env, e.g. IMAGE_TAG=1.0.0-xray26.10.31, then the same
two commands. The version is shown in the first log line (VLESS-to-HTTP 1.0.0: ...).
docker-compose.yml still has build: ., so it builds locally when the image cannot be pulled.
Build it yourself. The Dockerfile downloads the latest Xray-core when it is built and verifies
the archive's SHA256 from the release's .dgst file. Docker reuses that cached layer afterwards, so a
plain docker compose up -d --build keeps the old core. To get the current release, rebuild without
the cache:
docker compose build --pull --no-cache
docker compose up -d
To pin a specific core: docker compose build --build-arg XRAY_VERSION=v26.10.21.
Do this when your server's Xray-core is updated: newer servers can refuse clients from older cores (see Troubleshooting).
🛠 Troubleshooting
- Container restarts with code 23
vless.confmissing, has novless://line, has empty/invalid mandatory parameters, or.envhas an invalid setting. TheERR:line in the log says which (andlink N:which link).
ERR: ... vless.conf is not readable by the container user- The container runs as a non-root user; make the file readable:
chmod 644 vless.conf.
- The container runs as a non-root user; make the file readable:
- Container is
unhealthy- No request passed through the tunnel. Check the server and the link(s);
docker exec vless-to-http /app/healthcheck.shprints the error. IfPROBE_URLis blocked on your server, set another one; on a slow tunnel raiseHEALTH_TIMEOUTin.env.
- No request passed through the tunnel. Check the server and the link(s);
- HTTP 407 / SOCKS authentication failed
PROXY_USER/PROXY_PASSare set; pass them in the client.
- HTTP returns 503
- Usually your VLESS parameters are incorrect (pbk/sid/sni/flow).
- Container exits with
ERR: empty PATH for xhttp transport- Add
path=...to the VLESS URL whentype=xhttp.
- Add
- TLS errors during CONNECT
- Verify
flow,fp(fingerprint),sni,pbk,sidmatch your server.
- Verify
- Log shows
REALITY: received real certificate (potential MITM or redirection)- The server did not accept the client. If
pbk/sid/sni/UUID are right, the cause is usually an old client core or an outdated fingerprint: current Xray servers reject a TLS ClientHello withoutX25519MLKEM768. Usefp=chrome(the default whenfpis omitted) and update the image withdocker compose pull && docker compose up -d(see "Versions and updates").
- The server did not accept the client. If
- To see the generated config, set
PRINT_CONFIG=1(andLOG_LEVEL=debugfor detailed Xray logs), restart, and look between===== GENERATED CONFIG (secrets masked) =====…====. Secrets are masked, but the log still shows your server address; check it before sharing.
📜 License
MIT