Как запустить Claude Desktop через прокси с аутентификацией (когда документация молчит)

Как запустить Claude Desktop через прокси
Или история о том, как я потратила три часа на то, что должно было работать из коробки

TL;DR

Claude Desktop — отличное Electron-приложение от Anthropic. Прокси с аутентификацией — реальность многих российских разработчиков. А вот их совместная работа — это квест с неочевидным решением. Спойлер: переменные окружения не работают, флаги --proxy-server не поддерживают авторизацию, а единственное рабочее решение — локальный прокси-туннель через mitmproxy.

Зачем вообще вот это всё?

Сижу я, значит, пытаюсь запустить Claude Desktop. Простое действие, казалось бы. Но у меня прокси с аутентификацией (http://user:password@proxy.example.com:8000), и Claude отказывается подключаться. Выдаёт загадочное "Couldn't connect to Claude" с ещё более загадочным "Unknown error".

Полезла в документацию Electron. Там пишут: "используйте --proxy-server". Хорошо! Запускаю:

/Applications/Claude.app/Contents/MacOS/Claude --proxy-server="proxy.example.com:8000"

Не работает. Потому что Chromium (на котором построен Electron) не поддерживает передачу логина и пароля через URL в флаге --proxy-server. Это не баг, это feature! 🤦‍♀️

Что я пробовала (и что не сработало)

Попытка №1: Переменные окружения

export HTTP_PROXY=http://user:pass@proxy.example.com:8000
export HTTPS_PROXY=http://user:pass@proxy.example.com:8000
open -a "Claude"

Результат: Приложение запустилось, но прокси проигнорировало. Electron-приложения, запущенные через open, не наследуют переменные окружения из терминала.

Попытка №2: Запуск через бинарник с переменными

env HTTP_PROXY=http://user:pass@proxy.example.com:8000 /Applications/Claude.app/Contents/MacOS/Claude

Результат: То же самое. Переменные передаются, но Electron их не видит. Это особенность песочницы macOS.

Попытка №3: Редактирование Info.plist

Добавила секцию LSEnvironment в /Applications/Claude.app/Contents/Info.plist:

<key>LSEnvironment</key>
<dict>
    <key>HTTP_PROXY</key>
    <string>http://user:pass@proxy.example.com:8000</string>
</dict>

Результат: Система отказалась это применять без повторной подписи приложения. А переподписывание — это отдельная песня с нотариусом Apple.

Решение: локальный прокси без аутентификации

Раз Electron хочет прокси без аутентификации, дадим ему! Создадим локальный прокси, который будет форвардить запросы на реальный прокси с учётными данными.

Шаг 1: Устанавливаем mitmproxy

brew install mitmproxy

mitmproxy — это швейцарский нож для работы с HTTP/HTTPS трафиком. У него есть консольная версия mitmdump, которая отлично подходит для наших целей.

Шаг 2: Запускаем локальный прокси

mitmdump \
    --mode upstream:http://proxy.example.com:8000 \
    --upstream-auth user:password \
    --listen-port 8888 \
    --set block_global=false

Что происходит:

  • --mode upstream — режим прокси-форвардера
  • --upstream-auth — учётные данные для реального прокси (вот он, наш спаситель!)
  • --listen-port 8888 — локальный порт без аутентификации
  • --set block_global=false — не блокируем глобальные запросы

Шаг 3: Запускаем Claude через локальный прокси

/Applications/Claude.app/Contents/MacOS/Claude \
    --proxy-server="127.0.0.1:8888" \
    --ignore-certificate-errors

Флаг --ignore-certificate-errors нужен, потому что mitmproxy создаёт свой SSL-сертификат для перехвата HTTPS.

Проверка

В терминале с mitmdump должны появиться логи:

[11:37:39.054] server connect proxy.example.com:8000
127.0.0.1:51952: GET https://claude.ai/ HTTP/2.0
     << HTTP/2.0 200 OK 239k

Видим успешные запросы? Победа! 🎉

Автоматизация: скрипт для запуска

Создала .command файл, чтобы не вводить эти команды каждый раз:

#!/bin/bash

# Цвета для красоты
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

echo -e "${GREEN}🚀 Запуск Claude Desktop с прокси...${NC}"

# Проверяем, запущен ли mitmdump
if ! lsof -i :8888 > /dev/null 2>&1; then
    echo -e "${YELLOW}📡 Прокси не запущен, запускаем mitmdump...${NC}"

    nohup mitmdump \
        --mode upstream:http://proxy.example.com:8000 \
        --upstream-auth user:password \
        --listen-port 8888 \
        --set block_global=false \
        > /tmp/mitmdump.log 2>&1 &

    sleep 2
    echo -e "${GREEN}✅ Прокси запущен на порту 8888${NC}"
else
    echo -e "${GREEN}✅ Прокси уже запущен${NC}"
fi

# Убиваем старые процессы Claude
pkill -f "Claude.app" 2>/dev/null

# Запускаем Claude с прокси
echo -e "${GREEN}🎯 Запускаем Claude Desktop...${NC}"
/Applications/Claude.app/Contents/MacOS/Claude \
    --proxy-server="127.0.0.1:8888" \
    --ignore-certificate-errors \
    > /tmp/claude.log 2>&1 &

echo -e "${GREEN}✨ Готово!${NC}"
echo "Логи прокси: /tmp/mitmdump.log"
echo "Логи Claude: /tmp/claude.log"

Сохраняем как launch-claude-proxy.command, делаем исполняемым (chmod +x), и теперь можно запускать двойным кликом в Finder.

Почему это работает?

Схема простая:

Claude Desktop → 127.0.0.1:8888 (без auth) → mitmproxy → proxy.example.com:8000 (с auth)

Claude видит обычный прокси без аутентификации, а mitmproxy берёт на себя грязную работу по авторизации на реальном прокси.

Что я поняла из этой истории

  1. Переменные окружения в Electron — это не то, что вы думаете. Они работают только если приложение запущено правильным образом, что почти никогда не происходит в GUI.
  2. Документация Electron врёт красиво. Там написано про поддержку прокси, но про аутентификацию — ни слова. А app.on('login') для обработки прокси-аутентификации требует редактирования кода приложения.
  3. mitmproxy — недооценённый инструмент. Обычно его используют для дебага HTTP-трафика, но он отлично справляется и с ролью прокси-форвардера.
  4. macOS любит усложнять. Песочница, подпись кода, отсутствие наследования ENV — всё это делает простые вещи непростыми.

Альтернативы

Если не хочется заморачиваться с mitmproxy, можно:

  1. Написать простой Node.js прокси на базе http-proxy с поддержкой upstream-аутентификации
  2. Использовать SSH-туннель (если есть доступ к серверу за прокси)
  3. Настроить системный прокси в macOS — но тогда весь трафик пойдёт через него

Заключение

Три часа боли превратились в рабочее решение и этот пост. Надеюсь, кому-то это сэкономит время. А заодно напоминает: современные технологии — это слоёный пирог из абстракций, где каждый слой добавляет свои нюансы.

Если у вас есть более элегантное решение — пишите в комментариях! Всегда интересно узнать, как другие разработчики решают подобные задачи.


P.S. Если вы разработчик Electron-приложений — пожалуйста, добавьте нормальную поддержку прокси с аутентификацией. Или хотя бы напишите об этом в документации. Спасибо 🙏