Переход с mihomo
Формат конфига у Citrus тот же, что у mihomo, и большинство конфигов запускаются без правок. Ниже — то, что всё-таки может потребовать изменений, и поведение, которое стало строже. Проверить конфиг можно до перезапуска:
citrus -t -f config.yamlДля тех, кто встраивает ядро как библиотеку: путь Go-модуля остался github.com/metacubex/mihomo, подключайте Citrus через replace. Сам Citrus тоже подменяет через replace модули github.com/metacubex/utls, github.com/metacubex/tls и github.com/metacubex/http на свои форки; эти строки нужно перенести в go.mod встраивающего проекта. Модулю нужен Go 1.26 или новее.
Удалённые протоколы
Заголовок раздела «Удалённые протоколы»VMess (вместе с mKCP, mekya и TLSMirror), ShadowsocksR, Hysteria v1, TUIC v4, потоковые шифры Shadowsocks и v2ray-plugin удалены. Замены — в таблице совместимости.
- Основной конфиг: такой прокси или листенер — ошибка с понятным текстом, например «VMess was removed from Citrus, use VLESS» или «TUIC v4 is no longer supported, use uuid/password (v5)». Конфиг не загрузится.
- Провайдеры прокси: узел с удалённым протоколом пропускается с предупреждением, остальная подписка загружается.
- Ссылки:
vmess://,ssr://,hysteria://и ссылки TUIC v4 конвертер пропускает. - Опции:
network: mkcp,kcp,mekyaиtlsmirror-optsтеперь ошибка; раньше VLESS и Trojan молча откатывались на TCP. ПравилоIN-TYPE,VMESSбольше не разбирается, верхнеуровневогоvmess-configнет. - Группа
relayудалена ещё в mihomo; её ошибка теперь предлагает группуtype: chain, см. Цепочки.
Контроллер
Заголовок раздела «Контроллер»Подробности — на странице Безопасность контроллера.
- Сетевой адрес требует
secret.external-controllerиexternal-controller-tlsна не-loopback адресе (0.0.0.0:9090,:9090, адрес в локальной сети) безsecretне запускаются: в логе ошибка, остальное ядро работает. Без secret можно на loopback, наexternal-controller-unixиexternal-controller-pipe, и на TLS с проверкой клиентского сертификата. Отключить проверку:external-controller-allow-insecure: true(или-ext-ctl-allow-insecure,CLASH_OVERRIDE_EXTERNAL_CONTROLLER_ALLOW_INSECURE=true). Это касается Docker-образов, которые публикуют порт контроллера. - Защита от браузера без secret. tcp/tls-контроллер без secret отвечает только на
Hostв виде IP илиlocalhostи отклоняет запросы с чужимOrigin. Дашборду на внешнем сайте нуженsecretили его источник вexternal-controller-cors.allow-origins("*"не считается). Скрипты и панели, которые не шлютOrigin, это не затрагивает. PUT /configsприменяет настройки контроллера. Новыйsecret, адреса, TLS, CORS иexternal-uiвступают в силу сразу: старый токен получает 401, открытые вебсокеты закрываются. Конфиг, чей контроллер был бы отклонён, получает 400, и ничего не применяется.- Unix-сокет и именованный канал доступны только владельцу (сокет 0600, канал — пользователь ядра, SYSTEM и администраторы). Если GUI работает от другого пользователя, задайте
CITRUS_UNIX_SOCKET_MODE=0660с общей группой или свойLISTEN_NAMEDPIPE_SDDL. Еслиsecretзадан, он нужен и на сокете, и на канале. - Лимиты соединений контроллера: 10 секунд на заголовки (и TLS), 2 минуты простоя keep-alive, 256 КиБ заголовков.
GET /configsскрывает секреты TUIC и Shadowsocks (******). Читайте их из файла конфига./debug(pprof) требует secret, как и остальной API.
Перезагрузка конфига
Заголовок раздела «Перезагрузка конфига»- Без
force=trueполитика доступа тоже применяется.PUT /configsиsystemctl reload citrusприменяютallow-lan,bind-address,skip-auth-prefixes,lan-allowed-ips,lan-disallowed-ips, встроенныеss-configиtuic-serverпри любой перезагрузке.forceтеперь решает только, переоткрываются ли встроенные порты (port,socks-port,mixed-portи другие) на значениях из файла. - Смена учётных данных закрывает сессии. Если перезагрузка убрала пользователя из
authenticationили сменила ему пароль, его открытые сессии на HTTP, SOCKS и mixed закрываются. Включениеauthenticationзакрывает сессии, пущенные без него. - Пустые имена пользователей запрещены:
authentication: [":pass"]иusersс пустымusernameу socks, http и mixed — ошибка конфига.
Файлы и пути
Заголовок раздела «Файлы и пути»external-uiне может указывать на корень конфигурации. Домашний каталог, каталог файла конфига, корень изSAFE_PATHSили их родитель не принимаются, даже сSKIP_SAFE_PATH_CHECK: обновление UI очищает этот каталог. Используйте подкаталог, например./ui.- Символические ссылки. Путь, который через симлинк или junction уходит за пределы домашнего каталога и
SAFE_PATHS, отклоняется. Например,ui -> /usr/share/metacubexd: добавьте цель ссылки вSAFE_PATHSили задайтеSKIP_SAFE_PATH_CHECK=true. Файл провайдера, который был симлинком, при обновлении заменяется обычным файлом. - Права новых файлов: каталог конфигурации 0700,
config.yaml0600, файлы провайдеров 0600,cache.db0600. Существующие файлы сохраняют свои права.
Провайдеры и загрузки
Заголовок раздела «Провайдеры и загрузки»- Редиректы в частные сети отклоняются. Публичный URL провайдера, rule-set, geodata или дашборда не может перенаправить на loopback, частный, link-local, CGNAT и подобные адреса. Если в конфиге сразу указан частный адрес, ограничения нет.
size-limit: 0означает 64 МиБ, а не «без ограничения»;-1снимает ограничение. Превышение лимита — ошибка обновления, предыдущая копия остаётся (раньше файл обрезался).- Пределы размера: провайдер — не больше 50 000 записей
proxiesи 10 000 построенных прокси;override-expr— не больше 65 536 результатов; логические правила — не глубже 32 уровней скобок. Обычные подписки в эти пределы укладываются.
Входящие
Заголовок раздела «Входящие»-
TLS 1.2 минимум на всех TLS-входящих и на TLS контроллера.
-
HTTP-прокси авторизует каждый запрос. На keep-alive соединении запрос без учётных данных получает 407, с неверными — 403 и закрытие соединения. Без авторизации
Proxy-Authorizationбольше не задаёт пользователя дляIN-USER. Заголовок запроса — не больше 64 КиБ (431). -
SOCKS5 UDP привязан к пользователю и порту. При включённой авторизации датаграммы принимаются только от клиента с открытым UDP ASSOCIATE и только с одного UDP-порта этой ассоциации. Если порт клиента сменился (перепривязка NAT), нужна новая ассоциация. UDP-сессии SOCKS5 теперь учитываются в лимитах и статистике пользователя.
-
Client ID в Snell больше не задаёт пользователя. Его выбирает любой клиент, знающий общий PSK, поэтому он игнорируется: правила
IN-USER, лимиты и статистика по пользователям видят пользователя Snell, только если его проверил ShadowTLS v3 или JLS. У обычного Snell-входа пользователя нет. -
Срок рукопожатия 15 секунд до авторизации: VLESS, Trojan, AnyTLS, Shadowsocks, Snell, HTTP, SOCKS, mixed и HTTP-транспорты. Клиент, который за это время не прислал заголовок, отключается; после авторизации срока нет.
-
Hysteria2 Realm за обратным прокси верит
trusted-proxy-headerтолько от адресов изtrusted-proxies. Пустой список значит «не верить никогда»: перечислите прокси, напримерtrusted-proxies: [loopback]. У VLESS и Trojan так было с самого появленияtrusted-proxy-header. -
Маскировка Hysteria2 по HTTPS проверяет сертификат upstream. Для самоподписанного локального сайта задайте
masquerade-skip-cert-verify: true, иначе ответ будет 502. -
REALITY:
max-time-differenceв миллисекундах, какmaxTimeDiffв Xray (раньше были микросекунды). -
Одинаковый адрес на разных входящих или под разными пользователями получает отдельные UDP-сессии со своими правилами и лимитами.
-
Пользователи серверных входящих не попадают через
DIRECTв сеть сервера. Это касается VLESS, Trojan, Shadowsocks, Snell, TUIC, Hysteria2, AnyTLS, Mieru, Sudoku, TrustTunnel и ShadowQUIC. Им недоступны loopback, частные, link-local, CGNAT и ULA адреса, metadata облака и адреса этого хоста, какие бы ни были правила. Если им нужен доступ к чему-то там, добавьте это вegress-guard.allow-ipsили задайтеegress-guard: falseна listener. Клиентские входящие не затрагиваются. См. защиту исходящего трафика. -
TUIC и TrustTunnel (HTTP/3): серверный
zero-rttпо умолчанию выключен.zero-rtt: trueявно включает ранние данные QUIC, допускающие повторную доставку. ShadowQUIC уже использует такой же выключенный по умолчанию параметр. -
KCPTun: без
keyсохранён известный общий ключ для старых конфигов, но теперь выводится предупреждение. Задайте уникальный случайный ключ;max-sessionsиmax-streamsограничивают сессии сервера и потоки одной сессии (по умолчанию 256/256). -
Sudoku fallback: максимум 256 relay на listener и 64 на источник (IPv4-адрес или IPv6 /64), простой в любом направлении ограничен 60 секундами; активная передача продлевает соединение. Формат handshake и существующие ключи Sudoku сохранены.
-
WebSocket контроллера: основной
secretв?token=по умолчанию больше не принимается. Панель должна получить одноразовый билет черезPOST /auth/ws-ticketс Bearer-заголовком, затем передать?ticket=при подключении. Для старой панели временно включитеexternal-controller-allow-legacy-websocket-token: true; это возвращает риск утечки основного секрета через URL. Описание API.
Исходящие
Заголовок раздела «Исходящие»- REALITY по умолчанию шлёт X25519MLKEM768. Для старых серверов задайте
reality-opts.support-x25519mlkem768: false. - XHTTP: без
reuse-settingsсоединения разделяются, как в Xray (кроме HTTP/1.1);h-max-request-times: "1"отключает это. При данных в заголовках или cookie безuplink-data-keyклиент шлётX-Data-Nиx_data_N, как Xray; если смешиваете версии, задайтеuplink-data-keyявно с обеих сторон. - SSH без
host-keyпо-прежнему подключается, но пишет в лог предупреждение и ключ сервера в формате authorized_keys, чтобы его можно было закрепить.skip-host-key-check: trueявно разрешает любой ключ и убирает предупреждение. - OpenVPN без проверки имени сервера пишет предупреждение. Новые
verify-x509-name,verify-x509-typeиverify-server-nameвключают проверку. - Ссылки
http(s)://иsocks5://больше не включаютskip-cert-verifyсами; только если в ссылке естьskip-cert-verify,allowInsecureилиinsecureсо значением 1 или true. tcp-concurrentнабирает не больше 8 адресов на соединение и 4 одновременно, проигравшие попытки отменяются.- DIRECT подключается к тому адресу, который проверили IP-правила, а не резолвит имя заново.
Обновление ядра
Заголовок раздела «Обновление ядра»/upgrade сверяет пакет с checksums.txt того же релиза. Релиз без этого файла или без строки для пакета не установится; сборки Citrus публикуют его всегда. version.txt проверяется, имена файлов внутри архива игнорируются, zip должен содержать ровно один файл.
Платформы и сборки
Заголовок раздела «Платформы и сборки»Для сборки Citrus нужен Go 1.26 или новее. mihomo публикует ещё и сборки на старых версиях Go (файлы с окончанием -go120, -go122, -go123, -go124, -go125); у Citrus их нет.
- Windows 7/8 и старые macOS: релизы для Windows и macOS собираются пропатченным тулчейном Go от MetaCubeX, который сохраняет работу на этих системах. Отдельно в Citrus они не тестируются.
- Ядра Linux старше 3.2 не поддерживаются: Go 1.24 и новее требуют ядро 3.2.
