В данном гайде будем устанавливать пакет sing-box на OpenWRT на примере стабильной 22.03.5 и 23.05.0. Рекомендуется роутер минимум с 128 МБ RAM (256 предпочтительно) и памятью более 16 Мб, так же будет описан способ установки sing-box в оперативную память (подходит для устройств с малым количеством ПЗУ <16 Мб)
Sing-Box — это бесплатная прокси-платформа с открытым исходным кодом, которая позволяет пользователям обходить интернет-цензуру и получать доступ к заблокированным веб-сайтам. Это альтернатива v2ray-core и xray-core. Его можно использовать с различными клиентами таких платформах, как Windows, macOS, Linux, Android и iOS.
Помимо поддержки протоколов Shadowsocks (в т.ч. 2022), Trojan, Vless, Vmess и Socks, он также поддерживает ShadowTLS, Hysteria и NaiveProxy.
Руководство будет включать:
Установку из репозитория
Настройку sing-box для shadowsocks, vless, vmess, trojan и обход блокировок с помощью SagerNet GeoIP, Geosite
Настройку обхода блокировок с помощью GeoIP, Geosite от L11R
Установку sing-box в оперативную память и настройку автозапуска
1. Установка sing-box
UPD 13.10.2023 Репозиторий lrdrdn/my-opkg-repo переориентировался на версию 23.05.0, претерпел изменения, потеряв большую часть пакетов необходимых для установки на 22.03.5, включая sing-box, поэтому заменил репозиторий.
Для версии OpenWRT 22.03.5 необходимо скачать и установить актуальную версию sing-box:
cd /tmp wget https://downloads.openwrt.org/releases/23.05.0/packages/$(grep "OPENWRT_ARCH" /etc/os-release | awk -F '"' '{print $2}')/packages/sing-box_1.8.4-1_$(grep "OPENWRT_ARCH" /etc/os-release | awk -F '"' '{print $2}').ipk opkg install sing-box_*.ipk rm sing-box_*.ipk
Начиная с версии 23.05.0 sing-box есть в стандартном репозитории OpenWRT.
Обновляем список пакетов:
opkg update
Далее устанавливаем необходимые для работы sing-box модули ядра и пакет совместимости с iptables:
opkg install kmod-inet-diag kmod-netlink-diag kmod-tun iptables-nft
Ждём завершения установки, пакеты заняли около 1Мб памяти.
Далее переходим к установке sing-box
opkg install sing-box
Пакет занимает около 10Мб, поэтому установить его на устройства с 16 Мб ПЗУ не удастся без дополнительных манипуляций (об этом в п.3 этой статьи).
Если пакет успешно установлен, переходим к настройке соединения, если нет - переходим к п.3.
2. Настройка sing-box для shadowsocks, reality, vmess, trojan и обход блокировок с помощью SagerNet GeoIP, Geosite
UPD 12.11.2023 Далее переходим к файлу конфигурации, по умолчанию это /etc/sing-box/config.json, но при установке доступен /etc/sing-box/config.json.example В версии 1.6.0 доступен /etc/sing-box/config.json по умолчанию, файла /etc/sing-box/config.json.example при установке больше нету
Удаляем дефолтный /etc/sing-box/config.json:
> /etc/sing-box/config.json
Я приведу пример файла config.json для настройки как Outline VPN (выпуск ключей и их расшифровку на пароль и тип шифрования из формата base64 я рассматривал здесь) так и XTLS-Reality, VMess TLS и Trojan Websocket. В конфигурации используется selector выбирающий только рабочие прокси с помощью urltest. На сайте проекта sing-box, Github юзера malikshi и vpnrouter.homes доступны многочисленные примеры конфигураций для различных протоколов.
Пример config.json:
{ "log": { "disabled": false, "level": "warn", "output": "/tmp/sing-box.log", "timestamp": true }, "dns": { "servers": [ { "tag": "google", "address": "tls://8.8.8.8" }, { "tag": "block", "address": "rcode://success" } ], "final": "google", "strategy": "prefer_ipv4", "disable_cache": false, "disable_expire": false }, "inbounds": [ { "type": "mixed", "tag": "mixed-in", "listen": "127.0.0.1", "listen_port": 1080, "tcp_fast_open": false, "sniff": true, "sniff_override_destination": true, "set_system_proxy": false }, { "type": "tun", "tag": "tun-in", "interface_name": "singtun0", "inet4_address": "172.19.16.1/30", "stack": "gvisor", "mtu": 9000, "auto_route": true, "strict_route": false, "endpoint_independent_nat": false, "sniff": true, "sniff_override_destination": true } ], "outbounds": [ { "type": "selector", "tag": "Proxy-out", "outbounds": [ "URL-Test", "direct", "shadowsocks-out", "vmess-tls-out", "trojan-WebSocket-out", "reality-out" ], "default": "URL-Test" }, { "type": "urltest", "tag": "URL-Test", "outbounds": [ "shadowsocks-out", "vmess-tls-out", "trojan-WebSocket-out", "reality-out" ], "url": "http://www.gstatic.com/generate_204", "interval": "1m", "tolerance": 50 }, { "type": "shadowsocks", "tag": "shadowsocks-out", "server": "IP", "server_port": 15000, "method": "chacha20-ietf-poly1305", "password": "password" }, { "type": "vless", "tag": "reality-out", "server": "IP", "server_port": 8442, "uuid": "UUID", "flow": "xtls-rprx-vision", "network": "tcp", "tls": { "enabled": true, "insecure": false, "server_name": "SERVERNAME", "utls": { "enabled": true, "fingerprint": "chrome" }, "reality": { "enabled": true, "public_key": "AP24JYROAB8odK5glVW_KLnsWl3UZ-voaGq_9ihQgTL" } } }, { "type": "trojan", "tag": "trojan-WebSocket-out", "server": "IP", "server_port": 8443, "password": "PASSWORD", "transport": { "type": "ws", "path": "/", "early_data_header_name": "Sec-WebSocket-Protocol" }, "tls": { "enabled": true, "disable_sni": false, "server_name": "d43f429a97e4ea6d.gstatic.com" }, "multiplex": { "enabled": true, "max_connections": 4, "min_streams": 4, "max_streams": 0 } }, { "type": "vmess", "tag": "vmess-tls-out", "server": "IP", "server_port": 8444, "uuid": "UUID", "security": "auto", "alter_id": 0, "global_padding": false, "authenticated_length": true, "tls": { "enabled": true, "disable_sni": false, "server_name": "google.com", "insecure": false, "alpn": [ "http/1.1" ] }, "multiplex": { "enabled": true, "protocol": "smux", "max_connections": 5, "min_streams": 4, "max_streams": 0 }, "connect_timeout": "5s" }, { "type": "direct", "tag": "direct" }, { "type": "block", "tag": "block" }, { "type": "dns", "tag": "dns-out" } ], "route": { "geoip": { "path": "/tmp/geoip.db", "download_url": "https://github.com/SagerNet/sing-geoip/releases/latest/download/geoip.db", "download_detour": "Proxy-out" }, "geosite": { "path": "/tmp/geosite.db", "download_url": "https://github.com/SagerNet/sing-geosite/releases/latest/download/geosite.db", "download_detour": "Proxy-out" }, "rules": [ { "protocol": "dns", "outbound": "dns-out" }, { "protocol": [ "quic" ], "outbound": "block" }, { "geosite": [ "private", "youtube", "google", "yandex" ], "geoip": [ "private", "ru" ], "ip_cidr": [ "94.100.180.201/32", "94.100.180.202/32" ], "domain_keyword": [ "mail.ru", "vk.com" ], "domain_suffix": [ ".ru" ], "outbound": "direct" } ], "final": "Proxy-out", "auto_detect_interface": true } }
Конфигурация пишет в лог /tmp/sing-box.log предупреждения и ошибки, поднимает socks5 proxy на порту 1080, поднимает туннель singtun0 с помощью kmod-tun и gvisor.
Раздел outbounds содержит конфигурации для XTLS-Reality, VMess TLS и Trojan Websocket:
{ "type": "shadowsocks", "tag": "shadowsocks-out", .... }, { "type": "vless", "tag": "reality-out", .... }, { "type": "trojan", "tag": "trojan-WebSocket-out", .... }, { "type": "vmess", "tag": "vmess-tls-out", ..... },
При необходимости замените или удалите лишние записи, не забыв убрать или добавить их в разделах selector и urltest
"type": "selector", "tag": "Proxy-out", "outbounds": [ "URL-Test", "direct", "shadowsocks-out", "vmess-tls-out", "trojan-WebSocket-out", "reality-out" ], "default": "URL-Test" }, { "type": "urltest", "tag": "URL-Test", "outbounds": [ "shadowsocks-out", "vmess-tls-out", "trojan-WebSocket-out", "reality-out"
В разделе "route" "rules" прописаны правила для прямого подключения к сайтам в зоне .ru и другим незаблокированным ресурсам:
"geosite": "private", "youtube", "google", "yandex" - обозначает домены: частных адресов (включая .local), YouTube и поддомены, сервисы Google, сервисы Яндекса.
"geoip": "private", "ru" - обозначает диапазоны IP адресов: частные адреса, диапазоны IP адресов сегмента .RU
"ip_cidr" - в этом разделе можно указать диапазоны IP адресов которые должны подключаться напрямую минуя прокси
"domain_suffix"
Правило соответствует, если домен запроса соответствует суффиксу. Например: «google.com» соответствует «www.google.com», «mail.google.com» и «google.com», но не соответствует «content-google.com».
"domain_keyword"
Правило соответствует, если домен запроса содержит ключевое слово.
При редактировании json файлов можно пользоваться инструментами вроде JSON Online Validator для проверки форматирования
В раздел outbounds нужно ввести параметры вашего (ваших) прокси: IP, порт, пароль, uuid, public key (если применимо).
параметр download_detour используется для указания способа скачивания баз, в случае конфигурации - через прокси
Для работы используются списки SagerNet от разработчика sing-box, они не содержат списков заблокированных в РФ ресурсов и поэтому многие незаблокированные сайты могут открываться через прокси.
Для работы sing-box необходимо прописать настройки файрволла, для этого:
В файл /etc/config/network добавим:
config interface 'proxy' option proto 'none' option device 'singtun0'
В файл /etc/config/firewall :
config zone option name 'proxy' list network 'tunnel' option forward 'REJECT' option output 'ACCEPT' option input 'REJECT' option masq '1' option mtu_fix '1' option device 'singtun0' option family 'ipv4' config forwarding option name 'lan-proxy' option dest 'proxy' option src 'lan' option family 'ipv4'
После чего перезагружаем сеть:
/etc/init.d/network restart
Далее проверяем работоспособность конфигурации:
sing-box check -c /etc/sing-box/config.json
Если всё правильно команда не выдаст ошибок.
Далее проверяем работу прокси:
sing-box run -c /etc/sing-box/config.json
Работоспособность можно проверить открыв нужный вам сайт.
Если всё сработало, можем добавить sing-box в автозапуск, для этого вводим команды:
Добавим sing-box в автозапуск:
/etc/init.d/sing-box enable /etc/init.d/sing-box start
На этом настройка sing-box завершена.
В случае настройки sing-box на маршрутизацию с помощью firewall4, то есть классическими маршрутами к singtun0, конфигурация /etc/sing-box/config.json будет упрощена и выглядеть так:
{ "log": { "disabled": false, "level": "warn", "output": "/tmp/sing-box.log", "timestamp": true }, "dns": { "servers": [] }, "inbounds": [ { "type": "tun", "tag": "tun-in", "interface_name": "singtun0", "inet4_address": "172.19.16.1/30", "stack": "gvisor", "mtu": 9000, "auto_route": false, "strict_route": false, "endpoint_independent_nat": false, "sniff": true, "sniff_override_destination": true } ], "outbounds": [ { "type": "selector", "tag": "Proxy-out", "outbounds": [ "URL-Test", "direct", "shadowsocks-out", "vmess-tls-out", "trojan-WebSocket-out", "reality-out" ], "default": "URL-Test" }, { "type": "urltest", "tag": "URL-Test", "outbounds": [ "shadowsocks-out", "vmess-tls-out", "trojan-WebSocket-out", "reality-out" ], "url": "http://www.gstatic.com/generate_204", "interval": "1m", "tolerance": 50 }, { "type": "shadowsocks", "tag": "shadowsocks-out", "server": "IP", "server_port": 15000, "method": "chacha20-ietf-poly1305", "password": "password" }, { "type": "vless", "tag": "reality-out", "server": "IP", "server_port": 8442, "uuid": "UUID", "flow": "xtls-rprx-vision", "network": "tcp", "tls": { "enabled": true, "insecure": false, "server_name": "SERVERNAME", "utls": { "enabled": true, "fingerprint": "chrome" }, "reality": { "enabled": true, "public_key": "AP24JYROAB8odK5glVW_KLnsWl3UZ-voaGq_9ihQgTL" } } }, { "type": "trojan", "tag": "trojan-WebSocket-out", "server": "IP", "server_port": 8443, "password": "PASSWORD", "transport": { "type": "ws", "path": "/", "early_data_header_name": "Sec-WebSocket-Protocol" }, "tls": { "enabled": true, "disable_sni": false, "server_name": "d43f429a97e4ea6d.gstatic.com" }, "multiplex": { "enabled": true, "max_connections": 4, "min_streams": 4, "max_streams": 0 } }, { "type": "vmess", "tag": "vmess-tls-out", "server": "IP", "server_port": 8444, "uuid": "UUID", "security": "auto", "alter_id": 0, "global_padding": false, "authenticated_length": true, "tls": { "enabled": true, "disable_sni": false, "server_name": "google.com", "insecure": false, "alpn": [ "http/1.1" ] }, "multiplex": { "enabled": true, "protocol": "smux", "max_connections": 5, "min_streams": 4, "max_streams": 0 }, "connect_timeout": "5s" }, { "type": "direct", "tag": "direct" }, { "type": "block", "tag": "block" } ], "route": { "rules": [], "final": "Proxy-out", "auto_detect_interface": true } }
Для настройки самих маршрутов или BGP рекомендую статьи:
Точечный обход блокировок на роутере OpenWrt c помощью BGP / Хабр (habr.com) С помощью BGP (bird2).
Точечный обход блокировок PKH на роутере с OpenWrt с помощью WireGuard и DNSCrypt / Хабр (habr.com) (путём скачивания списков и настройкой маршрутов в iptables, nftables).
3. Настройка обхода блокировок с помощью GeoIP, Geosite от L11R
Данный способ с GeoIP и Geosite содержащие весь дамп базы РКН (автор данных файлов @L11R, огромная ему за это благодарность). К сожалению данный способ требователен к количеству ОЗУ, у меня запустилось минимум с 384 МБ, иначе срабатывал memory killer. Удобство способа в том, что является заменой BGP (или скачивания списков), трафик на адреса из баз идёт через прокси, всё остальное напрямую.
Пример такого config.json:
{ "log": { "disabled": false, "level": "warn", "output": "/tmp/sing-box.log", "timestamp": true }, "dns": { "servers": [ { "tag": "google", "address": "tls://8.8.8.8" }, { "tag": "block", "address": "rcode://success" } ], "final": "google", "strategy": "prefer_ipv4", "disable_cache": false, "disable_expire": false }, "inbounds": [ { "type": "mixed", "tag": "mixed-in", "listen": "127.0.0.1", "listen_port": 1080, "tcp_fast_open": false, "sniff": true, "sniff_override_destination": true, "set_system_proxy": false }, { "type": "tun", "tag": "tun-in", "interface_name": "singtun0", "inet4_address": "172.19.16.1/30", "stack": "gvisor", "mtu": 9000, "auto_route": true, "strict_route": false, "endpoint_independent_nat": false, "sniff": true, "sniff_override_destination": true } ], "outbounds": [ { "type": "selector", "tag": "Proxy-out", "outbounds": [ "URL-Test", "direct", "shadowsocks-out", "vmess-tls-out", "trojan-WebSocket-out", "reality-out" ], "default": "URL-Test" }, { "type": "urltest", "tag": "URL-Test", "outbounds": [ "shadowsocks-out", "vmess-tls-out", "trojan-WebSocket-out", "reality-out" ], "url": "http://www.gstatic.com/generate_204", "interval": "1m", "tolerance": 50 }, { "type": "shadowsocks", "tag": "shadowsocks-out", "server": "IP", "server_port": 15000, "method": "chacha20-ietf-poly1305", "password": "password" }, { "type": "vless", "tag": "reality-out", "server": "IP", "server_port": 8442, "uuid": "UUID", "flow": "xtls-rprx-vision", "network": "tcp", "tls": { "enabled": true, "insecure": false, "server_name": "SERVERNAME", "utls": { "enabled": true, "fingerprint": "chrome" }, "reality": { "enabled": true, "public_key": "AP24JYROAB8odK5glVW_KLnsWl3UZ-voaGq_9ihQgTL" } } }, { "type": "trojan", "tag": "trojan-WebSocket-out", "server": "IP", "server_port": 8443, "password": "PASSWORD", "transport": { "type": "ws", "path": "/", "early_data_header_name": "Sec-WebSocket-Protocol" }, "tls": { "enabled": true, "disable_sni": false, "server_name": "d43f429a97e4ea6d.gstatic.com" }, "multiplex": { "enabled": true, "max_connections": 4, "min_streams": 4, "max_streams": 0 } }, { "type": "vmess", "tag": "vmess-tls-out", "server": "IP", "server_port": 8444, "uuid": "UUID", "security": "auto", "alter_id": 0, "global_padding": false, "authenticated_length": true, "tls": { "enabled": true, "disable_sni": false, "server_name": "google.com", "insecure": false, "alpn": [ "http/1.1" ] }, "multiplex": { "enabled": true, "protocol": "smux", "max_connections": 5, "min_streams": 4, "max_streams": 0 }, "connect_timeout": "5s" }, { "type": "direct", "tag": "direct" }, { "type": "block", "tag": "block" }, { "type": "dns", "tag": "dns-out" } ], "route": { "geoip": { "path": "/etc/sing-box/geoip.db", "download_url": "https://github.com/savely-krasovsky/antizapret-sing-box/releases/latest/download/geoip.db", "download_detour": "Proxy-out" }, "geosite": { "path": "/etc/sing-box/geosite.db", "download_url": "https://github.com/savely-krasovsky/antizapret-sing-box/releases/latest/download/geosite.db", "download_detour": "Proxy-out" }, "rules": [ { "protocol": "dns", "outbound": "dns-out" }, { "geoip": "antizapret", "geosite": "antizapret", "outbound": "Proxy-out" }, { "protocol": "quic", "outbound": "block" } ], "final": "direct", "auto_detect_interface": true } }
Если из конфигурации убрать строки:
{ "type": "mixed", "tag": "mixed-in", "listen": "127.0.0.1", "listen_port": 1080, "tcp_fast_open": false, "sniff": true, "sniff_override_destination": true, "set_system_proxy": false },
и "path": "/etc/sing-box/geoip.db" , "path": "/etc/sing-box/geosite.db",
То конфигурацию можно использовать и в клиенте sing-box на Android и других платформах
4. Установка sing-box в оперативную память
Если установить sing-box в ПЗУ не удалось (а это вполне вероятный сценарий для большинства роутеров среднего ценового сегмента), возможно произвести установку в ОЗУ и подгружать пакет при запуске устройства.
Установленный и запущенный sing-box занимает около 35 Мб ОЗУ.
Для начала нам необходимо установить в ПЗУ модули ядра и iptables-nft
opkg install kmod-inet-diag kmod-netlink-diag kmod-tun iptables-nft
Это должно занять около 1Мб памяти, после чего установим sing-box в ОЗУ:
opkg install sing-box -d ram
Если всё успешно установилось, далее нужно будет создать папку конфигурации:
mkdir /etc/sing-box
После чего помещаете ваш файл config.json из п.2 в /etc/sing-box/config.json
Проверяем работу прокси (более подробно в п.2):
/tmp/usr/bin/sing-box run -c /etc/sing-box/config.json
Если всё заработало, далее настраиваем автозапуск sing-box.
Для автоматической установки пакета при загрузке системы в файл /etc/rc.local добавляем строки перед exit 0
opkg update opkg install sing-box -d ram exit 0
при помощи текстового редактора, либо через Luci

Сохраняем изменения и создаём службу автозапуска для sing-box.
Создаём файл /etc/init.d/sing-box следующего содержания:
#!/bin/sh /etc/rc.common # # Copyright (C) 2022 by nekohasekai <contact-sagernet@sekai.icu> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # START=99 USE_PROCD=1 ##### ONLY CHANGE THIS BLOCK ###### PROG=/tmp/usr/bin/sing-box # Положение sing-box в ОЗУ RES_DIR=/etc/sing-box/ # resource dir / working dir / the dir where you store ip/domain lists CONF=./config.json # where is the config file, it can be a relative path to $RES_DIR ##### ONLY CHANGE THIS BLOCK ###### start_service() { sleep 10 # Ожидание скачивания пакета sing-box при загрузке системы procd_open_instance procd_set_param command $PROG run -D $RES_DIR -c $CONF procd_set_param user root procd_set_param limits core="unlimited" procd_set_param limits nofile="1000000 1000000" procd_set_param stdout 1 procd_set_param stderr 1 procd_set_param respawn "${respawn_threshold:-3600}" "${respawn_timeout:-5}" "${respawn_retry:-5}" procd_close_instance iptables -I FORWARD -o singtun+ -j ACCEPT #Эта строка будет выдавать ошибку, если iptables-nft не установлен echo "sing-box is started!" } stop_service() { service_stop $PROG iptables -D FORWARD -o singtun+ -j ACCEPT echo "sing-box is stopped!" } reload_service() { stop sleep 5s echo "sing-box is restarted!" start }
Делаем файл исполняемым:
chmod +x /etc/init.d/sing-box
После чего добавляем в автозапуск:
/etc/init.d/sing-box enable /etc/init.d/sing-box start
На этом настройка окончена.
P.S. 35 Мб это достаточно большой объём занимаемой оперативной памяти для роутера со 128 Мб, так что решение что называется на грани.
