olcRTC tunnel server for MikroTik RouterOS containers
190
olcRTC tunnel server for MikroTik RouterOS containers.
Patched build of openlibrecommunity/olcrtc — tunnels TCP/UDP traffic through public video-conferencing platforms (Telemost / Jitsi / WBStream) by disguising it as a WebRTC video call. Pairs with the WireTurn Android client.
Built from source on every push. Config-file driven: drop one or more *.yaml in the mount directory and the container brings up a separate olcRTC process for each.
This image is not vanilla olcRTC. Four patches are applied at build time to make the Telemost provider actually work from a datacenter/RouterOS container and to make client pairing painless. Upstream (as of this build) does not carry them.
| # | Patch | Why |
|---|---|---|
| 1 | X-Telemost-Client-Version bumped 187.1.0 → 207.3.0 + fresh User-Agent | Yandex raised the minimum client version; old value gets rejected. Override with --build-arg TELEMOST_CLIENT_VERSION=... |
| 2+3 | HTTP/2 disabled in the HTTP client (ForceAttemptHTTP2=false, empty TLSNextProto) + ALPN pinned to http/1.1 in the TLS config | cloud-api.yandex.ru negotiates HTTP/2 but sends a broken SETTINGS frame → connection reset → the auth request never reaches the API. Forcing HTTP/1.1 (like a browser) fixes it. This was the real blocker — the error surfaces misleadingly as auth provider rejected ... 400. |
| 4 | Server prints a ready-to-copy client URI to the log on connect | The vp8channel frame token is derived from the room string. If the server config uses the full room URL and the client uses the bare ID, tokens mismatch and no data flows. The logged URI carries the exact same room string the server used, so client pairing can't drift. |
Plus: GODEBUG=http2client=0 is exported in the entrypoint as a belt-and-suspenders HTTP/2 kill-switch, the entrypoint self-restarts a crashed process inside the container (so RouterOS doesn't restart-storm and take down neighbouring containers), and curl is bundled for in-container debugging.
Full write-up of the reverse-engineering path is in PATCH_NOTES.md in the build context.
| Tag | Notes |
|---|---|
latest | Newest build |
uri | Adds patch 4 (client URI printed to log) |
h2fix | Adds patches 2+3 (HTTP/2 disabled + ALPN pin) — the fix that made Telemost connect |
v1 | Initial patched build (version bump only) |
RouterOS caches images by name:tag. When updating, build under a new tag and give the container a new
root-dir, otherwise the old layer is reused.
server.<provider>.<transport>.yaml files in the mount directory (/etc/olcrtc inside the container).*.yaml / *.yml and starts one olcRTC process per file — so several rooms / providers / users can run side by side.WireTurn client URI line — copy that straight into the client.Recommended combo for stealth: Telemost + vp8channel (below). For raw speed with less stealth: Jitsi + datachannel.
server.telemost.vp8channel.yaml — Telemost carrier, VP8 steganography transport:
mode: srv
auth:
provider: telemost
room:
# Create a meeting at telemost.yandex.ru and paste its link (or bare ID).
# Whatever form you use here is echoed back in the logged client URI.
id: "https://telemost.yandex.ru/j/PUT_ROOM_ID_HERE"
crypto:
# 64 hex chars (32 bytes). Generate: openssl rand -hex 32
# Same key must be used by the client.
key: "PUT_64_HEX_KEY_HERE"
net:
transport: vp8channel
dns: "8.8.8.8:53" # must be a DNS server the container can actually reach
liveness:
interval: 10s
timeout: 15s
failures: 4
vp8:
fps: 30
batch_size: 64
debug: false
Prefer keeping the key out of the file? Replace the crypto block with:
crypto:
key_file: "/etc/olcrtc/olcrtc.key" # 64 hex chars, one line, same dir
Jitsi alternative (server.jitsi.datachannel.yaml) — no Yandex API, faster, less stealthy:
mode: srv
auth:
provider: jitsi
room:
id: "https://meet.jit.si/YourRoomName"
crypto:
key: "PUT_64_HEX_KEY_HERE"
net:
transport: datachannel
dns: "8.8.8.8:53"
liveness:
interval: 10s
timeout: 15s
failures: 4
debug: false
/interface/veth add name=veth-olc address=172.16.182.2/24 gateway=172.16.182.1
/ip/address add address=172.16.182.1/24 interface=veth-olc
/ip/firewall/nat/add chain=srcnat src-address=172.16.182.0/24 \
action=masquerade comment="olcrtc container out"
/container/mounts/add name=olc_config src=/docker/olc-confs dst=/etc/olcrtc
Place your server.*.yaml (and optional olcrtc.key) in /docker/olc-confs/ before starting.
/container/add \
remote-image=ulfrasark/olcrtc:latest \
interface=veth-olc \
root-dir=disk1/docker/olcrtc \
mounts=olc_config \
dns=8.8.8.8 \
logging=yes \
start-on-boot=yes \
restart-policy=on-failure restart-interval=60s
The entrypoint restarts a crashed olcRTC process internally, so
on-failurewith a long interval is enough — the whole container almost never needs bouncing, and neighbours stay safe.
/system/device-mode/update container=yes
Confirm with a cold reboot (power off + power on via your VPS control panel).
/container/start [find tag~"olcrtc"]
Telemost's signaling / STUN / TURN / media servers are reached by these hostnames. If you block Yandex on the container's outbound path, allow these domains (all ports — WebRTC media uses ephemeral UDP ports, not just 3478/443). You do not need to open all of Yandex.
cloud-api.yandex.ru # HTTP API — conference auth (TCP 443)
goloom.strm.yandex.net # media signaling — WebSocket (TCP 443)
stun.rtc.yandex.net # STUN (UDP 3478)
turn.tel.yandex.net # TURN relay (UDP/TCP 3478, 443 + relayed media)
On RouterOS, add them to an address-list by hostname — RouterOS resolves each name and keeps the resolved IPs in the list:
/ip/firewall/address-list add list=yandex_telemost address=cloud-api.yandex.ru
/ip/firewall/address-list add list=yandex_telemost address=goloom.strm.yandex.net
/ip/firewall/address-list add list=yandex_telemost address=stun.rtc.yandex.net
/ip/firewall/address-list add list=yandex_telemost address=turn.tel.yandex.net
/ip/firewall/filter/add chain=forward src-address=172.16.182.0/24 \
dst-address-list=yandex_telemost action=accept place-before=0
RouterOS expands a hostname in an address-list only to the IPs it resolves at add time (and on DNS refresh). These Yandex names sit behind CNAME chains and rotate across several IPs, so the list can lag reality and you may see occasional media timeouts on a fresh IP. If that happens, re-resolve (
/ip/dns/cache/flush) or, for a rock-solid setup, allow the underlying media subnets instead:37.9.64.0/18,77.88.0.0/18,87.250.224.0/19,213.180.192.0/19.
Not needed for the Jitsi provider.
Copy the olcrtc://... URI straight from the server log:
/log/print where topics~"container"
Look for the WireTurn client URI line and import it into WireTurn. Because that URI carries the server's exact room string, the vp8channel frame tokens are guaranteed to match — no token mismatch.
/log/print where topics~"container"
Healthy Telemost startup ends with Link connected, the client URI block, then got new track once media flows.
Upstream project: openlibrecommunity/olcrtc Android client: spkprsnts/WireTurn
Content type
Image
Digest
sha256:f8f654d8d…
Size
17 MB
Last updated
20 days ago
docker pull ulfrasark/olcrtc:v5