# Hosted proxies

A hosted proxy sends an app's traffic through URnetwork when the app only takes
a proxy setting: curl, a script, a scraper, or a phone app such as Shadowrocket.
This guide shows where to find a proxy's URL on ur.io and how to enter it in
common clients.

One scope note: a hosted proxy has no sealed session. Your client device runs
inside the operator, which translates the proxy's protocol into the network's.
What stands between the operator and your traffic is the proxy's no-logging
design described in the [threat model](/docs/threat-model), not a seal.
Providers still do not learn who you are. Where an app can run URnetwork
itself, the apps and the [SDK](/docs/getting-started-sdk) are the more private
path.

## Two kinds of proxy {#types}

ur.io creates two kinds of proxy that third-party clients can use:

| | HTTPS proxy | SOCKS5 proxy |
| --- | --- | --- |
| Plan | Every plan | UR Pro |
| URL on ur.io | `https://<token>.<host>:<port>` | `socks5h://<token>:x@<host>:<port>` |
| Where the token goes | In the host name, with no username or password | In the username; the password is never checked |
| The client must support | HTTPS proxies, which use TLS to the proxy | SOCKS5 with a username and password |
| Carries | Web traffic: HTTP, and HTTPS through CONNECT | TCP connections, and UDP through UDP associate |

The SOCKS5 proxy does not support BIND, and it drops UDP datagrams over 2 KiB.
ur.io also creates WireGuard profiles on UR Pro. Import the downloaded `.conf`
file into a WireGuard app; the rest of this guide covers HTTPS and SOCKS5.

## Get a proxy's URL {#create}

1. Sign in at [ur.io](https://ur.io) and open **Proxies**
   ([ur.io/app/proxies](https://ur.io/app/proxies)).
2. Choose **Create proxy**.
3. Pick the proxy type: **HTTPS**, **SOCKS5** or **WireGuard**. SOCKS5 and
   WireGuard carry a **Pro** badge. On the free plan, the create button
   offers Pro first.
4. Pick a location. Search for a country, region or city, or keep **Best
   available**, which uses any provider on the network. Locations show how
   many providers they have.
5. Choose **Create HTTPS proxy** or **Create SOCKS5 proxy**. The new proxy
   appears with its URL.

Every HTTPS and SOCKS5 proxy in the list has **Copy URL**, which copies the
whole URL with its token, and **×**, which removes the proxy.

## Read the URL {#url}

```text
https://<token>.<host>:<port>
socks5h://<token>:x@<host>:<port>
```

- `<token>` is the proxy's token, a long run of letters and digits. It is the
  proxy's only credential, and letter case does not matter.
- In the HTTPS URL, the token is the first label of the host name. Enter
  `<token>.<host>` as the proxy host, exactly as ur.io shows it: the token in the
  name is what signs you in.
- In the SOCKS5 URL, the token sits between `socks5h://` and `:x@`. `<host>`
  follows the `@`, and `<port>` follows the last `:`.
- The `x` is a placeholder password. The SOCKS5 proxy never checks the
  password, so any value works. Some clients send the username only when a
  password is set too, Python's `requests` among them, and ur.io's URL carries
  the `x` for them. If a client asks for the username and password separately,
  give it the token and any password.
- Keep the `h` in `socks5h`. It lets the proxy look up host names, so lookups
  leave through the provider instead of from your machine. With plain `socks5`,
  curl looks names up on your machine first.

> **Treat the URL like a password.** Anyone who has it can use the proxy, and
> the proxy's traffic uses your account's data. If a URL leaks, remove that
> proxy on ur.io, and the proxy stops accepting its token. Then create a new
> one.

## Check it works with curl {#curl}

```sh
# 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` answers with the address your request came from and where that
address is. Through the proxy, that is a provider's address in the location
you chose. HTTPS proxies need curl 7.52 or newer.

## Browsers {#browsers}

The simplest way to proxy a browser is the URnetwork extension, which creates
and manages its own hosted proxy. See
[Getting started in your browser](/docs/getting-started-browser).

To use a proxy you created on ur.io instead, use its HTTPS URL. Chrome cannot
send a SOCKS5 username at all. Operating system proxy settings and Firefox's
manual proxy settings generally cannot describe an HTTPS proxy.

**Chrome, Edge and other Chromium browsers.** Start the browser with the proxy
on its command line. The separate profile directory makes the flag work even
while your usual browser window is open:

```sh
# 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's manual settings have no username field for SOCKS and no
HTTPS proxy type, so use a one-line proxy auto-config (PAC) file. Save this as
`urnetwork.pac`:

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

Then open **Settings → General → Network Settings → Settings…**, choose
**Automatic proxy configuration URL**, enter the file's address, such as
`file:///Users/you/urnetwork.pac` or `file:///C:/Users/you/urnetwork.pac`, and
choose **OK**. To stop, choose **No proxy** in the same dialog.

## Phone apps: Shadowrocket and others {#shadowrocket}

Proxy apps for phones, such as Shadowrocket on iOS, take a SOCKS5 server as a
few fields. Create a SOCKS5 proxy on ur.io (UR Pro) and copy its URL. In the
app, add a server and fill it in from the URL:

| Field | Value |
| --- | --- |
| Type | SOCKS5 |
| Address, server or host | `<host>`: the part between `@` and the last `:` |
| Port | `<port>`: the digits after the last `:` |
| User or username | `<token>`: the part between `socks5h://` and `:x@` |
| Password | Any value, such as `x` |

Save the server, select it, and turn the connection on. For a whole phone, the
URnetwork app for [iOS](/docs/getting-started-ios) or
[Android](/docs/getting-started-android) needs no proxy and is the more
private path.

## Python {#python}

`requests` takes either proxy. SOCKS5 needs the `socks` extra
(`pip install "requests[socks]"`), and its URL needs a placeholder password:

```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` takes the same URLs; SOCKS5 needs `pip install "httpx[socks]"`.
`aiohttp` takes the HTTPS proxy:

```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's default download handler cannot fetch `https://` pages through an
HTTPS proxy: it stops with "HTTPS proxies for HTTPS destinations are not
supported". Fetch those pages with one of the libraries above instead.

## Node.js {#node}

For `fetch`, give undici's `ProxyAgent` the HTTPS proxy:

```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());
```

For `node:https` and libraries that take an agent, use `https-proxy-agent`, or
`socks-proxy-agent` for SOCKS5:

```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));
```

## Other programs: proxychains {#proxychains}

On Linux, proxychains-ng sends a program's connections through a SOCKS5 proxy
(UR Pro) even when the program has no proxy setting. It works by preloading a
library, so it cannot reach statically linked programs, which include most Go
programs. Its first proxy must be an IP address, not a host name, so look the
address up first:

```sh
dig +short <host>
```

Save a config file, `urnetwork.conf`, with that address:

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

Then run programs through it:

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

`proxy_dns` makes proxychains look names up through the proxy. If connections
stop working later, look the address up again.

## Limits {#limits}

| | Free | UR Pro |
| --- | --- | --- |
| Active proxies | 5 | 1,000 |
| New proxies a minute | 5 | 20 |

Proxies the browser extension creates count too. A limit only stops new
proxies: proxies you have keep working, and removing one makes room for
another. A proxy stays until you remove it; one left unused for about 30 days
is removed for you.

## Unique exit IPs {#unique-exit}

A hosted proxy usually spreads its connections over several providers, so
two of your proxies can leave from the same address. With a unique exit IP,
on UR Pro, each proxy leaves through one provider whose address none of your
other proxies uses. A proxy keeps its exit while that provider stays healthy.

- **Turn it on:** on the Proxies page, tick **Unique exit IP** when you create
  a proxy. Set **Number of proxies** to create up to 20 at a time. In the API,
  add `"unique_exit": true` to the `proxy_config`.
- **Limits:** unique exit proxies count toward the same limits as any other
  proxy, 1,000 active and 20 new a minute.
- **What you see:** each proxy shows where its exit is (city, region and
  country) and since when. The exit's IP address isn't shown. To see it, fetch
  an IP check through the proxy, for example with the curl commands above.
- **If the provider fails:** the proxy gets a new unique exit automatically,
  and shows **Replacing exit…** while it does. Replacements are limited per
  hour; past the limit, a proxy waits and tries again later. In the API,
  `"unique_exit_replace": "manual"` makes a proxy wait for you instead: it
  shows **Exit lost** until you rotate it.
- **Rotate exit:** gives the proxy a new unique exit. A proxy's exit can be
  rotated once a minute and up to 60 times a day. If no other unique exit is
  free in the location, the proxy keeps the one it has.
- **No unique exit available:** when every healthy exit in the location is
  already used by your other proxies, ur.io says so and creates nothing; the
  attempt doesn't count toward your limits. Pick another location, or **Best
  available**.

## Troubleshooting {#troubleshooting}

**ur.io refuses to create a proxy.** It shows the reason. On the free plan:

- "Your plan's limit of 5 active proxies is reached. Remove a proxy to create
  another, or upgrade to UR Pro for more." Remove proxies you no longer use,
  or upgrade.
- "Your plan allows 5 new proxies a minute. Try again in a minute, or upgrade
  to UR Pro for more." Wait a minute, then try again.

On UR Pro, the same messages give Pro's limits and leave out the upgrade.

**The SOCKS5 proxy rejects the sign-in.** curl says one of these, and other
clients word them their own way:

- `User was rejected by the SOCKS5 server (1 1).` The token is wrong or cut
  short, or the proxy was removed. Copy the URL from ur.io again.
- `No authentication method was acceptable.` The client sent no username. Set
  the username to the token, with a placeholder password such as `x`.

**The HTTPS proxy refuses the connection.** curl says
`CONNECT tunnel failed, response N`, where N is:

- 407: the proxy found no valid token. Copy the URL from ur.io again, and enter
  the whole `<token>.<host>` as the proxy host.
- 502: the proxy no longer exists, for example because you removed it, or the
  destination could not be reached.
- 403: the caller's address is outside the proxy's IP lock. Only proxies
  created through the API with an IP lock have one.

A client that gets an empty reply, or a connection closed at once, is
probably speaking plain HTTP to the proxy. Use the `https://` URL in a client
that supports HTTPS proxies.

**Pages are slow or time out.** Try **Best available**, or a location with
more providers. The proxy's traffic uses your account's data, so an account
with no data left cannot open new connections.

**The exit IP changes.** As in the apps, a hosted proxy spreads its
connections over several providers in its location. The address a site sees
can change from one connection to the next. To hold one exit IP per proxy,
create it with a [unique exit IP](#unique-exit) on UR Pro.

**The proxy is in the wrong place.** Best available can exit in any country.
Pick a country, region or city when you create the proxy. ur.io cannot move a
proxy you already have: create a new one in the place you want, then remove
the old one.

## Automate with the API {#api}

The Proxies page calls the [Operator API](/docs/api): `POST /network/auth-client`
with a `proxy_config`, where `initial_device_state.location` picks the
location. The answer's `proxy_config_result` carries `https_proxy_url`,
`socks_proxy_url` and `auth_token`. The API's `socks_proxy_url` has no
username: add `auth_token` as the username, as ur.io does. A `lock_ip_list`
of IP addresses or subnets limits who may use the proxy. The limits above
apply to the API too.

For a [unique exit IP](#unique-exit), add `unique_exit` to the
`proxy_config`:

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

Add `"unique_exit_replace": "manual"` to keep a proxy on its exit when its
provider fails, until you rotate it; the default is `"auto"`.

The answer's `proxy_config_result.exit` gives the exit's `exit_id`,
`country_code`, `region`, `city`, `exit_since`, `state` (`assigned`,
`replacing` or `no_supply`), `state_reason` when there is one, and
`replace_mode`. `GET /network/proxies` reports the same as each proxy's
`exit`, beside its `proxy_client`. A refusal with `no_unique_supply` means the
location has no exit left that your proxies don't already use.
`POST /network/proxy/rotate-exit` with the proxy's `client_id` moves it to a
new unique exit and answers with the new `exit`; it refuses with
`rate_limited` past the rotate limit, or `no_unique_supply` when no other
exit is free. It takes your network's sign-in or an API key.
