18230 / php-tuic-client
Pure PHP TUIC client with a local SOCKS5 proxy runtime backed by cloudflare/quiche FFI.
Requires
- php: ^8.2.4
- ext-curl: *
- ext-ffi: *
- ext-json: *
- ext-openssl: *
- ext-sockets: *
- react/event-loop: ^1.5
- symfony/console: ^7.3
- symfony/yaml: ^7.3
Requires (Dev)
- phpunit/phpunit: ^11.5
Suggests
- illuminate/support: Optional for Laravel service-provider integration.
- topthink/framework: Optional for ThinkPHP service-provider integration.
README
php-tuic-client is a pure PHP TUIC v5 client focused on one job: start a local socks5://127.0.0.1:1080 style proxy and relay it through a TUIC node.
The QUIC transport is provided by cloudflare/quiche through PHP FFI. The local accept loop, node parsing, CLI flow, and runtime control stay in PHP.
Scope
- TUIC v5 authentication
- local SOCKS5 server
- Clash-style YAML / JSON node parsing
- Windows, Linux, and macOS project support
- cross-platform startup scripts
doctorandrunCLI workflow- compatibility request helpers for framework projects, built on top of the same local SOCKS5 runtime
Not in scope right now:
- UDP relay
- HTTP proxy runtime
- multi-node scheduling
Requirements
- PHP
8.2.4+ ext-ffiext-jsonext-opensslext-sockets- a loadable
libquicheshared library
Install
composer require 18230/php-tuic-client
Official release tags vendor prebuilt libquiche binaries for:
windows-x64linux-x64macos-x64
That means a normal composer require from a tagged release can use the bundled shared library directly. If you install from dev-main or run on another architecture, build your own library and point QUICHE_LIB or --quiche-lib at it.
Build libquiche
Official releases already include prebuilt x64 libraries. Build manually only if you are developing locally, using dev-main, or targeting another architecture.
You need a shared quiche build with the ffi feature enabled.
Windows:
.\scripts\build-quiche.ps1
Linux / macOS:
./scripts/build-quiche.sh
If your library lives outside the default search locations, point QUICHE_LIB or --quiche-lib to the absolute path.
Quick Start
Validate runtime prerequisites:
php bin/tuic-client doctor --config=examples/node.example.yaml
The doctor command prints the detected native triplet and the library search order. On official release installs it should resolve the bundled file under resources/native/<platform>-<arch>/.
Start with inline YAML:
php bin/tuic-client \
--node="{ name: 'SG 01', type: tuic, server: your-tuic-server.example.com, port: 443, uuid: 11111111-1111-1111-1111-111111111111, password: your-password, alpn: [h3], disable-sni: false, reduce-rtt: false, udp-relay-mode: native, congestion-controller: bbr, skip-cert-verify: false, sni: your-tuic-server.example.com }" \
--listen=127.0.0.1:1080
Or start from a config file:
php bin/tuic-client --config=examples/node.example.yaml --listen=127.0.0.1:1080
Then point your tools at:
socks5://127.0.0.1:1080
For command-line tools, prefer socks5h:// so DNS resolution also goes through the proxy:
curl --proxy socks5h://127.0.0.1:1080 https://api.ipify.org?format=json
Examples:
<?php $ch = curl_init('https://api.ipify.org?format=json'); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_PROXY => '127.0.0.1:1080', CURLOPT_PROXYTYPE => CURLPROXY_SOCKS5_HOSTNAME, ]); echo curl_exec($ch); curl_close($ch);
Node Fields
Required TUIC node fields:
name: local display nametype: must betuicserver: remote TUIC server hostname or IPport: remote TUIC portuuid: TUIC user UUIDpassword: TUIC password / tokenalpn: usually[h3]sni: TLS server name
Supported optional fields:
skip-cert-verify: defaults tofalsedisable-sni: defaults tofalsereduce-rtt: defaults tofalseudp-relay-mode: parsed but UDP relay is not implemented yetcongestion-controller: typicallybbr
Minimal example:
proxies: - name: demo-tuic type: tuic server: example.com port: 443 uuid: 00000000-0000-4000-8000-000000000000 password: replace-with-your-password alpn: [h3] sni: example.com
CLI
Main options:
--node--config--node-name--listen--allow-ip--max-connections--connect-timeout--idle-timeout--handshake-timeout--status-file--status-interval--log-file--pid-file--quiche-lib--dry-run
Production-style example:
php bin/tuic-client \ --config=/opt/php-tuic-client/config/tuic.yaml \ --listen=127.0.0.1:1080 \ --allow-ip=127.0.0.1 \ --max-connections=2048 \ --connect-timeout=12 \ --idle-timeout=600 \ --handshake-timeout=20 \ --status-file=/opt/php-tuic-client/runtime/status.json \ --log-file=/opt/php-tuic-client/runtime/proxy.log \ --pid-file=/opt/php-tuic-client/runtime/proxy.pid
Node Example
proxies: - name: demo-tuic type: tuic server: example.com port: 443 uuid: 00000000-0000-4000-8000-000000000000 password: replace-with-your-password alpn: [h3] disable-sni: false reduce-rtt: false udp-relay-mode: native congestion-controller: bbr skip-cert-verify: false sni: example.com
Runtime Outputs
When you run the proxy in production, these files are the most useful:
log-file: human-readable runtime logstatus-file: JSON snapshot of listener, node, and counterspid-file: current process ID
The status-file includes counters such as:
accepted_connections_totalclosed_connections_totalhandshake_timeouts_totaltuic_auth_success_totaltuic_auth_failure_total
Production Notes
- Keep the SOCKS5 listener on loopback unless you truly need LAN access.
- Run
doctoragainst the exact PHP binary that will host the long-running process. - Official release tags already ship bundled x64 native libraries inside the Composer package.
- Production flags stay intentionally small and explicit:
allow-ip,max-connections,connect-timeout,idle-timeout,handshake-timeout,status-file,log-file, andpid-file. - If you deploy on another architecture, ship your own
libquichewith the same artifact and either place it under the matching triplet directory or setQUICHE_LIB. - Prefer Linux for long-running production workloads.
Troubleshooting
doctorfails before startup: Runphp bin/tuic-client doctor ...with the exact PHP binary you will use in production.ext-ffiis disabled: Enable FFI inphp.ini, then rerundoctor.libquichecannot be found: Use the tagged release package or pointQUICHE_LIB/--quiche-libat the absolute library path.- The process starts but local requests fail:
Check
log-fileandstatus-filefirst. Iftuic_auth_failure_totalis non-zero, verify node credentials, SNI, and TLS settings. - Windows / Linux / macOS mismatch: Make sure the packaged native library matches the current platform and architecture.
Framework Helpers
The package still ships TuicRequestClient and framework service providers for Laravel / ThinkPHP. These helpers are convenience layers built on top of the same local SOCKS5 runtime plus cURL. They are optional and not required if you only want the protocol-level local proxy.
More detail:
Testing
composer test
php bin/tuic-client --config=examples/node.example.yaml --dry-run
php bin/tuic-client doctor --config=examples/node.example.yaml
The release pipeline also runs a real-node end-to-end probe on ubuntu-22.04, windows-latest, and macos-15-intel using the packaged libquiche binaries and a local socks5://127.0.0.1:11084 listener.