В данном гайде будем устанавливать пакет 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 Мб, так что решение что называется на грани.