[English](README.md) | [简体中文](README.zh-CN.md)
---
**Resin** is a **high-performance intelligent proxy pool gateway** built for operating massive numbers of proxy nodes.
It helps shield your services from unstable underlying proxy nodes by aggregating distributed proxy resources into a unified proxy entrypoint with **session stickiness (sticky routing)**.
## Why Resin?
- **Massive-scale management**: Easily handles 100k+ proxy nodes with native high-concurrency performance.
- **Smart scheduling and circuit breaking**: Fully automated **passive + active** health checks, outbound IP probing, and latency analysis to remove bad nodes precisely. Uses P2C plus domain-aware latency-weighted scoring for optimal node selection.
- **Business-friendly sticky proxying**: Keeps the same business account bound to a stable outbound IP. If a node fails, Resin seamlessly switches to another node with the same IP.
- **Multiple access modes**: Supports HTTP forward proxy, SOCKS5 forward proxy, and URL-based reverse proxy for different clients and integration styles.
- **Multiple inbound endpoints**: Add hot-reloaded listening ports in the WebUI and independently control admin-console, HTTP forward, HTTP reverse, and SOCKS5 access on each port.
- **Observability**: Detailed metrics and logs, plus a visual Web UI. Includes complete structured request logs for querying and auditing by platform, account, target site, and more.
- **Simple and powerful**: Works out of the box with default settings, while still offering deep customization for enterprise-grade needs.
- **Cross-subscription deduplication**: Automatically merges identical nodes from different subscriptions and shares their health state.
- **Hot reload**: Update common settings without restart. Refresh subscriptions without dropping existing traffic.
- **Persistent state**: Keeps node health, latency stats, and lease bindings across restarts.
- **Zero-intrusion sticky access**: Can extract account identity from existing request headers (for example API keys), so clients often need no code changes.
- **Incremental subscription refresh**: Syncs subscription updates without interrupting current connections.
- **Flexible node isolation**: Use Platform rules (regex, region, etc.) to build independent proxy pools for different business scenarios.
> [!TIP]
> You can feed this README and [`DESIGN.md`](DESIGN.md) to AI and ask it anything about the project.
---
## Supported Protocols and Subscription Formats
### Subscription sources
- Remote subscription URL: `http://` or `https://`.
- Local subscription content: paste subscription content directly in the UI/API.
### Subscription content formats
- sing-box JSON: `{"outbounds":[...]}` or raw outbound array `[...]`.
- Clash JSON/YAML: `{"proxies":[...]}` or YAML `proxies:`.
- URI line format (one node per line): `vmess://`, `vless://`, `trojan://`, `ss://`, `hysteria2://`, `http://`, `https://`, `socks5://`, `socks5h://`.
For `http://`, `https://`, `socks5://`, `socks5h://`, use `scheme://[user:pass@]host:port` (optional `#tag`; `https` also supports `sni`/`servername`/`peer` and `allowInsecure`/`insecure` query parameters).
- Plain HTTP proxy lines: `IP:PORT` or `IP:PORT:USER:PASS` (IPv4 and IPv6).
- Base64-wrapped text subscriptions (for URI lines/plain-text node lists).
### Supported outbound node types
- For sing-box JSON/raw outbounds: `socks`, `http`, `shadowsocks`, `vmess`, `trojan`, `wireguard`, `hysteria`, `vless`, `shadowtls`, `tuic`, `hysteria2`, `anytls`, `ssh`.
- For Clash conversion: `ss`/`shadowsocks`, `socks`/`socks4`/`socks4a`/`socks5`, `http`, `vmess`, `vless`, `trojan`, `wireguard`/`wg`, `hysteria`, `hysteria2`/`hy2`, `tuic`, `anytls`, `ssh`.
## Quick Start
In just three steps, you can turn your proxy subscriptions into a highly available proxy pool.
### Step 1: Deploy and start
Docker Compose is the recommended quick-start path:
```yaml
# docker-compose.yml
services:
resin:
image: ghcr.io/resinat/resin:latest
container_name: resin
restart: unless-stopped
environment:
RESIN_ADMIN_TOKEN: "admin123" # Change to your admin dashboard password
RESIN_PROXY_TOKEN: "my-token" # Change to your proxy password
RESIN_LISTEN_ADDRESS: 0.0.0.0
RESIN_PORT: 2260
ports:
- "2260:2260"
volumes:
- ./data/cache:/var/cache/resin
- ./data/state:/var/lib/resin
- ./data/log:/var/log/resin
```
Run `docker compose up -d` to start the service.
Custom endpoint ports must also be reachable from outside the container. Docker cannot add published ports to an already-running container, so pre-publish the required port range in `ports` (for example `"2300-2399:2300-2399"`) or use host networking where appropriate.
*(If you don't want Docker, jump to [Other Deployment Options](#other-deployment-options).)*
### Step 2: Import proxy nodes
1. Open `http://127.0.0.1:2260` in your browser (replace with your server IP if needed).
2. Log in with the `RESIN_ADMIN_TOKEN` you set.
3. Go to **Subscriptions** in the left menu and add your node subscription.
4. Wait briefly for the node pool to refresh.
### Step 3: Start sending proxy requests
See the following sections for client access modes. In common scenarios, you can choose HTTP forward proxy, SOCKS5 forward proxy, or reverse proxy based on what your client supports.
## Basic Usage (Non-sticky Proxy)
### Connect as a standard proxy
If you just need a high-performance, large-capacity proxy pool with automatic health management, Resin works out of the box.
Once Resin is running, you can choose HTTP forward proxy, SOCKS5 forward proxy, or reverse proxy based on what your client supports.
If you do not want a proxy password, explicitly set `RESIN_PROXY_TOKEN=""` (the variable must still be defined). Then HTTP forward proxy is available at `http://127.0.0.1:2260`, and SOCKS5 forward proxy is available at `socks5://127.0.0.1:2260`.
For binary/source runs, Resin also loads a `.env` file from the current working directory before reading configuration. Environment variables already set by the OS or shell take precedence over `.env` values.
HTTP forward proxy example:
```bash
curl -x http://127.0.0.1:2260 \
-U ":my-token" \
https://api.ipify.org
```
SOCKS5 forward proxy example:
```bash
curl --proxy socks5h://127.0.0.1:2260 \
-U "Default:my-token" \
https://api.ipify.org
```
When `RESIN_PROXY_TOKEN=""`, SOCKS5 also allows unauthenticated access.
If your client supports overriding `BASE_URL`, you can also use reverse-proxy mode.
URL format: `/token/Platform(optional).Account(optional)/protocol/target`.
Example request to `https://api.ipify.org`:
```bash
curl http://127.0.0.1:2260/my-token/./https/api.ipify.org
```
> Choosing forward vs reverse proxy: when possible, reverse proxy is recommended for better observability. If your client cannot change BaseURL, or requires scenarios better served by forward proxy (such as uTLS or non-WebAPI traffic), use forward proxy.
### Filter nodes
If your service needs specific nodes (for example by region, subscription source, or name regex), use Resin's Platform feature.
Open `http://127.0.0.1:2260/ui/platforms` and create a Platform. For example, to use only US and HK nodes, create `MyPlatform` and set region filters to:
```
us
hk
```
Node tag rules match `/`, with one regular expression per line. Plain rules are ORed, a leading `*` marks a required rule, and a leading `!` excludes a node on any match. For example, this selects dedicated Hong Kong or Japan nodes while excluding expired and invalid nodes:
```text
Hong Kong
Japan
*Dedicated
!Expired
!Invalid
```
Only the first character is interpreted as a rule prefix; the rest remains a Go regular expression. Escape a literal leading `!` as `\!`.
For forward proxy (HTTP / SOCKS5), include Platform in the auth info. Examples:
```bash
curl -x http://127.0.0.1:2260 \
-U "MyPlatform:my-token" \
https://api.ipify.org
```
```bash
curl --proxy socks5h://127.0.0.1:2260 \
-U "MyPlatform:my-token" \
https://api.ipify.org
```
For reverse proxy, include Platform in the URL prefix:
```bash
curl http://127.0.0.1:2260/my-token/MyPlatform/https/api.ipify.org
```
## Advanced Usage: Sticky Session Proxy
When your business depends on IP continuity or long-lived interactions, use Resin's core feature: **sticky proxying**.
First, understand two core concepts:
### Core Concepts: Platform and Account
- **Platform**: An isolated node pool. You can build it with filters (for example, only US nodes). Resin provides a default `Default` platform containing all available nodes.
- **Account**: A unique business identity (for example `Tom` or `user_1`). For requests carrying an Account, Resin anchors traffic to a dedicated high-quality outbound node. If that node fails, Resin retries seamlessly and switches to another node with the same IP.
### Sticky proxy access formats
#### Method 1: Forward proxy (HTTP Proxy / SOCKS5)
HTTP forward proxy and SOCKS5 forward proxy share the same identity format: `Platform.Account:RESIN_PROXY_TOKEN`.
Just put the identity in proxy authentication:
```bash
# HTTP forward proxy: bind business account user_tom to a stable dedicated outbound IP
curl -x http://127.0.0.1:2260 \
-U "Default.user_tom:my-token" \
https://api.ipify.org
```
```bash
# SOCKS5 forward proxy: uses the same identity format as HTTP forward proxy
curl --proxy socks5h://127.0.0.1:2260 \
-U "Default.user_tom:my-token" \
https://api.ipify.org
```
#### Method 2: Reverse proxy (URL Account, quick/manual debug)
By replacing your service BaseURL with Resin reverse-proxy URL, traffic goes through Resin directly.
Advanced URL format: `http://host:2260/token/platform.account/protocol/target`:
```bash
# Example: user_tom accesses api.ipify.org over https
curl "http://127.0.0.1:2260/my-token/Default.user_tom/https/api.ipify.org"
```
> The URL Account segment is designed for quick use and manual debugging.
> For long-running production integrations, prefer passing Account by header (`X-Resin-Account`).
#### Method 3: Reverse proxy + `X-Resin-Account` header (recommended production integration)
If your client/SDK supports custom request headers, pass Account explicitly with `X-Resin-Account`.
This is the recommended and most stable method.
Account source priority: `X-Resin-Account` header > Account in reverse-proxy URL > header extraction rules.
Example:
```bash
curl "http://127.0.0.1:2260/my-token/MyPlatform/https/api.example.com/v1/orders" \
-H "X-Resin-Account: user_tom"
```
#### Method 4: Reverse proxy + header rules (zero/low-intrusion integration)
If your client cannot set `X-Resin-Account`, Resin can still extract Account from existing business headers (for example API Key, Token, Cookie) via header rules.
Assume your requests already include an `Authorization` header:
1. In Platform Configuration, set `Reverse-proxy empty-account behavior` to `Extract specified request headers as Account`.
2. Set `Headers used to extract Account` to `Authorization`.
Then even if Account is omitted in URL, Resin can still parse it from headers:
```bash
curl "http://127.0.0.1:2260/my-token/MyPlatform/https/api.example.com/v1/orders" \
-H "Authorization: sk-abc123"
```
In this example, Resin uses `sk-abc123` as Account. Future requests with the same key are intended to stay bound to the same outbound IP whenever routing conditions allow.
> [!TIP]
> Beyond Platform header confi