kill_hbbs_hbbr_connections.sh is a Bash script designed to terminate active network connections on specific RustDesk server ports without stopping or killing the RustDesk server processes (hbbs and hbbr).
The script is intended for system administrators running a self-hosted RustDesk server who need to:
- Reset active or stuck connections
- Force clients to reconnect
- Perform maintenance or debugging
- Clear established sessions without restarting services
The script relies on the Linux ss utility and uses the ss -K command to drop TCP connections at the socket level.
RustDesk is a remote desktop solution that attempts to establish direct client-to-client (P2P) connections when network conditions allow it (e.g. via NAT traversal / hole punching).
When a direct connection cannot be established, traffic falls back to a relay path.
This behavior is documented in the official RustDesk documentation:
- https://rustdesk.com/docs/en/
- https://rustdesk.com/docs/en/self-host/
- https://github.com/rustdesk/rustdesk/wiki/FAQ
In a self-hosted setup, the server-side infrastructure typically includes:
- hbbs — Rendezvous / ID / Signaling server
(handles client discovery, ID registration, NAT detection, and connection setup) - hbbr — Relay server
(relays traffic only when direct P2P connectivity is not possible)
A detailed explanation of the architecture and connection flow is available in the official documentation:
🔗 https://github.com/rustdesk/rustdesk/wiki/How-does-RustDesk-work%3F
- A RustDesk client connects to hbbs
- hbbs performs:
- Client ID registration
- NAT type detection
- Signaling and hole punching
- If a direct P2P connection is possible, traffic flows directly between peers
- If NAT traversal fails, traffic is relayed through hbbr
- Optional web clients connect via WebSocket endpoints
| Port | Protocol | Description |
|---|---|---|
| 21115 | TCP | NAT type test and rendezvous handshake |
| 21116 | UDP | Client ID registration and heartbeat |
| 21116 | TCP | TCP hole punching and signaling |
| 21118 | TCP | Web client support (WebSocket, optional) |
| Port | Protocol | Description |
|---|---|---|
| 21117 | TCP | Relay service for indirect connections |
| 21119 | TCP | Web client support (WebSocket, optional) |
Note
Ports21118and21119are only required if the RustDesk web client is used.
If the web client is not needed, these ports can be safely closed.
The script operates only at the network connection level.
- ✅ Drops active TCP connections
- ❌ Does not stop or restart
hbbsorhbbr - ❌ Does not kill processes
- 🔒 Requires
sudoprivileges - 🎯 Targets only RustDesk-related ports
21115 21116 21117 21118 21119
The script supports two execution modes:
Drops only established TCP connections, leaving handshake or transient states untouched.
Command used internally:
ss -K state established sport = :PORTThis mode is safer and minimizes unintended disruption.
Drops all TCP connection states on the target ports. Command used internally:
ss -K sport = :PORTThis mode is more aggressive and should be used with caution.
The script can operate in two ways:
- All default RustDesk ports
- A single specified port (e.g.
21115)
This allows precise control when troubleshooting specific components such as:
Rendezvous* issues (21115)
- Relay congestion (
21117) - Web client sessions (
21118,21119)
- Resetting stuck RustDesk client sessions
- Forcing reconnects after network changes
- Clearing stale relay connections
- Performing live maintenance without downtime
- Debugging NAT traversal or relay behavior
In a RustDesk self-hosted environment, restarting hbbs or hbbr:
- Disconnects all clients
- Interrupts active sessions
- May impact service availability
This script provides a non-disruptive alternative, allowing administrators to control connectivity without service restarts.
Official RustDesk architecture documentation:
🔗 How does RustDesk work
#!/bin/bash
# kill_hbbs_hbbr_connections.sh
# Kill ONLY network connections (NOT processes) for RustDesk hbbs/hbbr ports.
DEFAULT_PORTS=(21115 21116 21117 21118 21119)
DOC_LINK="https://github.com/rustdesk/rustdesk/wiki/How-does-RustDesk-work%3F"
print_intro() {
cat <<EOF
RustDesk connection killer (connections only, processes are NOT stopped)
How RustDesk works (diagram / protocol overview):
$DOC_LINK
Port reference (RustDesk self-hosting docs):
hbbs (ID / rendezvous server):
- 21115/TCP : NAT type test
- 21116/UDP : ID registration + heartbeat
- 21116/TCP : TCP hole punching + connection service
- 21118/TCP : Web client support (WebSocket endpoint)
hbbr (relay server):
- 21117/TCP : Relay service
- 21119/TCP : Web client support (WebSocket endpoint)
Notes:
- If you don't need the web client, ports 21118 and 21119 can be closed.
- This script uses 'ss -K' to drop existing TCP connections without killing hbbs/hbbr processes.
EOF
}
usage() {
cat <<'EOF'
Usage:
sudo ./kill_hbbs_hbbr_connections.sh [options]
Options:
-m, --mode MODE MODE: all | established
all -> ss -K sport = :PORT
established -> ss -K state established sport = :PORT (recommended)
-p, --port PORT Kill connections only on a specific port (e.g. 21115).
If omitted, default ports are used:
21115 21116 21117 21118 21119
-l, --list List current TCP connections on target ports and exit.
-h, --help Show this help message.
Examples:
# Recommended mode on all default ports
sudo ./kill_hbbs_hbbr_connections.sh -m established
# Standard mode on all default ports
sudo ./kill_hbbs_hbbr_connections.sh -m all
# Target a single port (recommended)
sudo ./kill_hbbs_hbbr_connections.sh -m established -p 21115
# List connections only
sudo ./kill_hbbs_hbbr_connections.sh --list
EOF
}
MODE="established"
TARGET_PORT=""
DO_LIST="0"
# Print description + doc link at script start
print_intro
# Parse arguments
while [[ $# -gt 0 ]]; do
case "$1" in
-m|--mode)
MODE="$2"
shift 2
;;
-p|--port)
TARGET_PORT="$2"
shift 2
;;
-l|--list)
DO_LIST="1"
shift
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown argument: $1"
echo
usage
exit 1
;;
esac
done
# Validate mode
if [[ "$MODE" != "all" && "$MODE" != "established" ]]; then
echo "Invalid mode: $MODE (use: all | established)"
exit 1
fi
# Build port list
PORTS=()
if [[ -n "$TARGET_PORT" ]]; then
if ! [[ "$TARGET_PORT" =~ ^[0-9]+$ ]] || (( TARGET_PORT < 1 || TARGET_PORT > 65535 )); then
echo "Invalid port: $TARGET_PORT"
exit 1
fi
PORTS=("$TARGET_PORT")
else
PORTS=("${DEFAULT_PORTS[@]}")
fi
list_connections() {
echo "Current TCP connections on ports: ${PORTS[*]}"
for p in "${PORTS[@]}"; do
echo "---- PORT $p ----"
if [[ "$MODE" == "established" ]]; then
ss -Htn state established "( sport = :$p )" || true
else
ss -Htan "( sport = :$p )" || true
fi
done
}
kill_connections() {
for p in "${PORTS[@]}"; do
if [[ "$MODE" == "established" ]]; then
echo "Killing ESTABLISHED connections on port $p ..."
ss -K state established sport = :$p >/dev/null 2>&1 || true
else
echo "Killing ALL connections on port $p ..."
ss -K sport = :$p >/dev/null 2>&1 || true
fi
done
}
if [[ "$DO_LIST" == "1" ]]; then
list_connections
exit 0
fi
echo "Mode: $MODE"
echo "Ports: ${PORTS[*]}"
kill_connections
echo "Done."