JA3Proxy is an HTTP/SOCKS5 proxy that uses uTLS to create outbound TLS connections with configurable ClientHello fingerprints. It can be used to test how applications behave behind different browser-like TLS fingerprints, while keeping familiar proxy interfaces for clients.
- HTTP, HTTPS, and SOCKS5 proxy support on the same listen address.
- Customizable TLS ClientHello fingerprints through uTLS presets.
- Dynamic MITM certificates for HTTPS
CONNECTtraffic. - Automatic local CA generation when no certificate/key pair is provided.
- Optional SOCKS5 upstream proxy for both HTTP and HTTPS traffic.
- Docker and Docker Compose examples included.
For plain HTTP requests, JA3Proxy forwards the request directly. For HTTPS
CONNECT requests, it establishes a TLS connection to the upstream server using
the configured uTLS fingerprint, then serves a dynamically generated certificate
to the client using the local CA. SOCKS5 connections are accepted on the same
listen address: TLS streams use the same MITM/uTLS path, while non-TLS streams
are forwarded as plain TCP.
Because HTTPS traffic is intercepted, clients must either trust the generated CA certificate or explicitly skip certificate verification for testing.
Requirements:
- Go 1.24 or newer
makeif you want to use the provided Makefile
git clone https://github.com/lylemi/ja3proxy.git
cd ja3proxy
go build -o ja3proxy ./cmd/ja3proxy
./ja3proxy -port 8080 -client 360Browser -version 7.5The CLI source lives in cmd/ja3proxy.
Test the proxy:
curl -v -k --proxy http://127.0.0.1:8080 https://www.example.com
curl -v -k --proxy socks5h://127.0.0.1:8080 https://www.example.comThe first run creates credentials/cert.pem and credentials/key.pem if they
do not already exist.
mkdir -p credentials
docker run --rm \
-v ./credentials:/app/credentials \
-p 8080:8080 \
ghcr.io/lylemi/ja3proxy:latest \
-cert /app/credentials/cert.pem \
-key /app/credentials/key.pem \
-client 360Browser \
-version 7.5docker compose up -dSee compose.yaml for the full service definition.
Usage of ja3proxy:
-addr string
proxy listen host
-port string
proxy listen port (default "8080")
-cert string
proxy CA cert (default "credentials/cert.pem")
-key string
proxy CA key (default "credentials/key.pem")
-client string
utls client (default "Golang")
-version string
utls client version (default "0")
-fingerprint-config string
JSON file to hot-reload utls client/version
-upstream-tls-config string
JSON file with upstream TLS profiles
-upstream string
upstream proxy, e.g. 127.0.0.1:1080, socks5 only
-debug
enable debug
Example with a SOCKS5 upstream proxy:
./ja3proxy \
-port 8080 \
-client Chrome \
-version 106 \
-upstream socks5://127.0.0.1:1080The -upstream flag also accepts host:port, for example
127.0.0.1:1080. Only SOCKS5 upstream proxies are supported.
Use -upstream-tls-config when different upstream hosts need different outbound
TLS fingerprints. The flag loads a JSON file with a default upstream TLS profile
and optional host-specific routes:
{
"default": {
"protocol": "utls",
"client": "Chrome",
"version": "120"
},
"routes": [
{
"host": "*.gm.example.com",
"protocol": "utls",
"client": "360Browser",
"version": "7.5"
},
{
"host": "api.example.com",
"protocol": "utls",
"client": "Firefox",
"version": "105"
}
]
}Start the proxy with the profile file:
./ja3proxy -port 8080 -upstream-tls-config upstream-tls.jsonJA3Proxy uses the default profile when no route matches. If default is
omitted, unmatched hosts continue to use the global fingerprint from -client,
-version, or -fingerprint-config.
Each profile currently supports protocol: "utls" with the same client and
version values described in TLS fingerprints. tlcp is
intentionally not implemented yet, so tlcp profiles are not supported in this
version.
Route host values match the upstream destination host. Matching supports exact
hosts such as api.example.com and leading wildcard patterns such as
*.example.com.
This differs from -fingerprint-config: -fingerprint-config hot-reloads one
global uTLS client/version pair for all upstream hosts, while
-upstream-tls-config selects a profile by upstream host from the JSON file.
The existing -client, -version, and -fingerprint-config flags remain
backwards-compatible shortcuts for configuring one global uTLS fingerprint.
Use -fingerprint-config to load the uTLS fingerprint from a JSON file and
watch it for changes:
{
"client": "Chrome",
"version": "106"
}Start the proxy with the file:
./ja3proxy -port 8080 -fingerprint-config fingerprint.jsonWhen the file changes, JA3Proxy validates and reloads it. New HTTPS CONNECT
connections use the latest fingerprint; existing TLS tunnels keep the
fingerprint they were opened with. If a reload fails, the previous fingerprint
stays active and the error is logged.
JA3Proxy resolves global fingerprint settings and upstream TLS profiles to uTLS
ClientHello presets. With the global shortcut flags, JA3Proxy passes the
-client and -version values to uTLS. With -upstream-tls-config, each
matched profile supplies the client and version values. Supported presets
depend on the uTLS version used by this project. See the uTLS
ClientHelloID definitions
for the authoritative list.
Common presets:
| Client | Version |
|---|---|
| Golang | 0 |
| Firefox | 55, 56, 63, 99, 105 |
| Chrome | 58, 62, 70, 96, 102, 106 |
| iOS | 12.1, 13, 14 |
| Android | 11 |
| Edge | 85, 106 |
| Safari | 16.0 |
| 360Browser | 7.5 |
| QQBrowser | 11.1 |
The uTLS library is compiled into the JA3Proxy binary, so updating it requires a
rebuild. Dependabot is configured to open weekly pull requests for Go module
updates, including github.com/refraction-networking/utls. Those pull requests
run the Go CI workflow before they are merged.
To update manually:
go get github.com/refraction-networking/utls@latest
go mod tidy
go test ./...JA3Proxy needs a CA certificate and private key to generate per-host certificates for HTTPS interception.
- If both files exist, they are loaded from
-certand-key. - If neither file exists, JA3Proxy generates a new CA pair.
- If only one file exists, startup fails to avoid using a mismatched pair.
By default, generated CA files are written to credentials/cert.pem and
credentials/key.pem. If the configured paths include missing directories,
JA3Proxy creates them before writing the files.
For browser or application testing, import the generated CA certificate into the
client trust store. For one-off command-line checks, tools such as curl -k
can skip verification.
Run the test suite:
go test ./...Build release binaries with the Makefile:
makeThis creates Linux and Windows AMD64 binaries in the bin/ directory.
JA3Proxy performs TLS interception and can expose decrypted traffic to the machine running the proxy. Use it only in environments where you have permission to inspect the traffic. Protect generated CA private keys carefully and remove them from client trust stores when they are no longer needed.
Issues and pull requests are welcome. Please include a clear description, reproduction steps when reporting bugs, and tests for behavior changes when practical.
This project is licensed under the MIT License.