OrangePi R2S: Строим Linux-роутер на доступном восьмиядерном RISC-V одноплатнике с портами 2.5G
- Цена: $50 (2GB) | $77 (4GB) | $115 (8GB)
- Перейти в магазин
Друзья, привет!
Не так давно мы смотрели на одноплатный SBC-роутер Orange Pi R2S на архитектуре RISC-V. Тогда мы поверхностно окунулись в архитектуру, посмотрели, насколько это жизнеспособно в качестве домашнего сервера. В этом обзоре не будет повторов и мы не будем ходить вокруг да около, а будем тестировать устройство исключительно по его прямому назначению — в качестве DIY Linux-роутера. Забегая наперёд, я продал свой Keenetic и перешёл на модульную систему (Orange Pi R2S + Wi-Fi точка доступа). В этом обзоре протестируем его сетевые возможности, включая 2.5G порты, VPN-протоколы, USB в паре с DAS, а также попытаемся понять, это универсальное решение или нишевая история, в чём преимущества и недостатки и что интересного я смог на нём реализовать. Приглашаю ↓


ТЕХНИЧЕСКИЕ ХАРАКТЕРИСТИКИ
- Процессор: Ky X1, 8 ядер, архитектура RISC-V AI (производительность ИИ — 2.0 TOPS)
- Оперативная память: LPDDR4X: 2 ГБ / 4 ГБ / 8 ГБ
- Накопитель: eMMC: 8 ГБ
- Сетевые интерфейсы:
- 2.5G Ethernet — 2 порта
- 1000M Ethernet (гигабитный) — 2 порта
- USB:
- USB 3.0 — 1 порт
- USB 2.0 — 1 порт (может использоваться для обновления ПО и прошивки)
- Кнопки: Кнопка MASKROM — 1 шт.
- Индикаторы состояния:
- Индикатор питания — 1 шт.
- Индикатор 1000M Ethernet — 2 шт.
- Индикатор 2.5G Ethernet — 2 шт.
- Отладка (DEBUG): 3-контактный (3PIN) последовательный порт отладки, уровень напряжения 3.3 В
- Питание: Разъем Type-C, 5 В / 3 А (постоянный ток)
- Размеры платы (PCB): 79.2 * 46 * 1.6 мм
- Поддерживаемые ОС: OpenWrt, Ubuntu



Начиная этот обзор, хочу сразу отметить, что он не является инструкцией. Это именно обзор продукта — Orange Pi R2S и его возможностей.
Сама плата достаточно компактная, лёгкая и горячая в нагрузке. У меня без радиатора уходила до 90 градусов. Но стоило поставить простой рандомный пассивный радиатор на термопрокладке, температура сразу упала до комфортных 60. Стоит иметь это в виду. Также существенно нагреваются сетевые порты (особенно 2.5G). Поэтому радиаторы очень желательно поставить и на них. Планирую купить для обслуживания видеокарты жидкую термопрокладку Tputty607, заодно посажу нормально радиаторы на Orange Pi R2S.


К сожалению, порта MicroSD нет. Только проприетарный разъём для её установки, но соответствующего адаптера я в продаже не увидел. SPI нет, загрузчик U-Boot на несъёмной eMMC. Поэтому можно пойти двумя путями: или держать на eMMC только загрузчик, а систему установить на USB 3.0 носитель (производитель предусмотрел такую возможность), или пользоваться eMMC, но быть готовым к тому, что при интенсивной записи/чтении системной памяти в будущем, возможно, придётся перепаивать. В целом я посмотрел свою конфигурацию, использование вполне щадящее, настроил буферы в ОЗУ на кэш, поэтому я заморачиваться не буду, думаю, одноплатник скорее устареет, чем на нём отвалится eMMC. Но здесь каждый для себя должен сам решить. В целом пространство для манёвра есть, и это хорошо.
TTL UART работает без нареканий. Можно подключить на скорости 115200 и работать в консоли, аналогичной той, которая открывается по SSH.

Первым делом я попытался собрать свою конфигурацию на OpenWrt, но после того, как он мне гордо заявил, что одного из компонентов для WireGuard, а именно kmod-wireguard, нет ни в одном репозитории под riscv64, я поднял WireGuard на Go и, взглянув на скорости, пришёл к выводу, что пока в OpenWrt не появится полноценная поддержка данного SBC, лучше искать альтернативу. Я не расстроился, так как для R2S также есть Ubuntu 24.04, которая мне более привычна и, по моему мнению, даёт значительно больше возможностей, чем OpenWrt. Правда, больше телодвижений, но ведь один раз настроил — и потом пользуешься.
МАРШРУТИЗАЦИЯ
Linux прекрасно работает с сетью, но всё настраивается вручную. Я могу назвать себя достаточно продвинутым пользователем ПК, но при этом я не IT-шник. С опытом работы с терминалом Linux уже есть стойкое понимание многих базовых вещей, однако это всё ещё очень далеко от полного понимания многих процессов. Но это, собственно, сейчас так же нужно, как математические расчёты в уме. Нам на самом деле очень повезло: мы первые, кто является свидетелями научно-технического прогресса беспрецедентного уровня. Думаю, далеко не каждый осознаёт, насколько важные процессы сейчас происходят в этом направлении. Мы живём в информационную эру, и сейчас человечеству доступен очень важный инструмент — искусственный интеллект. Это не волшебная палочка, с ним нужно уметь правильно работать. Не всегда получается, как хочешь, иногда нужно уметь распознать, когда он не понимает, что от него хотят или свернул не туда, видеть неточности в результатах и, основываясь на этом, направлять в нужную канву. Но даже на нынешнем уровне вещи, которые он способен делать — фантастические.

У одноплатника есть 4 сетевых интерфейса: два 1G и два 2.5G. Нужно определиться, какой порт будет использоваться в WAN, остальные объединить в мост. В отличие от многих роутеров, здесь нет аппаратного сетевого ускорителя, но так как сам восьмиядерный чип Ky X1 достаточно производительный, маршрутизация на уровне SoC не является проблемой.
После создания моста нужно поднять DHCP, чтобы роутеру был присвоен статичный IP и статичная сеть (192.168.1.0/24) и, конечно, DNS, через который будут стучаться сетевые запросы. Это можно сделать из-под интерфейса, через AdGuard Home, но я с ним не подружился: у меня от его использования тупит интернет (даже без фильтрации), поэтому я пошёл путём проверенных решений. Установил пакет dnsmasq и в его конфиге (/etc/dnsmasq.conf) прописал:
# Интерфейс локальной сети
interface=br0
# Внешние DNS-серверы
server=1.1.1.1
server=1.0.0.1
server=8.8.8.8
# Не пересылать адреса без доменной части и локальные запросы на внешние DNS
domain-needed
bogus-priv
# Диапазон DHCP (от .100 до .200, время аренды 12 часов)
dhcp-range=192.168.1.100,192.168.1.200,255.255.255.0,12h
# Параметры DHCP для клиентов: Шлюз (192.168.1.1) и DNS (192.168.1.1)
dhcp-option=option:router,192.168.1.1
dhcp-option=option:dns-server,192.168.1.1
# ---------------------------------------------------------
# Статические IP-адреса клиентов (MAC, Имя, IP)
# ---------------------------------------------------------
dhcp-host=aa:bb:cc:dd:ee:ff,pc,192.168.1.2
Затем, чтобы встроенный systemd-resolved не перехватывал 53 порт (DNS), я направил символической ссылкой /etc/resolv.conf на работающий DNS:
sudo rm /etc/resolv.conf
sudo ln -s /run/systemd/resolve/resolv.conf /etc/resolv.conf
sudo systemctl restart systemd-resolved
sudo systemctl restart dnsmasq
sudo systemctl enable dnsmasq
Как это в итоге работает? У роутера IP 192.168.1.1. При подключении клиентов им даётся аренда на 12 часов из диапазона 192.168.1.100 – 192.168.1.200, после этого присваивается другой рандомный IP. Постояльцев сети можно зарегистрировать вручную в таблице (которую можно дополнять), чтобы предоставить им постоянный статический IP-адрес.
Безусловно, можно было бы так и оставить, но как человек, избалованный интерфейсом Keenetic, я захотел веб-интерфейс, чтобы можно было вносить правки в /etc/dnsmasq.conf интерактивно, из лёгкого веб-интерфейса. И ИИ сделал это для меня на базе python3-flask! Мы несколько раз меняли логику работы, принцип, включали сортировку, автоматическое определение новых клиентов, переключение политик (обычное подключение или один из WireGuard-интерфейсов), а также Wildcard DNS перенаправления. У меня на VPS-сервере есть NPMPlus, и я сделал так, чтобы все запросы доменов .local шли через него, ну и также внутренние перенаправления, например 192.168.1.1 – orangepi.lan, и этот адрес я могу вводить вместо IP, к примеру, в Samba. Сейчас у меня появилась вообще шикарная идея: отказаться от NPMPlus и добавить в скрипт 3-й блок — “Reverse Proxy” на базе Caddy, в который я буду вписывать домен, IP и порт, а Caddy будет переправлять эти порты на 80-й. Но это уже будет совсем другая история)



Вышло реально Keenetic style, хотя по мне даже лучше, так как всё это на одной странице и именно так, как я этого хотел и как я это видел у себя в голове.
Когда появляется новый клиент — его предлагает добавить на постоянной основе, можно прописать имя и задать целевой IP. Насчёт имени: предусмотрена “защита от дурака”, которая отсекает нежелательные символы и делает транслитерацию из кириллицы. После нажатия кнопки “Сохранить и применить маршруты” скрипт вносит изменения в файл dnsmasq.conf и перезагружает dnsmasq.
Выглядит это так:

Ушло, конечно, определённое количество времени на создание этого инструмента, но оно того однозначно стоило, ведь как я уже говорил — один раз настроил, а потом пользуешься.
По моему мнению, это получилось настолько хорошо, что я даже поделюсь кодом, кому понадобится — сможет адаптировать под себя:
Шаг 1. Установка Flask и создание структуры
Установите минимальные библиотеки Python:
Bash
sudo apt update
sudo apt install -y python3-flask
Создайте папку для веб-сервиса:
mkdir -p /opt/dnsmasq-web/templates
cd /opt/dnsmasq-web
Шаг 2. Создание файла скрипта app.py
Откройте app.py:
Bash
sudo nano /opt/dnsmasq-web/app.py
И вставьте следующий текст:
import json
import re
import subprocess
from flask import Flask, render_template, request, redirect, url_for, jsonify
app = Flask(__name__)
CONFIG_PATH = '/etc/dnsmasq.conf'
LEASES_PATH = '/var/lib/misc/dnsmasq.leases'
PBR_RULES_PATH = '/etc/pbr-rules.json'
CYR_TO_LAT = {
'а': 'a', 'б': 'b', 'в': 'v', 'г': 'g', 'д': 'd', 'е': 'e', 'ё': 'yo',
'ж': 'zh', 'з': 'z', 'и': 'i', 'й': 'y', 'к': 'k', 'л': 'l', 'м': 'm',
'н': 'n', 'о': 'o', 'п': 'p', 'р': 'r', 'с': 's', 'т': 't', 'у': 'u',
'ф': 'f', 'х': 'h', 'ц': 'ts', 'ч': 'ch', 'ш': 'sh', 'щ': 'sch', 'ъ': '',
'ы': 'y', 'ь': '', 'э': 'e', 'ю': 'yu', 'я': 'ya'
}
def sanitize_hostname(name):
name = name.strip().lower()
res = [CYR_TO_LAT.get(char, char) for char in name]
name = "".join(res)
name = re.sub(r'[\s_]+', '-', name)
name = re.sub(r'[^a-z0-9\-]', '', name)
return name.strip('-') if name.strip('-') else "device"
def get_pbr_modes():
try:
with open(PBR_RULES_PATH, 'r') as f:
return json.load(f)
except Exception:
return {}
def save_pbr_modes(modes):
try:
with open(PBR_RULES_PATH, 'w') as f:
json.dump(modes, f, indent=2)
except Exception as e:
print(f"Error saving PBR rules: {e}")
def apply_pbr_rule(ip, mode):
# Очищаем правила для данного IP из обеих таблиц
subprocess.run(['ip', 'rule', 'del', 'from', ip, 'table', '100'], stderr=subprocess.DEVNULL)
subprocess.run(['ip', 'rule', 'del', 'from', ip, 'table', '101'], stderr=subprocess.DEVNULL)
# Применяем нужную таблицу
if mode == 'ORACLE':
subprocess.run(['ip', 'rule', 'add', 'from', ip, 'table', '100'])
elif mode == 'WARP':
subprocess.run(['ip', 'rule', 'add', 'from', ip, 'table', '101'])
# При DIRECT (No VPN) никаких правил не нужно — трафик идёт через стандартный дефолтный шлюз системы
def read_data():
saved_hosts = []
dns_redirects = []
saved_macs = set()
pbr_modes = get_pbr_modes()
try:
with open(CONFIG_PATH, 'r') as f:
for line in f:
line = line.strip()
if line.startswith('dhcp-host='):
parts = line.replace('dhcp-host=', '').split(',')
if len(parts) >= 3:
mac = parts[0].strip().lower()
ip = parts[2].strip()
saved_hosts.append({
'mac': mac,
'name': parts[1].strip(),
'ip': ip,
'mode': pbr_modes.get(ip, 'DIRECT')
})
saved_macs.add(mac)
elif line.startswith('address=/'):
parts = line.replace('address=/', '').split('/')
if len(parts) >= 2:
# Убираем ведущую точку при чтении для чистого отображения
domain_clean = parts[0].strip().lstrip('.')
dns_redirects.append({
'domain': domain_clean,
'ip': parts[1].strip()
})
except Exception as e:
print(f"Error reading config: {e}")
leases = []
try:
with open(LEASES_PATH, 'r') as f:
for line in f:
parts = line.strip().split()
if len(parts) >= 4:
mac = parts[1].strip().lower()
ip = parts[2].strip()
hostname = parts[3].strip()
if hostname == '*':
hostname = 'new-device'
if mac not in saved_macs:
leases.append({
'mac': mac,
'ip': ip,
'name': hostname
})
except Exception as e:
print(f"Error reading leases: {e}")
return saved_hosts, dns_redirects, leases
@app.route('/')
def index():
hosts, dns_redirects, new_devices = read_data()
return render_template('index.html', hosts=hosts, dns_redirects=dns_redirects, new_devices=new_devices)
@app.route('/save', methods=['POST'])
def save():
macs = request.form.getlist('mac')
names = request.form.getlist('name')
ips = request.form.getlist('ip')
modes = request.form.getlist('mode')
domains = request.form.getlist('dns_domain')
dns_ips = request.form.getlist('dns_ip')
non_managed_lines = []
try:
with open(CONFIG_PATH, 'r') as f:
for line in f:
sline = line.strip()
if not sline.startswith('dhcp-host=') and not sline.startswith('address=/'):
non_managed_lines.append(line)
except Exception as e:
print(f"Error reading original config: {e}")
new_host_lines = []
pbr_dict = {}
for mac, name, ip, mode in zip(macs, names, ips, modes):
if mac.strip() and ip.strip():
clean_name = sanitize_hostname(name)
clean_ip = ip.strip()
new_host_lines.append(f"dhcp-host={mac.strip()},{clean_name},{clean_ip}\n")
apply_pbr_rule(clean_ip, mode)
pbr_dict[clean_ip] = mode
save_pbr_modes(pbr_dict)
new_dns_lines = []
for domain, dns_ip in zip(domains, dns_ips):
d_clean = domain.strip().lstrip('*').strip('.')
if d_clean and dns_ip.strip():
# Записываем без принудительной точки перед доменом
new_dns_lines.append(f"address=/{d_clean}/{dns_ip.strip()}\n")
with open(CONFIG_PATH, 'w') as f:
f.writelines(non_managed_lines)
if non_managed_lines and not non_managed_lines[-1].endswith('\n'):
f.write('\n')
f.write('# --- Wildcard & Specific DNS Redirects ---\n')
f.writelines(new_dns_lines)
f.write('# --- Static DHCP Hosts ---\n')
f.writelines(new_host_lines)
subprocess.run(['systemctl', 'restart', 'dnsmasq'])
return redirect(url_for('index'))
@app.route('/api/pbr', methods=['GET'])
def api_get_pbr():
ip = request.args.get('ip')
if not ip:
return jsonify({'error': 'Missing ip parameter'}), 400
pbr_modes = get_pbr_modes()
mode = pbr_modes.get(ip, 'DIRECT')
return jsonify({'ip': ip, 'mode': mode})
@app.route('/api/pbr', methods=['POST'])
def api_set_pbr():
data = request.get_json() or {}
ip = data.get('ip') or request.form.get('ip')
mode = data.get('mode') or request.form.get('mode')
if not ip or mode not in ['DIRECT', 'ORACLE', 'WARP']:
return jsonify({'error': 'Invalid ip or mode'}), 400
apply_pbr_rule(ip, mode)
pbr_modes = get_pbr_modes()
pbr_modes[ip] = mode
save_pbr_modes(pbr_modes)
return jsonify({'status': 'ok', 'ip': ip, 'mode': mode})
if __name__ == '__main__':
app.run(host='0.0.0.0', port=3030)
И сам веб-интерфейс (index.html)
Введите код:
sudo nano /opt/dnsmasq-web/templates/index.html
Вставьте следующий текст:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>DNSMasq & Routing Manager</title>
<style>
body { font-family: system-ui, -apple-system, sans-serif; background: #121212; color: #e0e0e0; padding: 20px; }
.container { max-width: 1000px; margin: 0 auto; background: #1e1e1e; padding: 20px; border-radius: 8px; box-shadow: 0 4px 10px rgba(0,0,0,0.5); }
h2 { margin-top: 0; color: #4caf50; }
h3 { color: #2196f3; margin-top: 30px; border-bottom: 1px solid #333; padding-bottom: 5px; }
.h3-new { color: #ff9800; border: none; margin-top: 0; }
table { width: 100%; border-collapse: collapse; margin-bottom: 15px; }
th, td { padding: 8px 12px; text-align: left; border-bottom: 1px solid #333; }
th { cursor: pointer; background: #2a2a2a; user-select: none; }
th:hover { background: #333; }
input[type="text"], select { width: 95%; padding: 6px; background: #2b2b2b; border: 1px solid #444; color: #fff; border-radius: 4px; }
select { cursor: pointer; font-weight: bold; }
.btn { padding: 8px 16px; border: none; border-radius: 4px; cursor: pointer; font-weight: bold; }
.btn-save { background: #4caf50; color: white; font-size: 16px; }
.btn-add { background: #2196f3; color: white; margin-right: 10px; }
.btn-del { background: #f44336; color: white; padding: 4px 10px; }
.btn-claim { background: #ff9800; color: #121212; padding: 4px 10px; font-weight: bold; }
.actions { display: flex; justify-content: space-between; align-items: center; margin-top: 25px; }
.new-box { background: #262118; border: 1px solid #523b12; padding: 15px; border-radius: 6px; margin-top: 25px; }
.hint { font-size: 12px; color: #888; margin-top: -5px; margin-bottom: 10px; }
</style>
</head>
<body>
<div class="container">
<h2>DNSMasq & Routing Manager</h2>
<form action="/save" method="post" id="mainForm">
<!-- СЕКЦИЯ 1: DHCP HOSTS -->
<h3>1. Статические DHCP Клиенты и Маршрутизация</h3>
<table id="hostsTable">
<thead>
<tr>
<th onclick="sortTable('hostsTable', 0, false)">Имя ▲▼</th>
<th onclick="sortTable('hostsTable', 1, false)">MAC Адрес ▲▼</th>
<th onclick="sortTable('hostsTable', 2, true)">IP Адрес ▲▼</th>
<th style="width: 160px;">Маршрут</th>
<th style="width: 50px;"></th>
</tr>
</thead>
<tbody>
{% for host in hosts %}
<tr>
<td><input type="text" name="name" value="{{ host.name }}"></td>
<td><input type="text" name="mac" value="{{ host.mac }}"></td>
<td><input type="text" name="ip" value="{{ host.ip }}"></td>
<td>
<select name="mode">
<option value="DIRECT" {% if host.mode == 'DIRECT' %}selected{% endif %}>⚪ Direct (No VPN)</option>
<option value="ORACLE" {% if host.mode == 'ORACLE' %}selected{% endif %}> VPN Oracle (wg0)</option>
<option value="WARP" {% if host.mode == 'WARP' %}selected{% endif %}>⚡ WARP (wg-warp)</option>
</select>
</td>
<td><button type="button" class="btn btn-del" onclick="deleteRow(this)">X</button></td>
</tr>
{% endfor %}
</tbody>
</table>
<button type="button" class="btn btn-add" onclick="addHostRow()">+ Устройство</button>
<!-- СЕКЦИЯ 2: WILDCARD DNS -->
<h3>2. DNS Перенаправления (DNS Records / Wildcard)</h3>
<p class="hint">Укажите доменную зону (например, <code>local</code> для всех *.local) или конкретный хост (например, <code>orangepi.local</code>).</p>
<table id="dnsTable">
<thead>
<tr>
<th onclick="sortTable('dnsTable', 0, false)">Домен / Зона ▲▼</th>
<th onclick="sortTable('dnsTable', 1, true)">Целевой IP ▲▼</th>
<th style="width: 50px;"></th>
</tr>
</thead>
<tbody>
{% for dns in dns_redirects %}
<tr>
<td><input type="text" name="dns_domain" value="{{ dns.domain }}" placeholder="local или pc.local"></td>
<td><input type="text" name="dns_ip" value="{{ dns.ip }}" placeholder="192.168.1.X"></td>
<td><button type="button" class="btn btn-del" onclick="deleteRow(this)">X</button></td>
</tr>
{% endfor %}
</tbody>
</table>
<button type="button" class="btn btn-add" onclick="addDnsRow()">+ DNS Зону</button>
<!-- СЕКЦИЯ 3: НОВЫЕ УСТРОЙСТВА -->
{% if new_devices %}
<div class="new-box">
<h3 class="h3-new">Обнаружены новые устройства в сети</h3>
<table>
<thead>
<tr>
<th>Имя</th>
<th>MAC Адрес</th>
<th>Текущий IP</th>
<th>Действие</th>
</tr>
</thead>
<tbody>
{% for dev in new_devices %}
<tr>
<td>{{ dev.name }}</td>
<td><code>{{ dev.mac }}</code></td>
<td>{{ dev.ip }}</td>
<td>
<button type="button" class="btn btn-claim" onclick="claimDevice('{{ dev.name }}', '{{ dev.mac }}', '{{ dev.ip }}', this)">
+ Закрепить IP
</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
<div class="actions">
<div></div>
<button type="submit" class="btn btn-save">Сохранить и применить маршруты</button>
</div>
</form>
</div>
<script>
function claimDevice(name, mac, ip, btn) {
const tbody = document.querySelectorAll('#hostsTable tbody')[0];
const tr = document.createElement('tr');
tr.innerHTML = `
<td><input type="text" name="name" value="${name}"></td>
<td><input type="text" name="mac" value="${mac}"></td>
<td><input type="text" name="ip" value="${ip}"></td>
<td>
<select name="mode">
<option value="DIRECT" selected>⚪ Direct (No VPN)</option>
<option value="ORACLE"> VPN Oracle (wg0)</option>
<option value="WARP">⚡ WARP (wg-warp)</option>
</select>
</td>
<td><button type="button" class="btn btn-del" onclick="deleteRow(this)">X</button></td>
`;
tbody.appendChild(tr);
btn.parentNode.parentNode.remove();
}
function addHostRow() {
const tbody = document.querySelectorAll('#hostsTable tbody')[0];
const tr = document.createElement('tr');
tr.innerHTML = `
<td><input type="text" name="name" placeholder="new-device"></td>
<td><input type="text" name="mac" placeholder="00:00:00:00:00:00"></td>
<td><input type="text" name="ip" placeholder="192.168.1.X"></td>
<td>
<select name="mode">
<option value="DIRECT" selected>⚪ Direct (No VPN)</option>
<option value="ORACLE"> VPN Oracle (wg0)</option>
<option value="WARP">⚡ WARP (wg-warp)</option>
</select>
</td>
<td><button type="button" class="btn btn-del" onclick="deleteRow(this)">X</button></td>
`;
tbody.appendChild(tr);
}
function addDnsRow() {
const tbody = document.querySelectorAll('#dnsTable tbody')[0];
const tr = document.createElement('tr');
tr.innerHTML = `
<td><input type="text" name="dns_domain" placeholder="local или pc.local"></td>
<td><input type="text" name="dns_ip" placeholder="192.168.1.X"></td>
<td><button type="button" class="btn btn-del" onclick="deleteRow(this)">X</button></td>
`;
tbody.appendChild(tr);
}
function deleteRow(btn) {
btn.parentNode.parentNode.remove();
}
function ipToNumArray(ip) {
return ip.split('.').map(num => parseInt(num, 10) || 0);
}
function sortTable(tableId, colIndex, isIpColumn) {
const table = document.getElementById(tableId);
let rows = Array.from(table.rows).slice(1);
let dir = table.getAttribute("data-sort-dir") === "asc" ? "desc" : "asc";
table.setAttribute("data-sort-dir", dir);
rows.sort((a, b) => {
let inputA = a.cells[colIndex].querySelector('input');
let valA = inputA ? inputA.value.trim() : a.cells[colIndex].innerText.trim();
let inputB = b.cells[colIndex].querySelector('input');
let valB = inputB ? inputB.value.trim() : b.cells[colIndex].innerText.trim();
if (isIpColumn) {
let numA = ipToNumArray(valA);
let numB = ipToNumArray(valB);
for (let i = 0; i < 4; i++) {
if (numA[i] !== numB[i]) {
return dir === "asc" ? numA[i] - numB[i] : numB[i] - numA[i];
}
}
return 0;
} else {
valA = valA.toLowerCase();
valB = valB.toLowerCase();
if (valA < valB) return dir === "asc" ? -1 : 1;
if (valA > valB) return dir === "asc" ? 1 : -1;
return 0;
}
});
rows.forEach(row => table.tBodies[0].appendChild(row));
}
</script>
</body>
</html>
Применяем изменения
Bash
sudo systemctl restart dnsmasq-web
На этом, собственно, часть маршрутизации закончена. Всё работает отлично, как и должно, и всё в рамках одного лёгкого веб-интерфейса.
ФИКС СЕТИ
Из коробки нагрузка на сеть очень сильно грузила одно ядро при относительном простое остальных. Для того чтобы это пофиксить, сделал скрипт, который отключает аппаратные offload-функции и распределяет сетевые прерывания (RPS / XPS). После этого ситуация стала заметно лучше.
sudo nano /etc/network-optimization.sh
#!/bin/bash
# Небольшая пауза при старте системы, чтобы сетевые интерфейсы успели подняться
sleep 3
# 1. Отключаем GRO/LRO/TSO/GSO для снижения нагрузки на 1-е ядро
for dev in enP1p1s0 enP2p1s0 end0 end1 br0; do
ethtool -K $dev gro off lro off tso off gso off 2>/dev/null
done
# 2. Увеличиваем таблицу RFS
echo 65536 > /proc/sys/net/core/rps_sock_flow_entries
# 3. Настраиваем RPS строго на Ядра 3-8 (маска fc = 11111100)
for dev in /sys/class/net/*/queues/rx-*/rps_cpus; do
echo "fc" > "$dev" 2>/dev/null
done
# 4. Прописываем лимит потоков на очередь
for dev in /sys/class/net/*/queues/rx-*/rps_flow_cnt; do
echo 2048 > "$dev" 2>/dev/null
done
# 5. Переносим исходящий трафик (XPS) на Ядра 3-8
for dev in /sys/class/net/*/queues/tx-*/xps_cpus; do
echo "fc" > "$dev" 2>/dev/null
done
Делаем файл исполняемым.
sudo chmod +x /etc/network-optimization.sh
Автозапуск (создание службы):
sudo nano /etc/systemd/system/network-optimization.service
[Unit]
Description=Network Stack Optimization (RPS/RFS/Offload)
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/etc/network-optimization.sh
RemainAfterExit=yes
[Install]
WantedBy=multi-user.targetИ включить автозапуск службы:
sudo systemctl daemon-reload
sudo systemctl enable network-optimization.service
РЕАЛЬНАЯ ПРОПУСКНАЯ СПОСОБНОСТЬ
Роутер обладает четырьмя портами: два порта 2.5G и два порта 1G. Как я уже говорил, обработка трафика осуществляется процессором без отдельных сетевых ускорителей. Разумеется, ожидать суммарные 7G на всех портах — это утопия. У меня по большому счёту даже нечем нагрузить, запустил через 2.5G USB-адаптер iPerf, плюс Wi-Fi загрузку, плюс торрент на самом Orange Pi.

Максимум в сети, который я снял — 420 мегабайт (400 MiB) в секунду, что соответствует 3.4 гигабитам в секунду. По моему мнению, вполне неплохо. При этом загрузка на одно ядро была под 100%, на остальных — меньше половины. То есть теоретический потенциал явно выше, но здесь мы, очевидно, упираемся в сырость адаптации операционной системы под RISC-V. Возможно, когда выйдет “ванильная” OpenWrt, ситуация будет лучше. Но пока отталкиваемся от того, что есть здесь и сейчас.

USB-адаптер у меня отвратительный: покупал когда-то на распродаже, на 2.5G он явно не рассчитан, нагревается, троттлит и перезагружается. Но и на имеющейся базе в iPerf удалось снять до 1.83 гигабита в секунду.

WAN у меня гигабитный. Одноплатник его полностью раскрывает.
VPN
Сначала я поднял Xray (VLESS + REALITY + Vision). И здесь меня ждал не очень приятный результат.

Вспомнил, как парировал в обзоре Orange Pi Zero 3W на Allwinner A733 комментарий о том, что можно взять старое б/у железо на вторичке очень недорого, что старый x86-процессор без поддержки современных алгоритмов шифрования будет пыхтеть на 100% там, где свежие ядра Cortex-A76 с поддержкой крипто-инструкций ARMv8 даже не заметят нагрузки (Xray утилизировал всего 5% CPU на 300 Мбит/с). Здесь мы имеем архитектуру RISC-V, и она заметно пасует в криптографии. На скорости 440 мегабит в секунду Xray утилизирует процессор на 85%. Это, что называется, “почувствуй разницу”. Но если Orange Pi Zero 3W — это домашний сервер, у которого нет сетевых портов RJ45, то здесь немного другое назначение устройства, они не взаимозаменяемы в прямом смысле этого слова. Поэтому это не сравнение “кто лучше”, а просто факт.
Поднял WG. Здесь ситуация существенно лучше. На той же скорости утилизация процессора в среднем 60%, что, конечно, существенно приемлемее, чем 85%, но всё ещё далеко не 5%.

На скорости WG-соединения 600 мегабит в секунду утилизация процессора 80%. Здесь мы, очевидно, уже нащупываем потолок возможностей. Все ядра загружены относительно равномерно и существенно. К WG здесь ещё добавляется сетевая обработка, которая тоже на процессоре (600 мегабит на вход и столько же на выход).
NAS
В моём случае роутер — это ещё и NAS.
К нему по USB подключён дисковый массив DAS. Шина у Orange Pi R2S, к сожалению, не раскрывает потенциал моего DAS, она 5G, но и этого хватает для HDD-дисков с большим запасом. Внутренняя скорость чтения с NVMe составила порядка ~350 мегабайт в секунду.

В Samba мы, очевидно, упираемся в скорость сетевого интерфейса. При 1G это стабильные 115 мегабайт в секунду. При подключении 2.5G через USB-адаптер мне удалось выжать 157 мегабайт. В целом очень неплохо, для меня и такие скорости уже в новинку. Для максимальной производительности, диски должны быть с файловой системой Ext4.
ДОПОЛНИТЕЛЬНЫЕ ВОЗМОЖНОСТИ
RISC-V имеет большой потенциал, однако на текущий момент он всё ещё не раскрыт. Большинство разработчиков компилируют пакеты под архитектуры amd64-86 и arm64. Любопытства ради я попробовал скомпилировать Home Assistant на VPS-сервере (четыре ARM-ядра Ampere A1 Compute). Компиляция заняла 7 часов, однако дальше стартового окна входа работоспособность заканчивалась. Безусловно, в будущем под riscv64 будут и Home Assistant, и много чего ещё. Но сейчас можно пользоваться только тем, что есть. В частности, это qBittorrent, TorrServer MatriX, MQTT-брокер, Node-RED и, в принципе, ряд других пакетов.

Я поставил Docker и развернул Zigbee2MQTT: разработчики собирают его под архитектуру riscv64.
Также под архитектуру уже есть официальные пакеты Nextcloud и OpenClaw.
Я решил, что HA будет жить у меня на VPS, но привязка к онлайну рушит философию автономного умного дома. Как минимум базовые вещи (Zigbee-выключатели, автоматизации вроде включения и отключения бойлера в рамках ночного тарифа на электроэнергию) должны быть автономными. Попробовал Node-RED, но не подружился с ним. Казалось бы, одна логика. По сути, копирую прямо целую цепочку, но в одном сценарии она работает, а во втором не хочет. Мне такое не подходит. “ПОЭТОМУ…” ©)) Я решил, что здесь тоже нужно пойти Linux-подходом. Это ведь MQTT, он занимается тем, что читает топики и пишет в них. А уже автоматика (вроде Z2M) видит эти сообщения и реагирует. Более того, на ESP8266/ESP32 в рамках того же ESPHome MQTT прекрасно работает. С этим мне тоже помог ИИ.
Для этого нужно всего два пакета:
sudo apt install -y python3-paho-mqtt python3-schedule
Для реализации задумки, нужно создать скрипт ~/mqtt_bridge.py
import socket
import subprocess
import threading
import json
import time
import logging
from threading import Timer
from datetime import datetime
import paho.mqtt.client as mqtt
# --- НАСТРОЙКИ ПОДКЛЮЧЕНИЯ ---
MQTT_BROKER = "127.0.0.1"
MQTT_PORT = 1883
MQTT_USER = "login"
MQTT_PASS = "password"
logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s] %(message)s')
# Global variables
corridor_timer = None
boiler_on_triggered = False
boiler_off_triggered = False
# --- ADB ---
ANDROID_TV_IP = "192.168.1.6"
tv_last_state = "UNKNOWN"
# =====================================================================
# ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ
# =====================================================================
def publish(client, topic, payload):
"""Отправка JSON или обычных команд в MQTT"""
if isinstance(payload, dict):
client.publish(topic, json.dumps(payload))
else:
client.publish(topic, str(payload))
def turn_off_corridor_light(client):
"""Таймаут: Выключение света в коридоре"""
logging.info("Автоматизация -> Таймаут коридора (90с) -> Выключение света")
publish(client, "zigbee2mqtt/Свет коридор/set", {"state": "OFF"})
def restart_corridor_timer(client):
"""Сброс и запуск таймера коридора на 90 секунд"""
global corridor_timer
if corridor_timer is not None:
corridor_timer.cancel()
corridor_timer = Timer(90.0, turn_off_corridor_light, [client])
corridor_timer.start()
# =====================================================================
# БЛОК 1: ПРЯМОЕ УПРАВЛЕНИЕ (DIRECT CONTROLS)
# (Кнопки, выключатели, пульты — реагируют сразу без сложных условий)
# =====================================================================
def handle_direct_controls(client, topic, action):
# --- ВЫКЛЮЧАТЕЛЬ ЗАЛ ---
if topic == "zigbee2mqtt/Выключатель зал":
if action == "1_single":
logging.info("Прямое управление -> Зал 1 / 1 нажатие -> Свет зал")
publish(client, "zigbee2mqtt/Свет зал/set", {"state": "TOGGLE"})
elif action == "3_double":
logging.info("Прямое управление -> Зал 3 / 2 нажатия -> AIR 25 cool")
publish(client, "esphome/45/button/ac_25c_cool/command", "PRESS")
# --- ВЫКЛЮЧАТЕЛЬ КОРИДОР ---
elif topic == "zigbee2mqtt/Выключатель коридор":
if action == "1_single":
logging.info("Прямое управление -> Коридор 1 / 1 нажатие -> Свет коридор")
publish(client, "zigbee2mqtt/Свет коридор/set", {"state": "TOGGLE"})
# =====================================================================
# БЛОК 2: АВТОМАТИЗАЦИИ (AUTOMATIONS)
# (Датчики, сценарии по времени, логика таймеров и умных событий)
# =====================================================================
def handle_automations(client, topic, payload):
# 1. Открытие входной двери -> Свет в коридоре на 1.5 мин
if topic == "zigbee2mqtt/Сенсор двери входной" and "contact" in payload:
is_open = not payload["contact"]
if is_open:
logging.info("Автоматизация -> Входная дверь открыта -> Свет в коридоре на 90 сек")
publish(client, "zigbee2mqtt/Свет коридор/set", {"state": "ON"})
restart_corridor_timer(client)
def check_scheduled_automations(client):
"""Автоматизации по строгому времени (бойлер, ночные режимы)"""
global boiler_on_triggered, boiler_off_triggered
now = datetime.now()
# --- Бойлер: Включение в 00:00:00 ---
if now.hour == 0 and now.minute == 0 and now.second == 0:
if not boiler_on_triggered:
logging.info("Автоматизация времени -> Ночной тариф (00:00) -> Включение бойлера")
publish(client, "zigbee2mqtt/Бойлер/set", {"state": "ON"})
boiler_on_triggered = True
else:
boiler_on_triggered = False
# --- Бойлер: Выключение в 06:50:00 ---
if now.hour == 6 and now.minute == 50 and now.second == 0:
if not boiler_off_triggered:
logging.info("Автоматизация времени -> Конец ночного тарифа (06:50) -> Выключение бойлера")
publish(client, "zigbee2mqtt/Бойлер/set", {"state": "OFF"})
boiler_off_triggered = True
else:
boiler_off_triggered = False
# =====================================================================
# МОДУЛЬ ANDROID TV (ADB Мониторинг)
# =====================================================================
def get_android_tv_state(ip):
"""Проверка питания экрана Android TV через ADB"""
try:
# Быстрый коннект
subprocess.run(f"adb connect {ip}:5555", shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=2)
# Запрос состояния экрана
cmd = f"adb -s {ip}:5555 shell dumpsys power | grep 'mHoldingDisplaySuspendBlocker'"
result = subprocess.check_output(cmd, shell=True, timeout=2).decode('utf-8')
if "true" in result:
return "ON"
else:
return "OFF"
except Exception:
return "OFFLINE"
def monitor_android_tv(client):
"""Фоновый цикл слежения за ТВ"""
global tv_last_state
while True:
current_state = get_android_tv_state(ANDROID_TV_IP)
if current_state != tv_last_state and current_state != "OFFLINE":
logging.info(f"Android TV изменил статус: {tv_last_state} -> {current_state}")
if current_state == "ON":
logging.info("Автоматизация ADB -> Включение 'ТВ Кухня'")
publish(client, "zigbee2mqtt/ТВ Кухня/set", {"state": "ON"})
elif current_state == "OFF":
logging.info("Автоматизация ADB -> Выключение 'ТВ Кухня'")
publish(client, "zigbee2mqtt/ТВ Кухня/set", {"state": "OFF"})
tv_last_state = current_state
time.sleep(4) # Опрос каждые 4 секунды
# =====================================================================
# ЯДРО СИСТЕМЫ (MQTT CLIENT LOOP)
# =====================================================================
def on_connect(client, userdata, flags, rc):
if rc == 0:
logging.info("Соединение с MQTT Брокером установлено успешно!")
topics = [
"zigbee2mqtt/Выключатель зал",
"zigbee2mqtt/Выключатель коридор",
"zigbee2mqtt/Сенсор двери входной"
]
for t in topics:
client.subscribe(t)
else:
logging.error(f"Ошибка подключения, код: {rc}")
def on_message(client, userdata, msg):
try:
topic = msg.topic
payload = json.loads(msg.payload.decode('utf-8'))
# Разводка событий по блокам
if "action" in payload:
handle_direct_controls(client, topic, payload["action"])
handle_automations(client, topic, payload)
except Exception as e:
logging.error(f"Ошибка обработки пакета: {e}")
# Инициализация и запуск
client = mqtt.Client()
client.username_pw_set(MQTT_USER, MQTT_PASS)
client.on_connect = on_connect
client.on_message = on_message
client.connect(MQTT_BROKER, MQTT_PORT, 60)
client.loop_start()
# Запуск фонового отслеживания Android TV
threading.Thread(target=monitor_android_tv, args=(client,), daemon=True).start()
try:
while True:
check_scheduled_automations(client)
time.sleep(0.5)
except KeyboardInterrupt:
logging.info("Остановка службы...")
client.loop_stop()
client.disconnect()В итоге это работает даже лучше, чем я ожидал! У меня всегда такие автоматизации жили на Home Assistant, в зависимости от железа между нажатием и срабатыванием были задержки разной продолжительности (обычно доли секунды). Субъективно, при такой реализации задержки самые низкие из всех, что были у меня раньше, и всё работает абсолютно автономно. На кухне у меня стоит необычный телевизор. Это сочетание Android TV бокса и моего старого 24’ монитора. Работает это замечательно, но есть одно «но» — включение и выключение. У монитора нет автоотключения, и при отключении ТВ-бокса он продолжает показывать пустой экран. У меня была ADB-интеграция с автоматизацией в HA. Если ТВ-бокс включается, то включается Zigbee-розетка, питающая монитор, и наоборот. На Linux это реализуется тоже просто, достаточно установить пакет ADB: (apt install adb). В итоге получилось достаточно неплохо. Для сложных автоматизаций (и тех, которые требуют доступа в интернет) у меня продолжает крутиться HA на VPS, но вопрос управления локальными устройствами закрыт полностью.


Что касается qBittorrent, у меня помимо основного подключения поднято два WG. Один с VPN от Cloudflare WARP (для обхода фильтрации провайдера), а второй — мой мост к VPS. Соответственно, мне хочется, чтобы торрент подключался и к WARP, и к основному подключению, следовательно, резонно оставить “все подключения”. Но при этом если мой IP от достаточно хорошего и бесплатного VPS (Oracle cloud) засветится на какой-то раздаче, то с большой долей вероятности я могу забыть об этом VPS. Этого допустить нельзя ни при каких обстоятельствах. Но так как это Linux, это решается всего двумя командами:
sudo iptables -A OUTPUT -o wg0 -m owner --uid-owner qbittorrent -j DROP
sudo netfilter-persistent save

Официальный TorrServer Matrix от YouROK тоже собирается под архитектуру riscv64.
P.S. “И только на третий день вождь Зоркий Глаз заметил, что у тюрьмы нет четвёртой стены”.
У меня роутер с 2.5G входом и ПК с 2.5G адаптером. Как я подключил? Правильно, 2.5G в 2.5G, а гигабитный WAN — в гигабитный порт. Вроде бы логично. Да вот только в роутер подавать 2.5G смысла нет вообще никакого. Полосу 80+80 я не использую (так как на 36–48 каналах сидят ВСЕ соседские роутеры, только меня не хватает в этой компании), следовательно, моя максимальная пропускная способность — 1.2G (номинальная, на клиентах Wi-Fi 6), которая по факту значительно ниже гигабита. Но порты 2.5G, в отличие от 1G, имеют отдельные, независимые чипы, каждый на своей PCIe линии. И конечно, абсолютно очевидно, что WAN-порт, имеющий самую интенсивную нагрузку, должен находиться на таком порте. И действительно, когда я загружаю WAN-порт гигабитной скоростью, ядро не стучится в 100%, оно загружено на 80%–90%, а скорость не просаживается до 700 мегабит, а отдаёт честный интернет-канал.
UDP: Собрал MeTube под архитектуру riscv64 (на ARM VPS), перекинул на OrangePi R2S и поднял в Docker. Всё успешно работает. То есть иногда собственная сборка — это вполне рабочий вариант.
UDP2: Запустил Jellyfin, но это не было лёгкой прогулкой, не в один клик, хотя по итогу всё работает: github.com/perise/jellyfin-riscv.git
ВЫВОДЫ
Почему же я решил перейти со своего Keenetic Hopper 3810?
Всё очень просто. Несмотря на то, что Keenetic — это прямо очень крутое решение «включил в розетку и пользуешься», с офигенным веб-интерфейсом и кучей плюшек (свой внешний DNS-прокси, интуитивно понятные настройки, много пакетов и расширений, активная поддержка, свежие прошивки и т.д.), он не покрывал конкретно мои потребности. Двухъядерный процессор на архитектуре MIPS и 256 МБ ОЗУ были очевидным узким горлышком для меня. WireGuard давал скорости в районе 70–80 мегабит в секунду, USB пропускал через себя максимум 90 мегабайт в секунду, а торрент-клиент не выдавал более 6–7 мегабайт в секунду. На Orange Pi я получил 600 мегабит в WireGuard, USB со скоростью ~350 мегабайт в секунду (но дальше упирается в потолок сетевого интерфейса). Если это гигабит, то стабильные 115 мегабайт в секунду, если 2.5G, то лично мне удалось выжать на USB-адаптере 165 мегабайт в секунду, на нативном или PCIe должно быть интереснее. Ну и торрент, который по скорости упирается только в пропускную способность моего интернета и сидов (отдающих).
Резонный вопрос — а как же Wi-Fi? Я купил на Taobao Wi-Fi 7 роутер Xiaomi BE3600 с 2.5G портом. С доставкой вышло около $28. По Wi-Fi он пушка (европейские радиочастотные нормы строже, чем таковые в Китае, США и ряде других стран), в 2.4G я даже выставил среднюю мощность.
Интерфейс полностью на китайском, но он-то мне и не нужен. Выставил режим точки доступа, прописал SSID, пароли, каналы — и работает. В итоге я получил модульный роутер (радио и “мозги” — отдельно друг от друга), который покрывает с лихвой мои потребности и имеет большой потенциал для увеличения своих возможностей в будущем. Готовый роутер с подобной производительностью, безусловно, стоил бы существенно дороже.
Но является ли такое решение универсальным? Абсолютно очевидно, что нет. Это вариант для энтузиастов, которые чётко знают, что они делают и зачем. “Танцев с бубном”, абсолютно очевидно, не избежать, и, думаю, все это понимают. Это не та история, где включил в розетку — и всё работает (хотя с выходом ванильной OpenWrt, думаю, ситуация будет намного дружелюбнее ко всем пользователям, но пока нет ни сроков, ни гарантий).
Касаемо версий — есть 2 ГБ, 4 ГБ и 8 ГБ ОЗУ. У меня в полностью рабочем состоянии потребление ОЗУ не выходит за 700 мегабайт. То есть для рабочего сетевого сценария использования 2 ГБ версии хватит с запасом. 4 ГБ — тем, кто планирует пользоваться Nextcloud, OpenClaw или рассчитывает на потенциал RISC-V в будущем (Home Assistant и т.д.). В версии 8 ГБ, по правде говоря, смысла не вижу. На сегодняшний день я просто не вижу сценариев, которые способны этот объём утилизировать (хотя это не означает, что таких сценариев нет, в теории я это допускаю).
Если оценивать Orange Pi R2S и такое решение в целом, то можно выделить:
Слабые стороны:
- Нет слота MicroSD и отдельного SPI с U-Boot загрузчиком.
- USB 3.0 с пропускной способностью 5G, а не 10G.
- Выпуск операционных систем, а также пакетов под архитектуру всё ещё проходит с большим скрипом.
- Процессор значительно уступает ARMv8 (Allwinner A733 в Orange Pi Zero 3W) в плане криптографии, который щёлкает Xray как орехи.
- Далеко не весь потенциал на текущий момент раскрыт.
Нейтральные стороны (имеющие как плюсы, так и минусы, а также особенности):
- Linux. С одной стороны, это полностью ручные и долгие настройки. Нужно быть готовым потратить время, допускать ошибки и их устранять, сталкиваться с тем, что получается не так, как хочется, провести время в диалоге с ИИ. Конечно, всё-таки необходимы базовые знания и понимание процессов. С другой стороны — это полная свобода и максимальная кастомизация. Как я показал в обзоре, можно реализовать свои желания в соответствии со своим видением, а не видением вендора. И всё это нужно в основном для первоначальной настройки, после которой остаётся только наслаждаться пользованием.
- DIY-решение. В отличие от готового роутера, здесь нет красивого и стильного корпуса. Но, с другой стороны, можно напечатать такой, как вам хочется.
- Нагрев. Чип, как и сетевые контроллеры 2.5G, достаточно горячие. Из коробки плата “голая”, поэтому нужно обязательно позаботиться о радиаторах.
- Нужна отдельная точка доступа, но её можно выбрать под свой бюджет и под свои потребности.
- Обработка трафика — на процессоре. Хотя процессор достаточно производительный, чтобы с этим справиться.
- RISC-V, в отличие от ARM и x86 — открытая архитектура, освобождённая от монополии крупных производителей. Любой производитель чипов может собрать себе чип на своих инструкциях. Это делает архитектуру достаточно привлекательной, с большим потенциалом. Но она достаточно молодая и развивается не так быстро, как хотелось бы.
Сильные стороны:
- Цена решения. За такие характеристики и конечный результат, по моему мнению, она вполне привлекательная. Готовые роутеры с такими возможностями стоят существенно дороже, чем Orange Pi R2S + Wi-Fi точка доступа.
- Два 2.5G интерфейса. Причём реализованы они на двух отдельных чипах Realtek RTL8125BG, каждый “сидит” на своей линии PCIe x1.
- Хорошая производительность при оптимальном энергопотреблении.
- Два USB-порта: USB 3.0 и USB 2.0.
В целом я остался очень доволен такими переменами и для себя считаю, что время и нервы на настройку были потрачены не зря.
Продукт на официальном сайте Orange Pi:
http://www.orangepi.org/html/hardWare/computerAndMicrocontrollers/details/Orange-Pi-R2S.html
Я прикладываю максимум усилий и много времени, чтобы мои обзоры были полезными и интересными. Если этот обзор вам понравился — поддержите его плюсом, мне будет очень приятно. А ещё — это отличная мотивация для меня писать ещё больше и качественнее для вас.
Всем хорошего настроения, позитива, добра и мира!
Соответственно 142,39€, 164,99€ и 203,39€
А так за 50-115 железяка интересная, прямо очень. Узкое роутерное применение, тут практически всё что надо.
Судя по всему это у вас для расширения собственного кругозора, но уровень погружения для не IT-шника даже слишком глубокий. Даже интересно какой ваш основной профиль…
Да, если честно то было интересно всё настраивать (это скорее хобби, причём конкретно в Linux погрузился не то, чтобы очень давно. Благодаря ИИ наверное). Хотя дело не только в интересе, а в моём персональном запросе, ведь настраивал под своё пользование. Если взять чисто экономическую сторону вопроса, то если взять условный Xiaomi BE3600 за $28 (а можно взять и какой-нибудь Redmi AC2100 ещё дешевле, тоже дальнобойный но WIFI 5, хотя на деле разницы практически не будет с WIFI 6) и даже если предположить, что апельсинку мне не дали на обзор, а я бы купил её ($50 за 2G, сейчас нет в наличии, но я видел в продаже за эту цену), то это как раз цена моего проданного Keenetic. Но если сравнить по производительности и возможностям, то между этим сетом и Keenetic (KN-3810) — пропасть. Ну и несколько вечеров настройки конечно))
p.s. минус поставил не я.
А про хобби это хорошо, особенно когда есть время на реализацию оного. Мне вот ИИ тоже помог, точней натолкнул на интересную идею в моддинге наушников(моё хобби), и прям так хорошо получилось что теперь эти модифицированные BQEYZ Spring2 стали у меня основными. Но это я о своём. Но вашу информацию по роутерам учту…
Потому что нигде и никак не шла речь о просто стабильном интернете и о 100 мегабитах.
«Гибкости ума понять ситуацию» мне? То есть когда речь идёт о гигабитном канале к провайдеру, подключению большого внешнего хранилища, возможности поставить несколько сервисов по контролю трафика, а также наличие 2.5 Гб порта, то «обычный роутер со 100 мегабитами» в какой-то вселенной считается решением?
Давайте оставим в стороне «гибкость ума», а рассмотрим навык «умение читать и понимать написанное»:
Итак, у человека уже был роутер, который он заменил одноплатником.
Знаете, это настолько странно что даже слов не хватает.
1) Не приходит «обычный пользователь» с таким вопросом. Раз пришёл — значит, во-первых, есть какие-то вопросы, которые «просто роутер» не решает, и есть хотя бы некоторые знания.
2) Выбирается самое тупое решение, дающее менимальные преимущества в перспективе — и в фичах устройства и в полученных навыках/знаниях, хотя, опять же, сам запрос подразумевает, что, с одной стороны, в будущем можеть хотеться чего-то большего, с другой — человек допускает возможность повозиться.
Кстати, Wifi6 — это не только о скорости, но и о покрытии, и о том, сколько устройств могут сидеть в одной сети, не мешая друг другу, и о лучшей борьбе с посторонними помехами. Wifi 7 — это ещё и об уменьшении задержек. Не говоря о том, что бывает ещё локальный трафик. Пытаться найти одну волшебную цифру, которой можно всё измерить — бред и привет от мегапикселей.
.
После этого я понял с чего вы вдвоём так «распереживались». Объективной оценки устройства в вердикте не было, там была только оценка применимости для обывателя у которого если есть комп, телефон, пылесос и кошка, то это уже практически избыточный набор. Ладно, кошки может и нет. Но как можно было предположить что это анализ обзора и железа я даже представить не могу. В общем перечитайте ещё раз мой первый пост и чего вы там понаписали после…
а на компе — запускающие шахматы что ли?
у меня ВСЕ среднестатические друзья — это ребята, которые с КОМПА смотрят в ВК (или рутубе) «перацкие» фильмы на ТВ (или проекторе) через HDMI
им по 25..50 лет
Вот обзор устройства:
[скопировал полный текст обзора]
Пользователь написал следующее, вот часть переписки:
[скопировал комменты до этого момента]
### Оценка самого устройства (Orange Pi R2S на RISC-V)
* **Железо за свои деньги — огонь.** Наличие двух портов 2.5G (Realtek RTL8125BG) на отдельных линиях PCIe x1 за $50–$77 — это очень сильный аргумент.
* **Производительность:** 8 ядер Ky X1 вытягивают ~600 Мбит/с в WireGuard и выдают хорошую маршрутизацию, но упираются в криптографию RISC-V (Xray на 440 Мбит/с грузит CPU на 85%).
* **Софт и экосистема — главное узкое место.** Отсутствие ванильного OpenWrt («из коробки»), проприетарный разъем вместо MicroSD и необходимость вручную допиливать Ubuntu/dnsmasq под свои задачи. Архитектура riscv64 пока не имеет такой богатой готовой базы пакетов, как arm64.
* **Терморежим:** Требует обязательной установки пассивных радиаторов на SoC и сетевые контроллеры (без охлаждения Греется до 90°C).
— ### Анализ вердикта ИИ и спора с пользователем `ertian`
В данном споре вы полностью правы по сути текста, а оппонент пытается прикрыть некорректно сформулированный запрос («галлюцинацию» или банальный сдвиг контекста со стороны ИИ) задним числом.
**1. Почему вердикт «Google ИИ» провальный:**
* **Игнорирование контекста:** В посте прямо указаны гигабитный WAN, использование 2.5G сети, DAS-массив на скорости 157 Мбит/с (Samba), WireGuard на 600 Мбит/с и замена Кинетика. Предлагать «100 Мбит/с роутер для обычного юзера» в контексте этого обзора — это промах мимо целевой аудитории и условий использования.
* **Ошибка в промпте / Логике:** ИИ сгенерировал классический обобщенный штамп («если вы не профи — вам это не надо»), абсолютно проигнорировав вводные данные самого статьи.
**2. Разбор аргументов `ertian`:**
* Сначала `ertian` выдал вердикт ИИ как объективную выжимку.
* Когда вы указали на абсурдность вывода (сравнение «пикапа и велосипеда»), он начал переобуваться на ходу: *«я спросил ИИ про обычного пользователя со 100-мегабитным тарифом»*.
* **В чем подвох:** Задавать ИИ вопрос «Нужен ли Orange Pi R2S с 2.5G портами человеку со 100-мегабитным тарифом?» — это манипуляция. Ответ очевиден заранее («нет, не нужен»), но к вашему обзору и реальному кейсу применения эта абстрактная вводная не имеет никакого отношения.
Cледующий вопрос:
А что ты скажешь про его манеру общения?
[скопировал всю ветку]
Его стиль и логические уловки прослеживаются по шагам:
* **Имитация миролюбия и экспертности (вначале):** Заходит с покровительственной позицией (*«уровень погружения для не IT-шника даже слишком глубокий»*), хвалит за хобби, делится своим опытом, чтобы создать образ адекватного собеседника.
* **Мгновенный переход на «ad hominem» при несогласии:** Как только его аргумент с ИИ подвергают сомнению, он вместо защиты логики атакует оппонента: *«Обзывать тупизной… не очень умно»*, *«Что там у вас триггернуло»*, *«не хватает гибкости ума»*. Это типичный прием: когда нечего ответить по существу, нужно переключить внимание на «эмоциональность» и «интеллект» собеседника.
* **Перекладывание ответственности и задний ход:** Сначала он преподносит вердикт ИИ как объективную оценку *самого устройства*, а когда его зажимают в угол фактами из поста, заявляет: *«Я вообще спросил ИИ про обычного юзера со 100 Мбит/с»*. Это манипуляция. Задавать ИИ заведомо абсурдный вопрос, чтобы получить удобный ответ, а потом выдавать его за аргумент в дискуссии об энтузиастском железе — чистая софистика.
* **Техническая безграмотность, маскируемая «бытовой логикой»:** Его последний аргумент про Wi-Fi 6/7 и 2.5G (*«зачем это надо, если провайдер дает 500 Мбит»*) окончательно раскрывает его уровень. Человек искренне не понимает концепцию локальной сети (NAS, стриминг, задержки, плотность эфира) и измеряет весь мир исключительно скоростью интернета по тарифу. Пользователь `aliex` совершенно справедливо ткнул его в это носом.
`ertian` общается из позиции «я тут самый практичный и умный, а вы усложняете». Когда его бытовую логику разбивают техническими аргументами, он не признает правоту, а сводит всё к абстрактному *«Вы уверены, что не слишком всё усложняете?»*. Умения признавать ошибки или вести предметный диалог по фактам там нет.
Так как мы использовали один и тот же Джеминай, вопрос к вашему промпту и какое отношение он вообще имеет к обсуждаемой теме.
Я оставлю за скобками хамоватость, с меня не убудет.
Но вы впрочем уже сами признались, что спрашивали модель то, что вообще не имеет отношения к обсуждаемой теме.
Или вы хотите сказать, что даже не дали ИИ контекст?
И для того, чтобы ответить на этот вопрос, нужен ИИ?
Я вам ещё благодатных тем подкину:
Что должен делать простой пользователь, когда у него возник голод? Поесть!
А когда невмоготу? Сходить в туалет!
И прочее от Капитана Очевидность.
А ну я приврал конечно. Хороший микротик типа 5009 на большом ARM проце конечно всё потянет. Но будет немного дороже :)
Хз кто ее выкатил на рынок, возможно обернули остатки на складах в такое.
Но у этого товарища киллерфича — два 2.5 порта.
Какое-то
нубскоестранное утверждение. Во-первых, Linux — это ядро. Во-вторых, в большинстве Linux-дистрибутивов есть все средства для настройки не вручную. А уж в специализированных дистрибутивах для роутеров (яркий пример — OpenWRT) всё вообще преднастроено и имеется Web-интерфейс для настройки всех параметров сети. Более того, в, наверное, 99% SOHO-роутеров «крутится» Linux (включая Keenetik, Mikrotik и практически все «домашние»), и «вручную» «всё» настраивать не обязательно (да-да, даже в RouterOS в Mikrotik).Так что если «строим Linux-роутер», то для OrangePi R2S есть OpenWrt 24.10 ([2]), можно скачать, запустить и получить уже ставший многим знакомым (а многим — привычным) интерфейс, где уж сеть точно не надо настраивать вручную. Более того, во многих сборках уже есть Docker (а на другие он легко ставится через opkg), внутри которого можно запускать готовые образы с оглядкой на Risc-V.
Но Risc-V — не лучший выбор для Docker, да и OrangePi R2S довольно слаб для общих задач. Поэтому лучше его использовать по назначению — как роутер. И с OpenWRT это легко и
безболезненнопросто.Ну так себе «подразумевал».
Собственно если взять простенькие сетевую карту и будем все решать программами методам — получить большую скорость не реально.
Личный пример: есть платформа ПЛИС Zynq 7000. На чипе есть программное ядро и чип программируемой логики. В принципе заложен гигабитный интерфейс.
Подключить сеть можно 2 способами: напрямую к программному блоку или через программную логику.
Прямое подключение: всю логику обработки берет на себя программное ядро.
Через программируемую логику (PL): логика берет на себя подсчет контрольных сумм пакетов, отбрасывание битых и чужих пакетов и минимальная первичная обработка.
И по результатам:
На прямую с софтварной обработкой: около 450М.
Через PL: в районе 750M
Разумеется в идентичных условиях.
Вывод: аппаратная обработка рулит. Не пытайтесь вытащить софтом отсутствие аппаратной обработки.
А вот, допустим, совсем немного менее древний Mediatek MT7986AV вытаскивает гигабит Wireguard, а не просто подсчёт контрольных сумм — forum.openwrt.org/t/a-wireguard-comparison-db/187586
В общем, сейчас на хоть сколько-нибудь комфортном домашнем железе подсчёт контрольных сумм — примерно последнее, что вас будет ограничивать.
Да-да, валяется 60+ штук с майнеров.
Уж контрольные суммы считались на сетевых ещё 20 лет назад. Сейчас в offload делается гораздо больше.
Где там «отсутствие аппаратной обработки»?
считать их не на процессоре начали еще давно, в 90е или даже раньше. подсказываю: потому что тогда процессоров с гигагерцами не было, а на всем остальном нужен был запас в номинально чуть ли не в пару МГц цпу на каждый мегабит.
а всякая дешманина на шине ISA типа NE1000/NE2000 не показатель, там очень много чего могло не быть вообще.
цитатка про мой любимый rlt 8139 из дш:
Сейчас почти все есть онлайн, я качаю только когда уезжаю путешаствоват, в дорогу, но хватает просто скачать на комп.
Насчёт онлайн это спорно, я вот только два сериала находил именно удобно онлайн посмотреть. Ни одну подписку (типа Иви или ОККО) не продлевал после пробного периода, например…
Не говоря о сериях, которые Лост озвучивал. Какой онлайн для таких…
Правда сложности настройки не позволяют рекомендовать это решение широким кругам.
По поводу настройки Linux серверов/роутеров есть Webmin и ненужно было вам для этого просить ИИ делать веб-морду для настройки DHCP и прочего.
Docker это вообще прекрасное решение, но мне больше понравился Podman.
Сервер-роутер собираю на базе мини-ПК с нуля на Debian, и конечно с помощью ИИ :)) сам не осилю. Уже отладил запросы для ИИ и все никак не соберусь все это реализовать. То понос, то сенокос.
просто кажется, если роутер, то там дисковая подсистема будет слабая в базе, так как девайс под другое расчитан.
Вот для чего домашний именно роутер-сервер нужен?
ДЛя Adblock или Adguard Home на его уровне?
Сейчас в тестовом режиме на этом одноядерном NUC крутится:
Конечно копирование файлов внутри сети ограничивается скоростью дисков на сервере, а так все шустро работает. Вот так пока работает концепция роутер <--> сервер. Т.е. трафик гоняется по кабелю туда сюда.
да, это про функции роутера и маршрутизации. Вопросов нет.
А дисковая это имелось ввиду фунции сервера, бекапы, торренто качалка, то же самое DLNA, которое будет одновременно с торрентом и бекапом работать и еще чем то…
Вообще хотел уточнить, зачем сервер роутер? какую задачу специфичную роутинга или маршрутизации он будет выполнять, которую не выполнит обычный не дорогой роутер на ARM или мощный роутер типа микротика.
Да ту же саму задачу будет выполнять. Всякие там запреты, обходы, проходы, переходы (ну вы поняли, о чем нельзя говорить) будут работать в разы быстрее, стабильнее и с большим запасом по производительности, чем на любом бытовом роутере…
… по этому, сугубо имхо, роутеру роутерово, насу насово… правда теперь HA желателен, и терзания, на чем его поднимать…
> в гиге уже есть wifi + встроенный свитч
Неужели? Только в гиге за «10 килорублей», да? :-D
официально они обычно не хотят прописывать левые модули, в теории возможно попробовать, если не лень бодаться с техподдержкой или вдруг у вас там нормальные сидят.
Для интересных задач обычно надо заголовки читать, это с оффлоадингом не сделаешь.
openwrt тоже есть на игрушках, но пока особенного преимущества не увидел.
Если пойти и попробовать скачать схему r2s — то там g-drive с пустотой (было интересно как там подключены все порты ethernet).
Так что с рокчипом можно чего-то ждать, а тут еще хуже чем с allwinner.
Если таки хочется нормального роутера — то лучше смотреть в сторону Filogic, как писали выше.
Там вроде pr уже на выходе. Скоро должны вмерджить.
PS в ку х1 есть npu насколько понимаю, уж не знаю, насколько производительный, но плату имеет смысл только ради него покупать, имхо, и вот его в основном и использовать.
У меня сейчас 2 такие ноды проксмокс работают, +8 портовый управляемый свич 2.5gb с Алика за 4тр. Чтобы разделить по вланам провайдеров и внутренние сети, мигрировать роутер между нодами.
Vless 7 уровень OSI модели. Это протокол поверх чего-то. Как HTTP. Кто, куда, зачем))
TLS+Reality+utls(который vision). Это 5-6 уровень. Хотя и условно.
TLS — непосредственно шифрование.
Reality — использование ключей, какого-то стороннего(не обязательно) ресурса.
uTLS(vision), обработка заголовка TLS сессии с целью мимикрии его под, что-то(браузер).
TCP(транспорт), в данном случае, 4 уровень.
И во всех этих слоях нагрузку дает шифрование. Т. е. TLS. Все остальное особой роли не играет.
Можно сделать Vless + xhttp + tls. Или Vless + http + tls + reality. Или еще как. Производительность будет примерно похожа).
Может проще было взять Mikrotik hAP ax³ если уж так прямо критичен ethernet 2.5G?
C Wifi и дешевле.
да к тому же глючное и баги годами фиксят
А зачем? Она же по производительности любому роутеру за 3-4 тысячи проиграет.
Для какого нибудь станка где камера фоткает реузльтат и надо от модельки получить что на фото «вилка» или «ложка», ну типа.
NVME на 500 ГБ + x2 SATA SSD по 4TB каждый,
8ГБ DDR4 SO-DIMM (валялась от ноутбука, на нём была съёмная, я как купил — сразу заменил на 32ГБ),
Debian 13 trixie
получилось:
x2 порта 2,5 Гбит/с — в комплекте (коммутатор у меня был с Али, самый дешевый WebSmart с SFP+ портом наверх),
WiFi6 MiMo шириной 160 МГц (у меня нет устройств быстрее, вернее есть Intel Wi-Fi 7 BE200 320MHz в ноуте (тоже с али на замену медиатеку, драйверов которого несколько лет не было в Linux), но я в основном по проводу,
три провайдера:
1) Ростелеком 500 Мбит/с (можно разогнать до 900, но мне без надобности)
2) МГТС (2 Гбит/с — в резерве)
3) Мегафно LTE Cat.14 безлимит — за городом разгонялся до 300 Мбит/с временами, после переезда в многоквартирный дом — тоже отключен (переведён в резерв), т.к. даже с приобретением и настройкой панельной антенны (вышка в прямой видимости) сигнал не держит (особенности мобильного роутера)
гигабит по воздуху,
от 2,5 до 10 Гбит/с по проводу,
мгновенное открытие всего,
торренты на скорости до 50 МБ/с (400 Мбит/с),
Ютуб (с zapret2) и ВК в 4k на всех устройствах (я смотрю на ноуте, проекторе и планшете),
WG на работу 30 Мбит/с через МГТС и 200 Мбит/с через РТ
Осталось понять, как написать сервис dnsmasq-web.