After My Claude Code Account Was Banned, I Fixed My Exit IP

2026-10-20 · Claude Code · Proxy · 中文

My Claude account was banned a while ago, and Claude Code stopped working with it. Anthropic does not say which rule was triggered, and appeals rarely come with a detailed explanation. After registering again, I started treating the network exit as part of the setup.

The short version: a single, clean residential IP matters more than constantly switching nodes.

Bans rarely have one cause

Common triggers include:

  • an IP that jumps between countries or regions
  • datacenter IPs, free proxies, or shared exits
  • a payment method that does not match the account region
  • bursts of requests, or one account shared across devices or people

Anthropic does not explain individual cases, so the practical move is to keep every controllable variable stable.

The setup I use now

  1. A fixed residential IP: a static proxy from webshare.io, around $1.5 per month. That is enough for one person using Claude Code. Pick a fixed endpoint, not a rotating IP.
  2. Payment: subscribe to Claude Pro through Google Play on Android. Compared with virtual cards, in-app billing is more stable and easier to keep consistent with the account region.
  3. A two-hop proxy: in Clash Verge, go through an airport first, then use the webshare HTTP proxy as the exit. TUN must be enabled.

Why two hops

Connecting directly to webshare has two problems: the route from where I am may be unreliable, and my home IP is exposed to the proxy provider. With the airport hop:

local → airport (fastest node) → webshare (fixed residential IP) → Claude

The airport gets you out; webshare provides a clean, fixed exit. The target sees the webshare IP, not the airport or your home connection.

One caveat: the airport can still see destination domains and traffic metadata, so it has to be trusted. This chain fixes exit IP reputation; it is not anonymity.

Clash Verge configuration

  1. Create a static proxy in the webshare dashboard and note the host, port, username, and password.

    webshare Static Residential → Proxy List: fixed endpoints, ports, authentication, and status

  2. In Clash Verge Rev: Subscriptions → Global Extension Script, open it, and paste the script below. It applies globally.

    The Global Extension Script entry at the bottom of Clash Verge's Subscriptions page

  3. Replace the webshare endpoint values at the top of the script, then uncomment the username/password fields in the node.

  4. Make sure the airport subscription has a group such as “Auto Select” or “URL Test”.

  5. Enable TUN. Claude Code is a CLI program and does not read the system proxy settings; without TUN it may not use the proxy at all.

  6. Verify with curl https://ipinfo.io/json — the IP should be the webshare endpoint.

What the script does

The global override works in six steps:

  1. Finds the airport's auto-select group to use as the second hop.
  2. Creates HTTP proxy nodes for the webshare endpoints and sets dialer-proxy on each one to that group. This is the “airport → webshare” chain.
  3. Adds a 🔒 Clean IP select group containing the webshare nodes, defaulting to the first one.
  4. Rewrites rules: keeps DIRECT / REJECT / PASS rules, points every other proxy rule at the exit group, and drops the original MATCH / FINAL rules.
  5. Appends two fallbacks: GEOIP,CN,DIRECT,no-resolve for domestic IPs, and MATCH,🔒 Clean IP for everything else.
  6. Handles name collisions and logs a short diagnostic. HONOR_PROFILE limits injection to a named profile.

Caveats

  • This lowers the probability of a ban; it does not guarantee anything. Account behavior, payment, and usage patterns matter too.
  • Keep one account on one exit. Do not switch from the US to Japan and back.
  • webshare credentials sit in the script as plain text. Never share a config containing them, and rotate the password if it leaks.
  • Do not switch between airport nodes and webshare endpoints constantly; the exit group only selects the first node by default.
  • This is a personal setup, not advice on bypassing the terms of service. Anthropic's enforcement rules are the authority.

The full script (credentials removed)

function main(config, profileName) {

  /* ======================= User configuration ======================= */

  // Names of the airport's auto-select groups, in priority order
  var AUTO_CANDIDATES = ["Auto Select", "URL Test", "url-test", "Proxy", "PROXY", "Node Select"];

  // webshare endpoints [IP, port]
  var WS_ENDPOINTS = [
    ["YOUR_ENDPOINT_IP", 6000],
    ["YOUR_ENDPOINT_IP", 6001]
  ];

  var EXIT_GROUP = "🔒 Clean IP";       // exit group name
  var WS_NODE_PREFIX = "🇺🇸 Clean IP-"; // prefix for generated nodes
  var HONOR_PROFILE = false;            // true = only inject for a matching profile

  /* ====================== End user configuration ==================== */

  config = config || {};
  var groups = config["proxy-groups"] = config["proxy-groups"] || [];
  var proxies = config.proxies = config.proxies || [];
  var rules = config.rules = config.rules || [];

  // 0. Optional: filter by subscription name
  if (HONOR_PROFILE) {
    if (!profileName || String(profileName).indexOf("YOUR_PROFILE_KEYWORD") === -1) {
      return config;
    }
  }

  // 1. Find the airport's auto-select group as the second hop
  var autoGroupName = null;
  for (var a = 0; a < AUTO_CANDIDATES.length; a++) {
    var cand = AUTO_CANDIDATES[a];
    for (var g = 0; g < groups.length; g++) {
      if (groups[g].name === cand) { autoGroupName = cand; break; }
    }
    if (autoGroupName) break;
  }

  // 2. Avoid name collisions
  var taken = {};
  proxies.forEach(function (p) { taken[p && p.name] = true; });
  groups.forEach(function (gr) { taken[gr && gr.name] = true; });
  function uniq(base) {
    var n = base, i = 1;
    while (taken[n]) { n = base + "·" + i; i++; }
    taken[n] = true;
    return n;
  }

  // 3. Create webshare exit nodes, dialed through the airport's fastest node
  var wsNames = [];
  WS_ENDPOINTS.forEach(function (ep, idx) {
    var rawPort = parseInt(String(ep[1]).replace(/[^0-9]/g, ""), 10);
    var node = {
      name: uniq(WS_NODE_PREFIX + (idx + 1)),
      type: "http",
      server: ep[0],
      port: rawPort,
      // webshare requires authentication: uncomment and fill in your credentials
      // username: "YOUR_USERNAME",
      // password: "YOUR_PASSWORD",
      udp: false
    };
    if (autoGroupName) { node["dialer-proxy"] = autoGroupName; }
    wsNames.push(node.name);
    proxies.push(node);
  });

  // 4. Exit group: select, first node by default
  var exitGroupName = uniq(EXIT_GROUP);
  groups.push({
    name: exitGroupName,
    type: "select",
    proxies: wsNames
  });

  // 5. Rewrite rules: keep direct/block, send everything else to the exit group
  var DIRECT_TARGETS = { "DIRECT": 1, "REJECT": 1, "REJECT-DROP": 1, "PASS": 1 };
  var kept = [];
  for (var r = 0; r < rules.length; r++) {
    var t = String(rules[r]).trim();
    if (!t) continue;
    var parts = t.split(",");
    var type = String(parts[0] || "").toUpperCase();
    if (type === "MATCH" || type === "FINAL") continue;

    var last = String(parts[parts.length - 1] || "").trim();
    if (DIRECT_TARGETS[last]) { kept.push(t); continue; }

    parts[parts.length - 1] = exitGroupName;
    kept.push(parts.join(","));
  }
  kept.push("GEOIP,CN,DIRECT,no-resolve");
  kept.push("MATCH," + exitGroupName);
  config.rules = kept;

  // 6. Diagnostics
  try {
    if (!autoGroupName) {
      console.log("[chain] No auto-select group found; webshare will dial directly. Candidates=" +
        AUTO_CANDIDATES.join("/"));
    } else {
      console.log("[chain] second hop=" + autoGroupName + ", exit group=" + exitGroupName +
        ", nodes=" + wsNames.length);
    }
  } catch (e) { /* some engines have no console */ }

  return config;
}
Link copied