Yuubin Proxy is a high-performance, lightweight multi-protocol proxy server written in Java. It leverages Virtual Threads (Project Loom) to handle concurrent connections using a "thread-per-connection" model.
While looking for a lightweight cross-platform proxy solution, drawing the best features from both Apache mod_proxy and Nginx, I was unable to find a solution that was both robust and lightweight. The introduction of Virtual Threads (Project Loom) in Java 21 provided the perfect foundation for building a high-performance, lightweight proxy tailored to my needs.
Beyond performance, portability is a primary objective. Java allows for seamless execution across diverse environments without the need to manage complex build pipelines or platform-specific binaries.
In Corporate environment, we often need to route all traffic through a parent proxy. Yuubin Proxy supports this with the upstreamProxy configuration. See Proxy Chaining in Corporate Environments for more details.
Yuubin Proxy supports proxy certificates. This is especially useful in environments where either Netskope, Zscaler or BlueCoat is used as a proxy. See Proxy Certificates for more details.
- Multi-Protocol Support:
- HTTP/HTTPS: Forward and reverse proxying with rule-based routing and header manipulation.
- HTTPS CONNECT: L4 TCP tunneling for encrypted traffic.
- SOCKS4/SOCKS4a: Simple TCP proxying with domain resolution support.
- SOCKS5: Advanced TCP proxying with username/password authentication.
- WebSockets: Full support for bidirectional WebSocket tunneling.
- Advanced Routing & Load Balancing:
- Host-Based Routing: Route requests based on the
Hostheader (Virtual Hosts). - Traffic Shaping: Per-route Rate Limiting (Token Bucket) to protect backends from floods.
- Load Balancing Strategies:
- Round-Robin: Distribute traffic evenly (default).
- IP Hash: Sticky sessions based on client IP for stateful backends.
- Health Checks: Automatic failover by periodically checking backend health status.
- Header Rewriting: Rewrites
Locationheaders in responses for seamless reverse proxying (ProxyPassReverse equivalent).
- Host-Based Routing: Route requests based on the
- Security First:
- DoS Protection: Strict I/O bounds on HTTP header parsing, line lengths, and SOCKS domains to prevent memory exhaustion (Out-of-Memory, or OOM) attacks.
- Constant-Time Auth: Password validation uses
MessageDigest.isEqualto mitigate timing side-channel attacks. - Modern TLS: Enforces
TLSv1.3and thePKCS12keystore format for secure, encrypted proxy endpoints. - Connection Limits: Configurable max concurrent connections and aggressive timeouts to thwart Slowloris attacks.
- Authentication Providers:
- YAML File: Standard user list in a YAML file.
- Kubernetes ConfigMap: Load credentials from a mounted directory (one file per user).
- Environment Variables: Inject users via strings like
user1:pass1,user2:pass2.
- Graceful Live Reload: Automatically detects changes to
application.ymland updates proxy settings, starting or stopping servers without an application restart.
Detailed technical documentation and configuration examples are available in the repository:
- Architecture Documentation: Deep dive into the system design, featuring ASCII request flow diagrams and UML class relationships.
- Configuration Examples: A collection of real-world setup scenarios including Load Balancing, API Gateway routing, and authenticated SOCKS5 proxies.
The proxy is configured via a YAML file. In the standard distribution, this is located at conf/application.yml.
proxies:
- name: main-http-proxy
port: 8080
type: HTTP
authEnabled: true
timeout: 60000 # Timeout in ms (default 60s)
maxRedirects: 3 # Max redirects to follow (default 0)
tlsEnabled: false # Set to true to enable TLSv1.3
# keystorePath: my-certs.p12 # Required if TLS is enabled
# keystorePassword: "secret-password"
rules:
- host: "api.example.com"
path: /v1
targets:
- http://backend-1:3000
- http://backend-2:3000
loadBalancing: IP_HASH # Sticky sessions (or ROUND_ROBIN)
rateLimit: 100.0 # 100 requests per second per IP
burst: 200 # Allow bursts up to 200
healthCheckPath: /health
healthCheckInterval: 5000
reverse: true
- path: /
target: http://localhost:8081
- name: socks5-proxy
port: 1080
type: SOCKS5
authEnabled: true
timeout: 30000
auth:
enabled: true
usersPath: users.yml # Resolved relative to conf/ or the working directory
# usersDirectory: /etc/proxy/users # Kubernetes ConfigMap mount (one file per user)
# usersEnv: YUUBIN_USERS # Environment variable (format: "u1:p1,u2:p2")
logging:
# Access logs go to EITHER console OR file (never both).
# Application logs (startup, shutdown) always print to console.
# %m = HTTP Method, %q = Query String, %r = Request path
format: '%h %l %u %t "%m %r%q" %>s %b'
logResponse: false
fileEnabled: true # true = file only, false = console only
filePath: "/var/log/yuubin-proxy"
fileName: "yuubin-proxy.log"
rotation: "DAILY" # Options: DAILY, WEEKLY, MONTHLY, SIZE
# maxSize: "100MB" # Max single file size. Enable if rotation is SIZE.
maxHistory: 30 # Max number of rotated logs to keep before purgingIf needed, for cloud-native deployments, Yuubin Proxy supports loading user credentials from a mounted directory (e.g., a Kubernetes ConfigMap or Secret):
- Create a ConfigMap where each key is a username and each value is the password.
- Mount it to
/app/auth/users. - Set
auth.usersDirectory: /app/auth/usersinapplication.yml. - Proxy will automatically load all files in that directory as user credentials.
For Linux users, the fastest and most integrated way to run Yuubin Proxy is via our standalone native packages. These do not require Java to be installed to run!
Installation:
Download the .deb (Ubuntu/Debian) or .rpm (RHEL/CentOS) from the GitHub Releases page:
sudo dpkg -i yuubin-proxy-*.deb
# OR
sudo rpm -i yuubin-proxy-*.rpmService Management:
Upon installation, a secure yuubin system user is created, and the service is automatically registered with systemd.
- Config Location: Edit your rules at
/etc/yuubin-proxy/application.yml - Log Location:
/var/log/yuubin-proxy/ - Start/Stop:
sudo systemctl start yuubin-proxy - Check Status:
sudo systemctl status yuubin-proxy
Reloading Configuration:
Yuubin Proxy supports Graceful Live Reload. If you modify /etc/yuubin-proxy/application.yml while the systemd service is actively running, the proxy will detect the file system change and automatically hot-reload the new rules within a few seconds without dropping active connections.
You only need to restart the service if you are upgrading the binary or need to force a hard JVM reboot:
sudo systemctl restart yuubin-proxyFor Windows users, download the standalone native binary yuubin-proxy-windows-latest.zip from the GitHub Releases page. Extract yuubin-proxy-windows-latest.exe to a permanent folder, for example C:\yuubin-proxy\.
Note
Windows SmartScreen: Since this is an unsigned open-source binary, Windows Defender SmartScreen may initially block execution. When prompted, click "More info" and then "Run anyway". Alternatively, right-click the .exe file, select Properties, check the Unblock box at the bottom, and click Apply.
To automatically start Yuubin Proxy in the background when you log into Windows:
- Press
Win + R, typeshell:startup, and press Enter. This opens your user's Startup folder. - Inside the folder, right-click and select New > Shortcut.
- Point the shortcut target to the executable and append the config flag, example:
"C:\yuubin-proxy\yuubin-proxy-windows-latest.exe" --config "C:\yuubin-proxy\application.yml" - (Optional) To hide the console window completely, you can create a small
.vbsscript instead:Save it asSet WshShell = CreateObject("WScript.Shell") WshShell.Run chr(34) & "C:\yuubin-proxy\yuubin-proxy-windows-latest.exe" & Chr(34) & " --config " & Chr(34) & "C:\yuubin-proxy\application.yml" & Chr(34), 0 Set WshShell = Nothing
yuubin-startup.vbsinside theshell:startupfolder.
For macOS users, download the standalone native binary yuubin-proxy-macos-latest.zip from the GitHub Releases page. Extract the yuubin-proxy-macos-latest executable to /usr/local/bin/yuubin-proxy.
Note
macOS Gatekeeper: As this is an unsigned binary, macOS will likely prevent it from running, stating the developer cannot be verified. To allow execution, remove the quarantine attribute by running this command in your terminal:
sudo xattr -d com.apple.quarantine /usr/local/bin/yuubin-proxyTo run Yuubin Proxy automatically in the background on macOS:
- Create a macOS Property List (plist) file in
~/Library/LaunchAgents/com.yuubin.proxy.plist:<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>com.yuubin.proxy</string> <key>ProgramArguments</key> <array> <string>/usr/local/bin/yuubin-proxy</string> <string>--config</string> <string>/path/to/your/application.yml</string> </array> <key>RunAtLoad</key> <true/> <key>KeepAlive</key> <true/> <key>StandardOutPath</key> <string>/tmp/yuubin-proxy.log</string> <key>StandardErrorPath</key> <string>/tmp/yuubin-proxy.err</string> </dict> </plist>
- Load the service into launchctl:
launchctl load ~/Library/LaunchAgents/com.yuubin.proxy.plist - The proxy will now start automatically in the background whenever you log in. To safely unload it, run
launchctl unload ~/Library/LaunchAgents/com.yuubin.proxy.plist.
The recommended way to deploy on traditional operating systems (Windows, macOS) or platforms requiring the JVM. These archives require Java 21+ and are attached to every tagged release.
Build from Source:
mvn clean packageThis generates target/yuubin-proxy-1.0.0-dist.tar.gz (and .zip), which contains a standard application layout:
yuubin-proxy/
├── bin/
│ ├── run.sh # Linux/MacOS launcher
│ └── run.bat # Windows launcher
├── conf/
│ ├── application.yml # Default proxy configuration
│ └── users.yml # Default user credentials
├── lib/
│ └── yuubin-proxy-1.0.0.jar # The compiled fat JAR
└── README.md
Run:
# Extract and enter the directory
tar -xzf yuubin-proxy-*-dist.tar.gz
cd yuubin-proxy-*
# Start the proxy (automatically uses conf/application.yml)
./bin/run.shYuubin Proxy is available as a multi-arch Docker image (amd64/arm64).
docker run -p 8080:8080 -p 1080:1080 \
-v $(pwd)/packaging/conf/application.yml:/etc/yuubin-proxy/application.yml \
ghcr.io/henrya/yuubin-proxy:latestTo build and run Yuubin Proxy locally using the provided docker-compose.yml, you must compile the Java artifact first:
# 1. Compile the proxy executable natively
mvn clean package
# 2. Build the Alpine Docker image and start the container
docker-compose -f docker/docker-compose.yml up -d --buildFor even faster startup times and a lower memory footprint, Yuubin Proxy can be compiled into a standalone native binary using GraalVM.
Build:
# Build the native binary using the 'native' profile
mvn clean package -PnativeThis produces a standalone yuubin-proxy binary in the target/ directory.
Run:
./target/yuubin-proxy --config conf/application.yml- Java 21 or higher.
- Maven 3.9+ (for building).
When running the JAR directly, or via the run.sh/run.bat scripts, you can override defaults:
| Option | Long Flag | Description |
|---|---|---|
-c |
--config |
Path to the YAML configuration file. |
-h |
--help |
Show this help message and exit. |
-V |
--version |
Print version information and exit. |
Usage:
# Using the provided script
./bin/run.sh --config custom-config.yml
# Or running the JAR directly
java -jar lib/yuubin-proxy-1.0.0.jar -c custom-config.ymlYuubin Proxy supports a live configuration refresh/reload mechanism while the application is running. You can type commands directly into the terminal:
reload: Manually triggers a configuration reload from the current config file.stop/exit/quit: Gracefully shuts down all proxy servers and exits the application.help: Lists available interactive commands.
Yuubin Proxy includes endpoints for monitoring and health checks:
- Endpoint:
http://localhost:9090(Configurable viaadmin.portandadmin.bindAddress) - Bind Address: Defaults to
127.0.0.1(loopback) for security. Setadmin.bindAddress: "0.0.0.0"for Kubernetes probes or remote scraping. /health: ReturnsOK(200) if the application is running./metrics: Exports real-time metrics in Prometheus format via Micrometer.
proxy.connections.active: Current number of open client connections.proxy.connections.total: Total number of connections accepted since startup.proxy.connections.errors: Total count of connection handling errors.proxy.http.requests.total: Total number of HTTP requests processed.proxy.traffic.bytes.sent: Total bytes sent to upstream targets.proxy.traffic.bytes.received: Total bytes received from upstream targets.
Yuubin Proxy can forward its traffic to another proxy server.
proxies:
- name: chained-proxy
port: 8080
type: HTTP
upstreamProxy:
host: "parent-proxy.com"
port: 3128
type: HTTP
username: "chained-user" # Optional
password: "secret-password" # OptionalBlock specific client IP addresses from connecting to your proxy.
globalBlacklist:
- 192.168.1.100
proxies:
- name: restricted-proxy
port: 1080
type: SOCKS5
blacklist:
- 10.0.0.50curl -x http://localhost:8080 -U admin:password123 http://www.google.comcurl --socks5-hostname localhost:1080 --proxy-user user:secret_pass http://www.google.comYuubin Proxy supports a Service Provider Interface (SPI extensions) for extending its capabilities without modifying the core.
To implement a custom proxy protocol (e.g., a proprietary binary protocol, gRPC, etc.):
- Implement the
com.yuubin.proxy.spi.ProxyProviderinterface. - Register your implementation in
META-INF/services/com.yuubin.proxy.spi.ProxyProvider. - Package your code as a JAR and add it to the classpath (e.g., inside the
lib/folder). - Configure your proxy in
application.ymlwith your custom type:proxies: - name: my-custom-proxy port: 9999 type: MY_PROTOCOL
To implement custom load balancing logic (e.g., Weighted Round-Robin, Geo-IP):
- Implement the
com.yuubin.proxy.spi.LoadBalancerinterface. - Package your class in a JAR and add it to the classpath.
- Configure your rule to use the
CUSTOMstrategy and specify the class name:rules: - targets: - http://s1 - http://s2 loadBalancing: CUSTOM customLoadBalancer: com.example.MyWeightedLoadBalancer