In on-site operation and maintenance, you may be troubled by the following issues:
- • Remote devices are scattered in weak network/cellular/private network environments, unable to open public IPs, and temporary debugging requires sending personnel on-site.
- • VPN/port forwarding configurations are complex and unstable, making it difficult to implement fine-grained permissions and operation logging.
- • Device resources are limited (flash/memory/CPU), unable to support heavyweight remote control components.rtty is a lightweight solution designed for the above scenarios.
What is rtty
- • Architecture:
<span>rtty (C client)</span>↔<span>WebSocket</span>↔<span>rttys (Go server + Web frontend)</span> - • Usage:Access the system terminal of on-site embedded devices remotely through a browser, without relying on public IPs and VPNs; devices are identified by a unique device ID.
- • Applicable:OpenWrt/Buildroot/Yocto/any embedded Linux, low storage/memory usage, stable operation.
Illustration:
┌──────────────┐ wss/ws ┌──────────────┐
│ rtty client │ ───────────────────▶ │ rttys │ ──▶ Browser UI
│ (device) │ ◀─────────────────── │ (server) │ ◀──┘
└──────────────┘ keepalive+auth └──────────────┘
Server rttys Deployment
Minimal Quick Start (Verify Link)
# Prepare Go environment (Linux x86_64)
go version || sudo apt-get update && sudo apt-get install -y golang
# Get and run rttys
git clone https://github.com/zhaojh329/rttys.git
cd rttys
go run main.go # Default listens on :5912
# Access in browser: http://<serverIP>:5912 to confirm the page can be opened
Managed by systemd (Daemon/Auto Start/Logs)
# /etc/systemd/system/rttys.service
[Unit]
Description=rttys server (WebSocket terminal broker)
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
WorkingDirectory=/opt/rttys
ExecStart=/usr/local/bin/rttys
Restart=always
RestartSec=3
User=nobody
Group=nogroup
LimitNOFILE=65536
Environment=RTTYS_ADDR=:5912
[Install]
WantedBy=multi-user.target
# Install and enable
install -d /opt/rttys
cp ./rttys /usr/local/bin/rttys # If using the binary generated by go build
systemctl daemon-reload
systemctl enable --now rttys
systemctl status rttys -n 50 --no-pager
Notes:
- • It is recommended to manage the listening address through the environment variable
<span>RTTYS_ADDR=:5912</span>, to avoid hardcoding. - •
<span>Restart=always</span>+<span>RestartSec=3</span>ensures the process is automatically restarted after unexpected exits.
Enable TLS and Reverse Proxy
In production environments, it is recommended to use Nginx/Caddy/Traefik to provide HTTPS and correctly handle WebSocket upgrades:
# /etc/nginx/conf.d/rttys.conf
server {
listen 443 ssl;
server_name rtty.example.com;
ssl_certificate /etc/ssl/certs/fullchain.pem;
ssl_certificate_key /etc/ssl/private/privkey.pem;
location / {
proxy_pass http://127.0.0.1:5912;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 3600s;
}
# Optional: Simple basic authentication
# auth_basic "Restricted";
# auth_basic_user_file /etc/nginx/.htpasswd;
}
nginx -t && systemctl reload nginx
Network and Firewall:
- • Allow inbound port on the server:
<span>443</span>(if directly connecting to rttys, then allow<span>5912</span>). - • The client only needs to connect to the server on that port (commonly device → cloud outbound 443).
Client rtty Deployment on Embedded Devices
Dependencies and Compilation Options
Client dependencies:
- •
<span>libev</span>(event loop) - •
<span>libuwsc</span>(lightweight WebSocket client) - • SSL library (choose one):
<span>mbedtls</span>/<span>wolfssl</span>/<span>openssl</span>(recommended to enable for wss support)
General Cross-Compilation Approach:
export TOOLCHAIN_PREFIX=arm-linux-gnueabihf-
export SYSROOT=/opt/toolchains/arm-sysroot
export CC=${TOOLCHAIN_PREFIX}gcc
export PKG_CONFIG_PATH=$SYSROOT/usr/lib/pkgconfig:$SYSROOT/usr/share/pkgconfig
export PKG_CONFIG_SYSROOT_DIR=$SYSROOT
Build Dependencies (Example with openssl + libev + libuwsc):
# Cross-compile from source (example command, adjust according to actual version and path)
# OpenSSL (or use mbedtls/wolfssl)
tar xf openssl-1.1.1w.tar.gz &&& cd openssl-1.1.1w
./Configure linux-generic32 --prefix=/usr --cross-compile-prefix=${TOOLCHAIN_PREFIX} --openssldir=/etc/ssl
make -j &&& make DESTDIR="$SYSROOT" install
# libev
tar xf libev-4.33.tar.gz &&& cd libev-4.33
./configure --host=arm-linux --prefix=/usr --with-pic --disable-shared --enable-static
make -j &&& make DESTDIR="$SYSROOT" install
# libuwsc (supports pkg-config)
git clone https://github.com/zhaojh329/libuwsc.git &&& cd libuwsc
make CC=${CC} SYSROOT=${SYSROOT} PREFIX=/usr STATIC=1
make DESTDIR="$SYSROOT" PREFIX=/usr install
Compile rtty client:
git clone https://github.com/zhaojh329/rtty.git
cd rtty
# CMake build (recommended)
cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_SYSROOT=$SYSROOT \
-DCMAKE_C_COMPILER=${CC} \
-DCMAKE_FIND_ROOT_PATH=$SYSROOT \
-DOPENSSL_ROOT_DIR=$SYSROOT/usr \
-DMBEDTLS_ROOT_DIR=$SYSROOT/usr
cmake --build build -j
file build/rtty &&& ${TOOLCHAIN_PREFIX}strip build/rtty
Copy to device:
scp build/rtty root@<device-ip>:/usr/bin/rtty
ssh root@<device-ip> 'chmod +x /usr/bin/rtty'
Run and Auto Start
Minimal run:
/usr/bin/rtty -I <deviceID> -h <rttys server address or domain name>
# For example: /usr/bin/rtty -I gw-7f3a2c -h rtty.example.com
systemd (for systemd devices):
# /etc/systemd/system/rtty.service
[Unit]
Description=rtty client (connects device terminal to rttys)
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
Environment=DEVICE_ID=gw-7f3a2c
Environment=RTTYS_HOST=rtty.example.com
ExecStart=/usr/bin/rtty -I ${DEVICE_ID} -h ${RTTYS_HOST}
Restart=always
RestartSec=2
[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable --now rtty
systemctl status rtty -n 50 --no-pager
init.d (BusyBox/non-systemd devices):
#!/bin/sh
# /etc/init.d/rtty
### BEGIN INIT INFO
# Provides: rtty
# Required-Start: $network
# Required-Stop: $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
### END INIT INFO
DAEMON=/usr/bin/rtty
ID_FILE=/etc/rtty/device_id
HOST_FILE=/etc/rtty/host
[ -x "$DAEMON" ] || exit 0
start() {
mkdir -p /etc/rtty
[ -f "$ID_FILE" ] || echo gw-7f3a2c > "$ID_FILE"
[ -f "$HOST_FILE" ] || echo rtty.example.com > "$HOST_FILE"
ID=$(cat "$ID_FILE")
HOST=$(cat "$HOST_FILE")
start-stop-daemon -S -b -x "$DAEMON" -- -I "$ID" -h "$HOST"
}
stop() {
start-stop-daemon -K -x "$DAEMON"
}
case "$1" in
start) start ;;
stop) stop ;;
restart) stop; start ;;
*) echo "Usage: $0 {start|stop|restart}" ; exit 1 ;;
esac
exit 0
chmod +x /etc/init.d/rtty &&& /etc/init.d/rtty start
Troubleshooting Common Issues
- 1. The browser can open the page but the connection drops instantly
- • Is the reverse proxy correctly set up with
<span>Upgrade/Connection</span>headers, and is<span>proxy_read_timeout</span>set sufficiently high? - • Large time drift between server/device causing TLS handshake failure (enable NTP).
- 2. The device side reports missing libraries
- •
<span>ldd /usr/bin/rtty</span>check if dependencies are in the target root filesystem; if necessary, switch to static linking or copy missing<span>.so</span>.
- 3. The device can ping the domain but cannot connect to the port
- •
<span>telnet rtty.example.com 443</span>or<span>nc -vz rtty.example.com 443</span>verify if outbound is allowed by the firewall.
- 4. Operation delay after many devices connect simultaneously
- • Check rttys server CPU/memory and file handle limits; increase
<span>LimitNOFILE</span>, increase instance count, and implement load balancing.
- 5. Occasional disconnections
- • Increase reverse proxy timeout and buffering, check for link jitter (cellular/weak network); use system services to auto-restart the client.
Log Location:
# Server
journalctl -u rttys -n 200 --no-pager
# Client (systemd devices)
journalctl -u rtty -n 200 --no-pager
———— END ————

The Shenzhen International Electronics Show and Embedded Exhibition elexcon has opened, with guests from Qualcomm, Renesas, and other companies sharing exciting insights!

Visual AI is one of the fastest-growing embedded AI disciplines.

How to reduce bugs in the three stages of coding, testing, and debugging?