OlcRTC: туннель через WebRTC-сервисы: различия между версиями
Владимир (обсуждение | вклад) Новая страница: «= olcRTC: туннелирование SOCKS5-трафика через публичные WebRTC-сервисы = == Введение == === Что такое olcRTC === olcRTC — это инструмент для построения SOCKS5-туннеля поверх инфраструктуры публичных сервисов видеосвязи. В отличие от классических VPN-протоколов, которые работ...» |
Владимир (обсуждение | вклад) |
||
| Строка 71: | Строка 71: | ||
=== Поток данных === | === Поток данных === | ||
[[Файл:Olcrtc-data-flow.png|центр|мини|841x841пкс|Поток данных olcRTC: от клиентского приложения через SOCKS5, smux + ChaCha20-Poly1305, транспорт и WebRTC peer-connection в видеоконференции, до серверного outbound и целевого сайта]] | |||
[ | |||
=== Слои кода === | === Слои кода === | ||
Текущая версия от 07:56, 9 мая 2026
olcRTC: туннелирование SOCKS5-трафика через публичные WebRTC-сервисы
Введение
Что такое olcRTC
olcRTC — это инструмент для построения SOCKS5-туннеля поверх инфраструктуры публичных сервисов видеосвязи. В отличие от классических VPN-протоколов, которые работают через выделенные UDP/TCP-порты на собственном сервере, olcRTC использует уже существующие WebRTC-каналы общедоступных видеоконференц-сервисов в качестве несущей среды.
Поддерживаются три сервиса:
| Carrier | Сервис | Адрес |
|---|---|---|
wbstream
|
WB Stream | stream.wb.ru
|
telemost
|
Yandex Telemost | telemost.yandex.ru
|
jazz
|
SaluteJazz | salutejazz.ru
|
Сервер olcRTC выступает в роли участника виртуальной видеоконференции (с автоматически сгенерированным именем). Клиент подключается к той же конференции и через peer-connection обменивается с сервером данными — поверх этого канала идёт трафик SOCKS5-туннеля.
Когда применяется
- Канал между клиентом и обычными VPN-серверами нестабилен или имеет высокий процент потерь.
- Требуется передать данные через инфраструктуру, использующую WebRTC, а не выделенные транспортные порты.
- Нужна альтернатива, которая работает поверх стандартного для пользовательских устройств WebRTC-стека (браузер, мобильное приложение).
Сравнение с другими методами туннелирования
| Метод | Транспорт | Особенность |
|---|---|---|
| WireGuard | UDP | Прямое соединение с собственным сервером, минимальные накладные расходы |
| OpenVPN | UDP/TCP | Универсальная совместимость, выше накладные расходы |
| Shadowsocks | TCP | Шифрованный поток, маскировка под произвольный TCP |
| VLESS + REALITY | TCP (TLS) | TLS-handshake донора (стороннего сайта) |
| NaiveProxy | TCP (HTTP/2) | Использует Chrome-стек, неотличим от обычного HTTPS |
| Hysteria2 | UDP (QUIC) | QUIC поверх UDP с маскировкой под HTTPS |
| olcRTC | WebRTC поверх QUIC/UDP | Использует существующую инфраструктуру SFU публичного сервиса видеосвязи в качестве несущей |
Принципы работы
Поток данных

Слои кода
Кодовая база разделена на четыре независимых слоя с реестром расширений:
| Слой | Ответственность | Реализации |
|---|---|---|
| Carrier | Сессия в видеосервисе: вход в конференцию, регистрация участника, peer-connection через SFU | wbstream, telemost, jazz
|
| Link | Поверх транспорта; в текущей версии только direct (passthrough)
|
direct
|
| Transport | Способ кодирования байтов внутри WebRTC-канала | datachannel, vp8channel, seichannel, videochannel
|
| Application | Сервер (приём входящих туннелей) или клиент (локальный SOCKS5) | server, client
|
Транспорты
| Транспорт | Несущая в WebRTC | Идея | Скорость | Пинг | WB Stream | Telemost | Jazz |
|---|---|---|---|---|---|---|---|
datachannel
|
RTCDataChannel | Прямые байты в датаканале | Максимум | Минимум | ✓ | ✗ | ⚠ |
vp8channel
|
VP8-видеотрек | KCP-пакеты внутри валидных VP8-кадров | Высокая | Средний | ✓ | ✓ | ✓ |
seichannel
|
H.264 SEI NAL | Полезные данные в SEI-сообщениях видеопотока | Низкая | Низкий | ✓ | ✗ | ✓ |
videochannel
|
Видеокадры | QR-коды или тайлы Reed-Solomon в видеопотоке | Минимум | Максимум | ✓ | ✓ | ✓ |
Рекомендуемая универсальная связка: wbstream + vp8channel. Она используется в данной статье как основная конфигурация.
Шифрование
| Параметр | Значение |
|---|---|
| Алгоритм | XChaCha20-Poly1305 (AEAD) |
| Длина ключа | 32 байта (64 hex-символа) |
| Nonce | 24 байта, случайный, на каждый фрейм, префиксится к шифротексту |
| Идентификация клиента | Поле client_id в открытом JSON, сравнивается с серверным значением
|
Реальная криптографическая защита — это ключ. client_id — лишь дополнительная проверка от случайных подключений в той же конференции, не криптографическая.
Smux: мультиплексирование
Поверх единого WebRTC-канала работает xtaci/smux v2. Один физический канал содержит много логических TCP-стримов: каждый запрос SOCKS5 от приложения открывается как отдельный smux-стрим.
Архитектурное ограничение: один сервер — один клиент
Это важное свойство кода, которое необходимо понимать.
Один экземпляр сервера olcRTC обслуживает ровно одного клиента в момент времени. Это не упущение, а сознательное архитектурное решение.
Причины:
- Сервер хранит одну переменную
clientIDи сравнивает с присланным значением (см.internal/server/server.go:399-401). - Сервер держит один link и одну smux-сессию, не словарь по идентификатору.
- Провайдер carrier держит один RTCPeerConnection.
| Сценарий | Поведение |
|---|---|
| Один владелец, разные устройства, по очереди (выключил ноутбук, включил телефон) | Работает с одной ссылкой |
| Один владелец, разные устройства, одновременно | Устройства конкурируют за peer-connection, рвут друг друга |
| Несколько разных людей, одна ссылка на всех, одновременно | То же — рвут друг друга |
| Несколько пользователей, у каждого своя ссылка | Работает; требуется отдельный контейнер на каждого пользователя |
Для предоставления доступа нескольким людям одновременно необходимо запустить несколько независимых контейнеров — каждый со своими room_id, key и client_id. В разделе «Управление несколькими пользователями» описан скрипт, который автоматизирует это.
Что должно быть на сервере перед установкой
Минимально необходимая конфигурация
Перед началом установки olcRTC сервер должен находиться в следующем состоянии:
| № | Требование | Зачем |
|---|---|---|
| 1 | Установлена операционная система Linux (Ubuntu 22.04+, Debian 12+, Fedora 38+ или сравнимая) | Среда выполнения Docker |
| 2 | Доступ по SSH с правами root (либо аккаунт с sudo без пароля)
|
Установка пакетов и управление контейнерами |
| 3 | Установлены Docker Engine 24.0+ и Docker Compose v2.20+ | Запуск контейнера olcRTC |
| 4 | Установлена утилита git
|
Скачивание исходного кода olcRTC с репозитория |
| 5 | Установлена утилита openssl
|
Генерация ключа шифрования |
Опциональная (но настоятельно рекомендуемая) конфигурация: egress через WARP
По умолчанию olcRTC сервер выходит в интернет напрямую с публичного IP вашей виртуальной машины. Все целевые сайты будут видеть именно этот адрес.
Чтобы выходной трафик уходил через Cloudflare WARP, требуется промежуточная цепочка через локальный SOCKS5-прокси. Самая распространённая реализация — панель 3x-ui (web-интерфейс над xray-core).
Что должно быть подготовлено в 3x-ui
| № | Параметр | Значение для нашей статьи | Комментарий |
|---|---|---|---|
| 1 | Сама панель 3x-ui установлена и доступна | — | Установка описана в отдельной статье (Установка 3x-ui); если её ещё нет — выполните установку до начала |
| 2 | Outbound в WARP активен и протестирован | tag warp или аналогичный
|
Должен быть настроен как WireGuard-outbound к Cloudflare WARP. Проверка: маршрут с outbound отдаёт IPv6 из диапазона 2a09:bac5::/29 или IPv4 104.28.x.x
|
| 3 | Inbound типа mixed (SOCKS5 + HTTP), слушающий только на 127.0.0.1 | порт 24365
|
Этот порт мы будем указывать в конфигурации olcRTC. Выберите любой свободный, мы используем 24365 как пример |
| 4 | Аутентификация (логин/пароль) на этом mixed-inbound отключена | — | olcRTC-сервер умеет работать только с режимом NOAUTH; если включена авторизация, цепочка не будет работать |
| 5 | Routing-rule в xray: трафик с inbound mixed → outbound warp | — | В 3x-ui это настраивается в разделе «Настройки xray → Маршрутизация» |
Как проверить, что цепочка работает
Команда ниже выполняется на самом сервере (не на компьютере пользователя). Она запрашивает свой IP-адрес через локальный SOCKS5-прокси, который должен направить запрос в WARP.
Замените 24365 на ваш реальный номер порта mixed-inbound.
curl --socks5-hostname 127.0.0.1:24365 https://icanhazip.com
Ожидаемый результат: IP-адрес из диапазона Cloudflare WARP (например, 104.28.218.x или IPv6 2a09:bac5:...). Если возвращается публичный IP вашего сервера — значит цепочка не сработала и трафик идёт мимо WARP. В этом случае проверьте настройки routing в 3x-ui.
Если egress через WARP вам не нужен (готовы выходить с публичного IP сервера), можно пропустить этот раздел. В дальнейших шагах указания для случая «без WARP» помечены явно.
Параметры, которые нужно подготовить заранее
Перед началом установки заполните таблицу ниже своими значениями. На каждом шаге, где встретится плейсхолдер, мы будем ссылаться на эту таблицу.
| Плейсхолдер | Что это | Где взять | Пример |
|---|---|---|---|
YOUR_SERVER_HOST
|
Адрес сервера для подключения по SSH: либо публичный IP, либо имя из ~/.ssh/config, либо доменное имя
|
У хостинг-провайдера в панели управления виртуальной машиной | 198.51.100.42 или my-vps
|
YOUR_SSH_USER
|
Имя пользователя SSH | В письме от хостинга при создании VM. Чаще всего root
|
root
|
YOUR_KEY_HEX
|
32-байтный ключ шифрования olcRTC в hex-формате (64 символа) | Будет сгенерирован командой на шаге 4. Сохраните в надёжное место | 1c3f8a2b...d4e5f6a7 (64 hex-символа)
|
YOUR_CLIENT_ID
|
Идентификатор клиента; должен совпадать на сервере и в клиентском приложении | Любое имя на латинице длиной 1–32 символа: буквы, цифры, _, -
|
my-laptop
|
YOUR_ROOM_ID
|
Идентификатор виртуальной видеоконференции | Будет получен из логов сервера на шаге 7 | 019e07b8-e292-73ec-a40b-6a6e4957ce01
|
YOUR_SOCKS_PORT
|
Порт mixed-inbound в 3x-ui для egress через WARP (опционально) | См. раздел «Что должно быть на сервере перед установкой» | 24365
|
Сохраните эту таблицу в текстовом файле — заполните по мере прохождения шагов. Особенно важно сохранить YOUR_KEY_HEX и YOUR_ROOM_ID — без них нельзя восстановить доступ к серверу после перезапуска.
Установка сервера: пошаговая инструкция
В этом разделе все команды выполняются на сервере (через SSH). Каждое пояснение — одна команда. Если команда выдала ошибку — остановитесь, не выполняйте следующую, и сверьтесь с предыдущим шагом.
Шаг 1. Подключение к серверу по SSH
Откройте терминал на своём компьютере. На Windows можно использовать встроенный PowerShell или Windows Terminal, на macOS — Terminal, на Linux — любой эмулятор терминала.
Замените YOUR_SSH_USER на имя пользователя из подготовленной таблицы (обычно root), а YOUR_SERVER_HOST — на адрес или имя сервера.
ssh YOUR_SSH_USER@YOUR_SERVER_HOST
Если подключение прошло успешно — вы увидите приглашение командной строки сервера. Все следующие команды выполняются именно в нём.
Шаг 2. Проверка наличия Docker
Прежде чем что-то ставить, проверим, есть ли Docker уже на сервере.
docker --version
Если команда вывела что-то вроде Docker version 24.0.5, build ... — Docker установлен, переходите к шагу 3.
Если команда выдала command not found — Docker нужно установить. Выберите один из подразделов ниже в зависимости от вашего дистрибутива.
2a. Установка Docker на Ubuntu / Debian
Обновите список пакетов.
apt update
Установите вспомогательные утилиты.
apt install -y ca-certificates curl gnupg
Подготовьте каталог для GPG-ключей репозитория Docker.
install -m 0755 -d /etc/apt/keyrings
Скачайте GPG-ключ официального репозитория Docker.
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
Дайте права на чтение всем.
chmod a+r /etc/apt/keyrings/docker.gpg
Добавьте репозиторий Docker в систему.
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
Снова обновите список пакетов (теперь уже с новым репозиторием).
apt update
Установите Docker и плагины.
apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
2b. Установка Docker на Fedora / RHEL
Установите менеджер репозиториев.
dnf -y install dnf-plugins-core
Подключите репозиторий Docker.
dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo
Установите Docker.
dnf -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Запустите и включите автозапуск Docker.
systemctl enable --now docker
2c. Проверка установки Docker (любая ОС)
Проверьте, что Docker установлен и работает.
docker --version
Должно вывести что-то вроде Docker version 24.0.5.
Проверьте, что плагин Compose доступен.
docker compose version
Должно вывести что-то вроде Docker Compose version v2.20.2.
Если обе команды отработали без ошибок — переходите к шагу 3.
Шаг 3. Создание рабочего каталога
Создайте каталог, в котором будет лежать репозиторий olcRTC.
mkdir -p /opt/olcrtc
Перейдите в этот каталог.
cd /opt/olcrtc
Шаг 4. Скачивание исходного кода olcRTC
Скачайте репозиторий вместе с подмодулями (флаг --recurse-submodules обязателен — без него транспорт videochannel не соберётся).
git clone --depth 1 --recurse-submodules --branch master https://github.com/openlibrecommunity/olcrtc.git .
Точка в конце команды означает «скачать в текущий каталог», не создавая вложенной папки. Если вы пропустили шаг 3 (cd /opt/olcrtc), команда создаст репозиторий не в том месте.
Проверьте, что скачивание прошло успешно.
ls /opt/olcrtc
В выводе должны быть файлы Dockerfile, go.mod, каталоги cmd, internal, script и другие.
Шаг 5. Генерация ключа шифрования
Сгенерируйте ключ командой openssl.
openssl rand -hex 32
Команда выведет строку из 64 hex-символов. Например:
1c3f8a2b3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8091a2b3c4d5e6f7a8b9c0d1e2
Скопируйте этот ключ и впишите его в свою таблицу подготовки как YOUR_KEY_HEX. Этот же ключ потом понадобится для настройки клиента.
Шаг 6. Создание конфигурационного файла .env
Файл .env хранит параметры запуска. Создадим его, подставив ваши значения.
Замените:
ВАШ_КЛЮЧ— на значениеYOUR_KEY_HEXиз шага 5.my-laptop— на значениеYOUR_CLIENT_IDиз таблицы подготовки.
Если вы используете egress через WARP (раздел «Что должно быть на сервере перед установкой»), также замените 24365 на свой YOUR_SOCKS_PORT. Если не используете WARP — удалите две строки OLCRTC_SOCKS_PROXY=....
nano /opt/olcrtc/.env
В открывшемся редакторе вставьте следующее содержимое:
OLCRTC_CARRIER=wbstream
OLCRTC_TRANSPORT=vp8channel
OLCRTC_ROOM_ID=any
OLCRTC_CLIENT_ID=my-laptop
OLCRTC_KEY=ВАШ_КЛЮЧ
OLCRTC_DNS=1.1.1.1:53
OLCRTC_SOCKS_PROXY=127.0.0.1
OLCRTC_SOCKS_PROXY_PORT=24365
OLCRTC_VP8_FPS=60
OLCRTC_VP8_BATCH=64
OLCRTC_DEBUG=false
Сохраните файл: нажмите Ctrl+O, затем Enter, затем Ctrl+X.
Защитите файл от чтения посторонними (он содержит ваш ключ).
chmod 600 /opt/olcrtc/.env
Проверьте, что значения подставились правильно.
cat /opt/olcrtc/.env
В строке OLCRTC_KEY=... должен быть ваш ключ, в строке OLCRTC_CLIENT_ID=... — ваше имя пользователя.
Шаг 7. Замена docker-compose.server.yml
Стандартный compose-файл из репозитория не использует режим host, который нужен для доступа к локальному xray. Заменим его на нашу версию.
Откройте файл для редактирования.
nano /opt/olcrtc/docker-compose.server.yml
Удалите всё содержимое (зажмите Ctrl+K до полной очистки) и вставьте следующее:
services:
olcrtc-server:
build:
context: .
image: olcrtc/server:local
container_name: olcrtc-server
restart: unless-stopped
network_mode: host
environment:
OLCRTC_MODE: srv
OLCRTC_CARRIER: "${OLCRTC_CARRIER:?set OLCRTC_CARRIER}"
OLCRTC_TRANSPORT: "${OLCRTC_TRANSPORT:?set OLCRTC_TRANSPORT}"
OLCRTC_ROOM_ID: "${OLCRTC_ROOM_ID:?set OLCRTC_ROOM_ID}"
OLCRTC_CLIENT_ID: "${OLCRTC_CLIENT_ID:?set OLCRTC_CLIENT_ID}"
OLCRTC_KEY: "${OLCRTC_KEY:?set OLCRTC_KEY}"
OLCRTC_DNS: "${OLCRTC_DNS:-1.1.1.1:53}"
OLCRTC_SOCKS_PROXY: "${OLCRTC_SOCKS_PROXY:-}"
OLCRTC_SOCKS_PROXY_PORT: "${OLCRTC_SOCKS_PROXY_PORT:-1080}"
OLCRTC_VP8_FPS: "${OLCRTC_VP8_FPS:-60}"
OLCRTC_VP8_BATCH: "${OLCRTC_VP8_BATCH:-64}"
OLCRTC_DEBUG: "${OLCRTC_DEBUG:-false}"
volumes:
- olcrtc-state:/var/lib/olcrtc
init: true
volumes:
olcrtc-state:
Сохраните файл: Ctrl+O, Enter, Ctrl+X.
Шаг 8. Сборка Docker-образа olcRTC
Перейдите в каталог проекта (если ещё не там).
cd /opt/olcrtc
Запустите сборку.
docker compose -f docker-compose.server.yml --env-file .env build
Сборка длится 1–3 минуты. Скачиваются зависимости Go и компилируется бинарник. Если в процессе возникает ошибка вида «context canceled» или «network unreachable» — повторите команду; первый прогон бывает прерывистым из-за нестабильности зеркал.
Когда сборка успешно завершится, в выводе появится строка Image olcrtc/server:local Built.
Шаг 9. Запуск контейнера
Запустите контейнер в фоновом режиме.
docker compose -f docker-compose.server.yml --env-file .env up -d
Подождите 15–20 секунд, чтобы сервер успел подключиться к WB Stream и создать виртуальную конференцию.
sleep 20
Посмотрите логи.
docker logs olcrtc-server
Ожидаемый вывод:
Connecting link via direct/vp8channel/wbstream... WB Stream room created: 019e07b8-e292-73ec-a40b-6a6e4957ce01 To connect client use: -id 019e07b8-e292-73ec-a40b-6a6e4957ce01 Link connected
Скопируйте идентификатор после WB Stream room created: и впишите его в таблицу подготовки как YOUR_ROOM_ID. Без этого значения невозможно настроить клиента.
Шаг 10. Фиксация room_id в .env
Сейчас в файле .env стоит OLCRTC_ROOM_ID=any. Это значение означает «при каждом запуске создавать новую конференцию». Если оставить его — после следующего перезапуска контейнера все ссылки клиентов перестанут работать, потому что комната окажется новой.
Зафиксируйте полученный идентификатор.
Замените YOUR_ROOM_ID в команде ниже на скопированное значение из шага 9.
sed -i 's/^OLCRTC_ROOM_ID=any$/OLCRTC_ROOM_ID=YOUR_ROOM_ID/' /opt/olcrtc/.env
Перезапустите контейнер с новым значением.
docker compose -f /opt/olcrtc/docker-compose.server.yml --env-file /opt/olcrtc/.env up -d
Подождите 10 секунд и снова проверьте логи.
sleep 10 && docker logs --tail 5 olcrtc-server
Теперь в логе не должно быть строки WB Stream room created — должна быть только Connecting link via direct/vp8channel/wbstream... и Link connected. Это означает, что сервер заходит в существующую комнату, а не создаёт новую.
Шаг 11. Формирование ссылки для клиента
Ссылка имеет фиксированный текстовый формат:
olcrtc://CARRIER?TRANSPORT@ROOM_ID#KEY%CLIENT_ID$ПОДПИСЬ
Подставьте свои значения. Подпись — произвольная строка, которая отобразится в названии локации в клиентском приложении (она не влияет на работу).
Пример итоговой ссылки:
olcrtc://wbstream?vp8channel@019e07b8-e292-73ec-a40b-6a6e4957ce01#1c3f8a2b...d4e5f6a7%my-laptop$home laptop, vp8 over wbstream
| Часть ссылки | Откуда берётся |
|---|---|
wbstream
|
Из OLCRTC_CARRIER в .env
|
vp8channel
|
Из OLCRTC_TRANSPORT в .env
|
019e07b8-...
|
YOUR_ROOM_ID из шага 9
|
1c3f8a2b...
|
YOUR_KEY_HEX из шага 5
|
my-laptop
|
YOUR_CLIENT_ID из шага 6
|
Подпись после $
|
Любой описательный текст |
Сохраните полученную ссылку в надёжное место. Её нужно будет ввести в клиентское приложение.
Шаг 12. Подключение клиента
12a. Olcbox (Android, рекомендуется для смартфона)
Скачайте APK из репозитория alananisimov/olcbox (раздел Releases) и установите его на телефон.
Откройте приложение. Перейдите в раздел Locations. Нажмите Add → Import from clipboard.
Перед нажатием убедитесь, что в буфере обмена телефона лежит ваша ссылка olcrtc://... из шага 11. Скопируйте её любым способом — например, отправив самому себе в Telegram-секретный чат.
После импорта откройте созданную локацию и проверьте поля:
- Carrier должен быть
wbstream. - Transport должен быть
vp8channel. - VP8 FPS — установите
60вручную (при импорте URI этот параметр сбрасывается на дефолт приложения). - VP8 Batch — установите
64.
Включите тумблер VPN.
12b. CLI-клиент (Linux, macOS, Windows)
Скачайте бинарник olcrtc для своей операционной системы из релизов репозитория или соберите из исходников.
Запустите туннель. Замените все плейсхолдеры YOUR_* на свои значения из таблицы подготовки.
./olcrtc -mode cnc -carrier wbstream -transport vp8channel -id YOUR_ROOM_ID -client-id YOUR_CLIENT_ID -key YOUR_KEY_HEX -link direct -data data -dns 1.1.1.1:53 -vp8-fps 60 -vp8-batch 64 -socks-host 127.0.0.1 -socks-port 1080
После запуска клиент поднимет локальный SOCKS5-прокси на 127.0.0.1:1080.
Проверьте, что туннель работает.
curl --socks5-hostname 127.0.0.1:1080 https://icanhazip.com
Если egress настроен через WARP — должен вернуть IP Cloudflare WARP. Если не настроен — IP вашего сервера. В обоих случаях это не должен быть IP вашего домашнего интернета.
Команды управления одним сервером
Все команды выполняются на сервере по SSH.
Посмотреть логи в реальном времени (для выхода нажать Ctrl+C).
docker logs -f olcrtc-server
Посмотреть статус контейнера.
docker ps --filter name=olcrtc-server
Перезапустить сервер (например, после изменения .env).
docker compose -f /opt/olcrtc/docker-compose.server.yml --env-file /opt/olcrtc/.env up -d
Остановить сервер.
docker compose -f /opt/olcrtc/docker-compose.server.yml --env-file /opt/olcrtc/.env down
Обновить исходный код до свежей версии master.
cd /opt/olcrtc && git pull --recurse-submodules
Пересобрать образ после обновления кода.
docker compose -f /opt/olcrtc/docker-compose.server.yml --env-file /opt/olcrtc/.env build
Применить новый образ.
docker compose -f /opt/olcrtc/docker-compose.server.yml --env-file /opt/olcrtc/.env up -d
Управление несколькими пользователями: скрипт olcrtc-users
Зачем он нужен
Из-за архитектурного ограничения «один сервер — один клиент» (раздел «Принципы работы → Архитектурное ограничение») для каждого пользователя нужен отдельный контейнер со своим room_id, ключом и client_id. Чтобы не повторять шаги установки руками каждый раз, написан bash-скрипт olcrtc-users, который автоматизирует:
- Создание пользователя: генерация ключа, создание контейнера с уникальным client_id, ловля room_id из логов, формирование готовой ссылки.
- Удаление пользователя: остановка и удаление контейнера, удаление volume и каталога.
- Просмотр списка и информации: таблица всех пользователей с возможностью получить ссылку по выбору номера.
Что получает каждый пользователь
| Атрибут | Значение |
|---|---|
| Контейнер | olcrtc-user-<имя>
|
| Каталог конфигурации | /opt/olcrtc-users/<имя>/
|
| Файл с переменными | /opt/olcrtc-users/<имя>/.env
|
| Compose project | olcrtc-user-<имя>
|
| Docker volume | olcrtc-user-<имя>_state
|
| Виртуальная конференция | Уникальная, создаётся при первом запуске |
| Ключ шифрования | Уникальный, 32 случайных байта |
Ссылка вида olcrtc://...
|
Уникальная |
Структура каталогов
/opt/olcrtc/ # репозиторий + Dockerfile (build context)
└── (код, не меняется после установки)
/opt/olcrtc-users/ # каталог менеджера пользователей
├── shared/
│ ├── docker-compose.user.yml # один шаблон compose для всех пользователей
│ └── defaults.env # значения по умолчанию для новых пользователей
├── alice/
│ └── .env # личные данные пользователя alice
├── bob/
│ └── .env
└── carol/
└── .env
/usr/local/bin/olcrtc-users # сам скрипт-меню
Установка скрипта
Все команды выполняются на сервере по SSH.
Шаг 1. Создание общего каталога
Создайте корневой каталог для пользователей.
mkdir -p /opt/olcrtc-users/shared
Защитите каталог.
chmod 700 /opt/olcrtc-users
Шаг 2. Создание общего шаблона docker-compose
Откройте файл для редактирования.
nano /opt/olcrtc-users/shared/docker-compose.user.yml
Вставьте следующее содержимое.
services:
olcrtc:
image: olcrtc/server:local
container_name: "olcrtc-user-${OLCRTC_CLIENT_ID}"
restart: unless-stopped
network_mode: host
environment:
OLCRTC_MODE: srv
OLCRTC_CARRIER: "${OLCRTC_CARRIER}"
OLCRTC_TRANSPORT: "${OLCRTC_TRANSPORT}"
OLCRTC_ROOM_ID: "${OLCRTC_ROOM_ID}"
OLCRTC_CLIENT_ID: "${OLCRTC_CLIENT_ID}"
OLCRTC_KEY: "${OLCRTC_KEY}"
OLCRTC_DNS: "${OLCRTC_DNS}"
OLCRTC_SOCKS_PROXY: "${OLCRTC_SOCKS_PROXY}"
OLCRTC_SOCKS_PROXY_PORT: "${OLCRTC_SOCKS_PROXY_PORT}"
OLCRTC_VP8_FPS: "${OLCRTC_VP8_FPS}"
OLCRTC_VP8_BATCH: "${OLCRTC_VP8_BATCH}"
volumes:
- state:/var/lib/olcrtc
init: true
volumes:
state:
Сохраните: Ctrl+O, Enter, Ctrl+X.
Шаг 3. Создание файла значений по умолчанию
Откройте файл для редактирования.
nano /opt/olcrtc-users/shared/defaults.env
Вставьте следующее (если используете egress через WARP — оставьте порт 24365 или замените на свой YOUR_SOCKS_PORT).
OLCRTC_CARRIER=wbstream
OLCRTC_TRANSPORT=vp8channel
OLCRTC_DNS=1.1.1.1:53
OLCRTC_SOCKS_PROXY=127.0.0.1
OLCRTC_SOCKS_PROXY_PORT=24365
OLCRTC_VP8_FPS=60
OLCRTC_VP8_BATCH=64
Сохраните файл: Ctrl+O, Enter, Ctrl+X.
Защитите файл.
chmod 600 /opt/olcrtc-users/shared/defaults.env
Если egress через WARP вам не нужен, выполните дополнительную команду — она очистит поле SOCKS-прокси.
sed -i 's|OLCRTC_SOCKS_PROXY=127.0.0.1|OLCRTC_SOCKS_PROXY=|' /opt/olcrtc-users/shared/defaults.env
Шаг 4. Создание самого скрипта
Откройте файл скрипта в редакторе.
nano /usr/local/bin/olcrtc-users
Вставьте полное содержимое скрипта (исходный код целиком — в спойлере «Исходный код скрипта olcrtc-users» в конце статьи).
Сохраните файл: Ctrl+O, Enter, Ctrl+X.
Сделайте файл исполняемым.
chmod 0755 /usr/local/bin/olcrtc-users
Проверьте корректность синтаксиса.
bash -n /usr/local/bin/olcrtc-users && echo OK
Если в выводе OK — скрипт установлен правильно.
Использование скрипта
Запустите.
olcrtc-users
Появится меню:
=== olcrtc users === 1) Список пользователей (выбор → ссылка) 2) Создать пользователя 3) Удалить пользователя 0) Выход > _
Пункт 1: список пользователей
После выбора отобразится таблица:
# name status
--- ------------------------------ ------------
1) alice running
2) bob running
3) carol exited
Введите номер пользователя и нажмите Enter — появится полная карточка с готовой ссылкой olcrtc://...:
name : alice status : running carrier : wbstream transport : vp8channel room_id : 019e07b8-e292-73ec-a40b-6a6e4957ce01 client_id : alice key : 1c3f8a2b...d4e5f6a7
URI for olcbox: olcrtc://wbstream?vp8channel@019e07b8-e292-73ec-a40b-6a6e4957ce01#1c3f8a2b...d4e5f6a7%alice$alice
Чтобы пропустить выбор и вернуться в меню — нажмите Enter без ввода номера.
Пункт 2: создание пользователя
Скрипт спросит имя.
Имя пользователя:
Введите имя на латинице (буквы, цифры, _, -, длина 1–32 символа), например alice.
Затем спросит, как получить ключ.
Ключ шифрования: [a]uto / [m]anual (по умолчанию a):
Введите a (или просто нажмите Enter) — скрипт сгенерирует ключ автоматически.
Если хотите ввести ключ вручную — введите m и затем 64-символьный hex-ключ.
После этого скрипт сам:
- создаст каталог пользователя;
- запустит контейнер;
- подождёт создания виртуальной конференции;
- запишет полученный room_id в .env;
- перезапустит контейнер с фиксированным room_id;
- выведет готовую карточку с ссылкой.
Пункт 3: удаление пользователя
Скрипт покажет список.
1) alice
2) bob
3) carol
Введите номер удаляемого пользователя, нажмите Enter.
Скрипт спросит подтверждение.
Удалить пользователя "carol"? (y/N):
Введите y и нажмите Enter. Если введёте что-то другое или просто Enter — операция отменится.
После подтверждения:
- контейнер будет остановлен и удалён;
- docker volume будет удалён;
- каталог пользователя будет удалён;
- ссылка
olcrtc://...у этого пользователя перестанет работать.
Исходный код скрипта olcrtc-users
| Развернуть полный исходный код и подробное объяснение архитектуры скрипта | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Полный исходный код#!/usr/bin/env bash
# olcrtc-users — управление пользователями olcrtc через docker compose.
# UI: 3 пункта (список / создать / удалить), под капотом — отдельный контейнер на пользователя.
set -euo pipefail
USERS_DIR=/opt/olcrtc-users
SHARED=$USERS_DIR/shared
COMPOSE=$SHARED/docker-compose.user.yml
DEFAULTS=$SHARED/defaults.env
if [ ! -f "$COMPOSE" ] || [ ! -f "$DEFAULTS" ]; then
echo "[X] $SHARED is not initialized. Aborting." >&2
exit 1
fi
# ----- helpers -----
list_users() {
find "$USERS_DIR" -mindepth 1 -maxdepth 1 -type d ! -name shared -printf "%f\n" | sort
}
container_status() {
docker inspect -f "{{.State.Status}}" "olcrtc-user-$1" 2>/dev/null || echo "missing"
}
read_env() {
local f=$1 k=$2
grep -E "^${k}=" "$f" | cut -d= -f2-
}
build_uri() {
local f=$1
local carrier transport room key cid
carrier=$(read_env "$f" OLCRTC_CARRIER)
transport=$(read_env "$f" OLCRTC_TRANSPORT)
room=$(read_env "$f" OLCRTC_ROOM_ID)
key=$(read_env "$f" OLCRTC_KEY)
cid=$(read_env "$f" OLCRTC_CLIENT_ID)
printf "olcrtc://%s?%s@%s#%s%%%s\$%s\n" \
"$carrier" "$transport" "$room" "$key" "$cid" "$cid"
}
show_user() {
local user=$1
local f=$USERS_DIR/$user/.env
local status; status=$(container_status "$user")
echo "name : $user"
echo "status : $status"
echo "carrier : $(read_env "$f" OLCRTC_CARRIER)"
echo "transport : $(read_env "$f" OLCRTC_TRANSPORT)"
echo "room_id : $(read_env "$f" OLCRTC_ROOM_ID)"
echo "client_id : $(read_env "$f" OLCRTC_CLIENT_ID)"
echo "key : $(read_env "$f" OLCRTC_KEY)"
echo
echo "URI for olcbox:"
build_uri "$f"
}
valid_name() { [[ "$1" =~ ^[a-zA-Z0-9_-]{1,32}$ ]]; }
compose_up() {
local user=$1
docker compose -f "$COMPOSE" --env-file "$USERS_DIR/$user/.env" \
-p "olcrtc-user-$user" up -d
}
compose_down() {
local user=$1
docker compose -f "$COMPOSE" --env-file "$USERS_DIR/$user/.env" \
-p "olcrtc-user-$user" down -v
}
# ----- menu actions -----
action_list() {
mapfile -t users < <(list_users)
if [ ${#users[@]} -eq 0 ]; then
echo "(пользователей нет)"
return
fi
printf " %3s %-30s %-12s\n" "#" "name" "status"
printf " %3s %-30s %-12s\n" "---" "------------------------------" "------------"
local i
for i in "${!users[@]}"; do
printf " %3d) %-30s %-12s\n" \
"$((i+1))" "${users[$i]}" "$(container_status "${users[$i]}")"
done
echo
read -rp "Введите номер чтобы показать ссылку (Enter — пропустить): " pick
[ -z "$pick" ] && return
if ! [[ "$pick" =~ ^[0-9]+$ ]] || [ "$pick" -lt 1 ] || [ "$pick" -gt "${#users[@]}" ]; then
echo "(неверный номер)"
return
fi
echo
show_user "${users[$((pick-1))]}"
}
action_new() {
read -rp "Имя пользователя: " name
if ! valid_name "$name"; then
echo "(имя должно быть 1..32 символа, только a-z A-Z 0-9 _ -)"
return
fi
if [ -d "$USERS_DIR/$name" ]; then
echo "(пользователь \"$name\" уже существует)"
return
fi
local key
read -rp "Ключ шифрования: [a]uto / [m]anual (по умолчанию a): " mode
case "${mode:-a}" in
m|M)
read -rp "Введите 64-символьный hex-ключ: " key
if ! [[ "$key" =~ ^[0-9a-fA-F]{64}$ ]]; then
echo "(не выглядит как 64-hex)"
return
fi
;;
*)
key=$(openssl rand -hex 32)
echo "[*] сгенерирован ключ: $key"
;;
esac
mkdir -p "$USERS_DIR/$name"
# shellcheck disable=SC1090
set -a; source "$DEFAULTS"; set +a
cat > "$USERS_DIR/$name/.env" <<EOF
OLCRTC_CARRIER=$OLCRTC_CARRIER
OLCRTC_TRANSPORT=$OLCRTC_TRANSPORT
OLCRTC_ROOM_ID=any
OLCRTC_CLIENT_ID=$name
OLCRTC_KEY=$key
OLCRTC_DNS=$OLCRTC_DNS
OLCRTC_SOCKS_PROXY=$OLCRTC_SOCKS_PROXY
OLCRTC_SOCKS_PROXY_PORT=$OLCRTC_SOCKS_PROXY_PORT
OLCRTC_VP8_FPS=$OLCRTC_VP8_FPS
OLCRTC_VP8_BATCH=$OLCRTC_VP8_BATCH
EOF
chmod 600 "$USERS_DIR/$name/.env"
echo "[*] стартую контейнер..."
compose_up "$name" >/dev/null
echo "[*] жду создания комнаты WB Stream..."
local room=""
local i
for i in $(seq 1 30); do
sleep 2
room=$(docker logs "olcrtc-user-$name" 2>&1 \
| grep -oE "WB Stream room created: [0-9a-f-]+" \
| head -1 | awk "{print \$NF}")
[ -n "$room" ] && break
done
if [ -z "$room" ]; then
echo "[!] не удалось получить room_id. Логи:"
docker logs --tail 30 "olcrtc-user-$name"
return
fi
echo "[+] комната создана: $room"
sed -i "s/^OLCRTC_ROOM_ID=any\$/OLCRTC_ROOM_ID=$room/" "$USERS_DIR/$name/.env"
compose_up "$name" >/dev/null
sleep 3
echo
show_user "$name"
}
action_delete() {
mapfile -t users < <(list_users)
if [ ${#users[@]} -eq 0 ]; then
echo "(пользователей нет)"
return
fi
local i
for i in "${!users[@]}"; do
printf " %3d) %s\n" "$((i+1))" "${users[$i]}"
done
echo
read -rp "Номер удаляемого: " pick
if ! [[ "$pick" =~ ^[0-9]+$ ]] || [ "$pick" -lt 1 ] || [ "$pick" -gt "${#users[@]}" ]; then
echo "(неверный номер)"
return
fi
local user=${users[$((pick-1))]}
read -rp "Удалить пользователя \"$user\"? (y/N): " conf
if ! [[ "$conf" =~ ^[yY]$ ]]; then
echo "(отменено)"
return
fi
compose_down "$user" >/dev/null 2>&1 || true
rm -rf "${USERS_DIR:?}/$user"
echo "[+] пользователь $user удалён"
}
# ----- main -----
while true; do
echo
echo "=== olcrtc users ==="
echo " 1) Список пользователей (выбор → ссылка)"
echo " 2) Создать пользователя"
echo " 3) Удалить пользователя"
echo " 0) Выход"
read -rp "> " choice
case "$choice" in
1) action_list ;;
2) action_new ;;
3) action_delete ;;
0|q|Q|"") exit 0 ;;
*) echo "(неверный выбор)" ;;
esac
done
Устройство скриптаОбщий принципСкрипт — это интерактивная обёртка над Каждый пользователь — это отдельный compose-проект с уникальным именем Защитные механизмы
Хелперы
Действие «Список пользователей»
Действие «Создать пользователя»
Действие «Удалить пользователя»
Главный циклБесконечный цикл с
Возможные расширенияСкрипт намеренно простой и легко расширяется. Возможные улучшения:
|
FAQ
Почему «один сервер ↔ один клиент»?
Это архитектурное свойство кода: сервер хранит одну сессию smux и одно поле clientID, не таблицу пиров. Изменение этой модели потребовало бы существенной переработки internal/server/server.go и поддержки множественных peer-connection в каждом провайдере.
Почему рекомендуется vp8channel, а не datachannel?
datachannel быстрее и имеет минимальный пинг, но: Telemost его не поддерживает, а Jazz может ограничивать IP-адреса серверов, использующих этот тип канала. vp8channel работает со всеми тремя сервисами и подходит для большинства сценариев.
Что такое «ограничение IP» со стороны carrier?
Некоторые carrier-сервисы используют автоматические эвристики против ботов. После срабатывания таких эвристик подключения с конкретного IP могут перестать пропускаться в виртуальные конференции. Лечится сменой IP сервера или ожиданием снятия ограничения. На момент написания статьи WB Stream таких эвристик не применяет.
Сколько контейнеров можно запустить на одной виртуальной машине?
В простое каждый контейнер потребляет приблизительно 10–15 МБ RAM и около 0% CPU. На VM с 4 GiB RAM реалистично запустить 50–100 пользователей. Узкими местами обычно становятся пропускная способность сетевого канала и допустимое количество одновременных WebRTC-сессий со стороны carrier-сервиса.
Можно ли использовать одну ссылку с нескольких устройств?
Технически — да, но не одновременно. Если включить туннель на двух устройствах с одной ссылкой, они будут конкурировать за один peer-connection и периодически разрывать друг друга. Для параллельной работы нужны разные пользователи (разные ссылки).
Виден ли реальный видеосигнал участникам конференции?
В транспортах vp8channel и seichannel поверх WebRTC отправляется минимально валидный видеопоток, в который встроены полезные данные. Внешне это выглядит как очень тихая «моностатичная» камера. В videochannel отправляется реальный видеоряд (QR-коды или тайлы) — формально это видимая «картинка». Если в виртуальной конференции, кроме сервера и клиента, никого нет — это никак не проявляется.
Что делать, если конкретный transport перестал работать?
Если carrier изменил проверки SFU и какой-то transport стал ненадёжен — переключитесь на другой transport (seichannel или videochannel) или другой carrier. Меняется в defaults.env для новых пользователей и в личном .env для существующих (с последующим перезапуском контейнера).
Можно ли совместить olcRTC с другими методами?
Да. С точки зрения клиентского приложения olcRTC — это локальный SOCKS5-прокси. Его можно использовать как один из outbound в xray, sing-box и подобных инструментах. На стороне сервера выходной трафик может быть направлен через xray + WARP (опциональный шаг 11 раздела установки) для дополнительной анонимизации.
Полезные ссылки
- Репозиторий olcrtc на GitHub — основной upstream проекта.
- Olcbox — мультиплатформенный клиент с UI (Android, macOS, Windows, Linux).
- docs/uri.md — официальное описание формата URI.
- docs/sub.md — формат файла подписки для нескольких локаций.
- docs/settings.md — матрица совместимости carrier × transport, описание всех флагов.
- 3x-ui — панель управления xray-core (для настройки egress через WARP).