开发者

托管代理

10 分钟阅读以 Markdown 格式查看 ↗

托管代理让只接受代理设置的应用经由 URnetwork 发送流量:curl、脚本、爬虫,或者 Shadowrocket 这样的手机应用。这份指南说明在 ur.io 上哪里能找到代理的 URL,以及如何把它填进常见的客户端。

一条适用范围说明:托管代理没有密封会话。你的客户端设备运行在运营方内部,由运营方把代理的协议翻译成网络自己的协议。站在运营方和你的流量之间的,是威胁模型里描述的代理不记日志的设计,而不是密封。提供者仍然不知道你是谁。如果应用本身能运行 URnetwork,那么 URnetwork 应用和 SDK 是更私密的途径。

两种代理

ur.io 能创建两种可供第三方客户端使用的代理:

HTTPS 代理SOCKS5 代理
套餐所有套餐UR Pro
ur.io 上的 URLhttps://<token>.<host>:<port>socks5h://<token>:x@<host>:<port>
令牌放在哪里放在主机名里,不需要用户名和密码作为用户名;从不检查密码
客户端必须支持HTTPS 代理,即与代理之间使用 TLS带用户名和密码的 SOCKS5
承载内容网页流量:HTTP,以及经 CONNECT 的 HTTPSTCP 连接,以及经 UDP associate 的 UDP

SOCKS5 代理不支持 BIND,并会丢弃超过 2 KiB 的 UDP 数据报。ur.io 还能在 UR Pro 上创建 WireGuard 配置文件。把下载的 .conf 文件导入 WireGuard 应用即可;本指南其余部分讲 HTTPS 和 SOCKS5。

获取代理的 URL

  1. 在 ur.io 登录,打开代理(Proxies)(ur.io/app/proxies)。
  2. 选择创建代理(Create proxy)。
  3. 选择代理类型:HTTPS、SOCKS5 或 WireGuard。SOCKS5 和 WireGuard 带有 Pro 标记。在免费档上,创建按钮会先提供 Pro。
  4. 选择位置。搜索国家、地区或城市,或者保留最佳可用(Best available),它使用网络上的任意提供者。每个位置都会显示它有多少提供者。
  5. 选择 Create HTTPS proxy 或 Create SOCKS5 proxy。新代理会连同它的 URL 一起出现。

列表中的每个 HTTPS 和 SOCKS5 代理都有复制URL(Copy URL),它会复制带令牌的完整 URL;还有 ×,用于删除这个代理。

读懂 URL

Text
https://<token>.<host>:<port>
socks5h://<token>:x@<host>:<port>
  • <token> 是代理的令牌,一长串字母和数字。它是代理唯一的凭据,字母大小写无关紧要。
  • 在 HTTPS URL 里,令牌是主机名的第一段。把 <token>.<host> 原样填作代理主机,与 ur.io 显示的完全一致:主机名里的令牌就是你的登录凭据。
  • 在 SOCKS5 URL 里,令牌位于 socks5h:// 和 :x@ 之间。<host> 在 @ 之后,<port> 在最后一个 : 之后。
  • 其中的 x 是占位密码。SOCKS5 代理从不检查密码,所以填什么都可以;但有些客户端只有在同时设置了密码时才会发送用户名,Python 的 requests 就是其中之一,所以 ur.io 的 URL 带上了这个 x。如果客户端要求分别填写用户名和密码,用户名填令牌,密码随便填。
  • 保留 socks5h 里的 h。它让代理去解析主机名,于是域名查询经由提供者发出,而不是从你的机器发出。如果用不带 h 的 socks5,curl 会先在你的机器上解析域名。

把 URL 当作密码对待。 任何拿到它的人都能使用这个代理,而代理的流量消耗的是你账户的数据。如果 URL 泄露了,在 ur.io 上删除那个代理,代理就不再接受它的令牌。然后再创建一个新的。

用 curl 检查是否可用

Shell
# HTTPS proxy, on every plan
curl -x 'https://<token>.<host>:<port>' https://api.bringyour.com/my-ip-info

# SOCKS5 proxy, on UR Pro
curl -x 'socks5h://<token>:x@<host>:<port>' https://api.bringyour.com/my-ip-info

/my-ip-info 会返回你的请求来自哪个地址,以及这个地址位于何处。经过代理时,那就是你所选位置中某个提供者的地址。HTTPS 代理需要 curl 7.52 或更新版本。

浏览器

给浏览器加代理最简单的办法是 URnetwork 扩展,它会创建并管理自己的托管代理。见浏览器入门。

如果要改用你在 ur.io 上创建的代理,请用它的 HTTPS URL。Chrome 根本无法发送 SOCKS5 用户名。操作系统的代理设置和 Firefox 的手动代理设置通常都无法描述 HTTPS 代理。

Chrome、Edge 及其他 Chromium 系浏览器。 在命令行上带着代理启动浏览器。单独的配置文件目录能让这个参数生效,即使你平时用的浏览器窗口还开着:

Shell
# macOS
open -na "Google Chrome" --args --user-data-dir="$HOME/urnetwork-proxy-profile" --proxy-server="https://<token>.<host>:<port>"

# Linux
google-chrome --user-data-dir="$HOME/urnetwork-proxy-profile" --proxy-server="https://<token>.<host>:<port>"

# Windows, in Command Prompt (Edge: msedge instead of chrome)
start chrome --user-data-dir="%USERPROFILE%\urnetwork-proxy-profile" --proxy-server="https://<token>.<host>:<port>"

Firefox。 Firefox 的手动设置里没有 SOCKS 的用户名栏,也没有 HTTPS 代理类型,所以改用一个只有一行的代理自动配置(PAC)文件。把下面的内容存为 urnetwork.pac:

js
function FindProxyForURL(url, host) {
  return "HTTPS <token>.<host>:<port>";
}

然后打开设置 → 常规 → 网络设置 → 设置…(Settings → General → Network Settings → Settings…),选择自动代理配置 URL(Automatic proxy configuration URL),填入该文件的地址,例如 file:///Users/you/urnetwork.pac 或 file:///C:/Users/you/urnetwork.pac,再选择确定(OK)。要停用时,在同一个对话框里选择不使用代理(No proxy)。

手机应用:Shadowrocket 等

手机上的代理应用,比如 iOS 上的 Shadowrocket,用几个字段来设置一台 SOCKS5 服务器。在 ur.io 上创建一个 SOCKS5 代理(UR Pro)并复制它的 URL。在应用里添加一台服务器,按 URL 填写:

字段值
类型(Type)SOCKS5
地址、服务器或主机(Address)<host>:@ 与最后一个 : 之间的部分
端口(Port)<port>:最后一个 : 之后的数字
用户或用户名(User)<token>:socks5h:// 与 :x@ 之间的部分
密码(Password)任意值,例如 x

保存服务器,选中它,然后打开连接。如果要覆盖整部手机,iOS 或 Android 上的 URnetwork 应用不需要代理,而且是更私密的途径。

Python

requests 两种代理都能用。SOCKS5 需要 socks 附加组件(pip install "requests[socks]"),而且它的 URL 需要一个占位密码:

python
import requests

proxy = "https://<token>.<host>:<port>"          # HTTPS proxy, every plan
# proxy = "socks5h://<token>:x@<host>:<port>"    # SOCKS5 proxy, UR Pro

r = requests.get(
    "https://api.bringyour.com/my-ip-info",
    proxies={"http": proxy, "https": proxy},
    timeout=30,
)
print(r.json()["info"]["ip"])

httpx 接受同样的 URL;SOCKS5 需要 pip install "httpx[socks]"。aiohttp 接受 HTTPS 代理:

python
import asyncio

import aiohttp
import httpx

with httpx.Client(proxy="https://<token>.<host>:<port>") as client:
    print(client.get("https://api.bringyour.com/my-ip-info").json())


async def main():
    async with aiohttp.ClientSession() as session:
        async with session.get("https://api.bringyour.com/my-ip-info", proxy="https://<token>.<host>:<port>") as r:
            print(await r.json())

asyncio.run(main())

Scrapy 的默认下载处理器无法经 HTTPS 代理抓取 https:// 页面:它会停下并报错 "HTTPS proxies for HTTPS destinations are not supported"。请改用上面的某个库来抓取这些页面。

Node.js

对于 fetch,把 HTTPS 代理交给 undici 的 ProxyAgent:

js
import { fetch, ProxyAgent } from "undici";

const dispatcher = new ProxyAgent("https://<token>.<host>:<port>");
const res = await fetch("https://api.bringyour.com/my-ip-info", { dispatcher });
console.log(await res.json());

对于 node:https 以及接受 agent 的库,使用 https-proxy-agent;SOCKS5 则用 socks-proxy-agent:

js
import https from "node:https";
import { HttpsProxyAgent } from "https-proxy-agent";
// import { SocksProxyAgent } from "socks-proxy-agent";

const agent = new HttpsProxyAgent("https://<token>.<host>:<port>");
// const agent = new SocksProxyAgent("socks5h://<token>:x@<host>:<port>");

https.get("https://api.bringyour.com/my-ip-info", { agent }, (res) => res.pipe(process.stdout));

其他程序:proxychains

在 Linux 上,proxychains-ng 能让一个程序的连接经由 SOCKS5 代理(UR Pro)发出,即使这个程序本身没有代理设置。它靠预加载一个库来工作,所以管不到静态链接的程序,其中包括大多数 Go 程序。它的第一个代理必须是 IP 地址,而不能是主机名,所以先查出地址:

Shell
dig +short <host>

把这个地址写进配置文件 urnetwork.conf:

Text
strict_chain
proxy_dns
[ProxyList]
socks5 <ip> <port> <token> x

然后通过它运行程序:

Shell
proxychains4 -f urnetwork.conf curl https://api.bringyour.com/my-ip-info

proxy_dns 让 proxychains 经由代理解析域名。如果之后连接不再可用,重新查一次地址。

限制

免费档UR Pro
活跃代理51,000
每分钟新建代理520

浏览器扩展创建的代理也计算在内。限制只阻止新建代理:你已有的代理照常工作,删除一个就能腾出位置再建一个。代理会一直保留,直到你删除它;闲置约 30 天未用的代理会被自动删除。

独立出口 IP

托管代理通常会把连接分散到多个提供者上,所以你的两个代理可能从同一个地址出网。开启独立出口 IP(UR Pro)后,每个代理只经由一个提供者出网,而这个提供者的地址不会被你的其他代理使用。只要该提供者保持健康,代理就一直使用这个出口。

  • 开启方式: 在代理页面创建代理时,勾选独立出口 IP。把代理数量设为最多 20,可以一次创建多个。在 API 里,在 proxy_config 中加入 "unique_exit": true。
  • 限制: 独立出口代理和其他代理计入同样的限制:1,000 个活跃代理,每分钟新建 20 个。
  • 你能看到什么: 每个代理会显示它的出口所在的位置(城市、地区和国家)以及开始使用的时间。出口的 IP 地址不会显示。想看 IP,可以通过代理访问一个 IP 查询地址,例如用上面的 curl 命令。
  • 提供者出故障时: 代理会自动换一个新的独立出口,期间显示正在更换出口…。每小时的自动更换次数有限制;超过限制后,代理会等待并稍后再试。在 API 里,"unique_exit_replace": "manual" 会让代理改为等你处理:它会显示出口已失效,直到你手动更换。
  • 更换出口: 给代理换一个新的独立出口。每个代理的出口每分钟可更换一次,每天最多 60 次。如果该位置没有其他空闲的独立出口,代理会保留当前的出口。
  • 没有可用的独立出口: 当该位置所有健康的出口都已被你的其他代理占用时,ur.io 会提示你,并且不会创建代理;这次尝试不计入你的限制。请换一个位置,或者选最佳可用。

故障排查

ur.io 拒绝创建代理。 它会显示原因(消息为英文)。在免费档上:

  • "Your plan's limit of 5 active proxies is reached. Remove a proxy to create another, or upgrade to UR Pro for more."(你的套餐已达到 5 个活跃代理的上限。)删除不再使用的代理,或者升级。
  • "Your plan allows 5 new proxies a minute. Try again in a minute, or upgrade to UR Pro for more."(你的套餐每分钟只允许新建 5 个代理。)等一分钟再试。

在 UR Pro 上,同样的消息会给出 Pro 的限制,并且不提升级。

SOCKS5 代理拒绝登录。 curl 会报下面其中一条,其他客户端各有各的措辞:

  • User was rejected by the SOCKS5 server (1 1). 令牌错误或不完整,或者代理已被删除。从 ur.io 重新复制 URL。
  • No authentication method was acceptable. 客户端没有发送用户名。把用户名设为令牌,并填一个占位密码,比如 x。

HTTPS 代理拒绝连接。 curl 会报 CONNECT tunnel failed, response N,其中 N 是:

  • 407:代理没有找到有效的令牌。从 ur.io 重新复制 URL,并把完整的 <token>.<host> 填作代理主机。
  • 502:代理已不存在,例如你删除了它;或者无法连到目标。
  • 403:调用方的地址不在代理的 IP 锁定范围内。只有通过 API 创建并设置了 IP 锁定的代理才有这种锁定。

如果客户端收到空回复,或者连接立刻被关闭,它多半是在用明文 HTTP 和代理通信。请在支持 HTTPS 代理的客户端里使用 https:// URL。

页面很慢或超时。 试试最佳可用,或者提供者更多的位置。代理的流量消耗你账户的数据,所以数据用完的账户无法建立新连接。

出口 IP 会变。 和应用一样,托管代理会把它的连接分散到所在位置的多个提供者上。网站看到的地址可能每次连接都不一样。如果想让每个代理固定一个出口 IP,请在 UR Pro 上用独立出口 IP 创建它。

代理位置不对。 最佳可用可能从任何国家出网。创建代理时选好国家、地区或城市。ur.io 无法移动你已有的代理:在你想要的位置新建一个,然后删除旧的。

用 API 自动化

代理页面调用的是运营方 API:带 proxy_config 的 POST /network/auth-client,其中 initial_device_state.location 选择位置。返回的 proxy_config_result 里有 https_proxy_url、socks_proxy_url 和 auth_token。API 返回的 socks_proxy_url 不含用户名:像 ur.io 那样,把 auth_token 加作用户名。由 IP 地址或子网组成的 lock_ip_list 可以限制谁能使用代理。上面的限制同样适用于 API。

如需独立出口 IP,在 proxy_config 中加入 unique_exit:

JSON
{
  "proxy_config": {
    "unique_exit": true,
    "initial_device_state": {
      "location": { "connect_location_id": { "best_available": true } }
    }
  }
}

加入 "unique_exit_replace": "manual" 后,代理的提供者出故障时会保持在原出口上,直到你手动更换;默认值为 "auto"。

返回的 proxy_config_result.exit 给出出口的 exit_id、country_code、region、city、exit_since、state(assigned、replacing 或 no_supply)、有原因时的 state_reason,以及 replace_mode。GET /network/proxies 会在每个代理的 exit 中报告同样的信息,与它的 proxy_client 并列。带 no_unique_supply 的拒绝表示该位置已没有你的代理尚未使用的出口。用代理的 client_id 调用 POST /network/proxy/rotate-exit,可以把它换到一个新的独立出口,返回新的 exit;超过更换频率时会以 rate_limited 拒绝,没有其他空闲出口时以 no_unique_supply 拒绝。调用它需要你网络的登录凭证或 API 密钥。