Add host firewall script for LiveKit ports
This commit is contained in:
@@ -72,12 +72,27 @@ docker compose -f infra/docker-compose.yml up -d
|
||||
| API | 8080 |
|
||||
| LiveKit | 7880 |
|
||||
|
||||
If the host runs a firewall, open the LiveKit ports:
|
||||
|
||||
```
|
||||
sudo ./infra/firewall.sh
|
||||
```
|
||||
|
||||
It allows 7880 and 7881 TCP, 3478 UDP and 50000-50100 UDP from your LAN, handling ufw and
|
||||
firewalld. Pass `--dry-run` to see the commands first, `--subnet` to name a different network or
|
||||
`--open-to-all` to drop the source restriction. The website and API need no rules, since Docker
|
||||
publishes those ports with its own firewall rules. LiveKit runs on the host network and does not
|
||||
get that treatment, so a firewalled host will load the site and then fail to connect to a room.
|
||||
|
||||
Sign in at `/admin` with the bootstrap admin details from your `.env`.
|
||||
|
||||
If you are serving anything other than localhost, set `PUBLIC_API_URL` and
|
||||
`PUBLIC_LIVEKIT_URL` in `infra/.env` to addresses your devices can actually reach, and change
|
||||
`turn.domain` in `infra/livekit.yaml` to the same host. LiveKit reads that file literally, so it
|
||||
does not pick up environment variables.
|
||||
If you are serving anything other than localhost, set `PUBLIC_API_URL`, `PUBLIC_LIVEKIT_URL` and
|
||||
`PUBLIC_WEB_URL` in `infra/.env` to addresses your devices can actually reach, add
|
||||
`PUBLIC_WEB_URL` to `CORS_ORIGINS`, and change `turn.domain` in `infra/livekit.yaml` to the same
|
||||
host. LiveKit reads that file literally, so it does not pick up environment variables.
|
||||
|
||||
Leaving `CORS_ORIGINS` on its localhost default while browsing by LAN address is the usual cause
|
||||
of requests failing with a missing `Access-Control-Allow-Origin` header.
|
||||
|
||||
The LiveKit container uses host networking, because WebRTC needs to advertise an address your
|
||||
devices can reach and a container on a bridge network has none. That is Linux only; on macOS or
|
||||
@@ -128,7 +143,8 @@ Set in `infra/.env`:
|
||||
| `PIN_ROTATION_SECONDS` | How often join codes change, 30 to 60 |
|
||||
| `PIN_GRACE_SECONDS` | How long an old code keeps working after it changes |
|
||||
| `PUBLIC_API_URL` / `PUBLIC_LIVEKIT_URL` | Addresses browsers and kiosks use to reach you |
|
||||
| `CORS_ORIGINS` | Browser origins allowed to call the API. Kiosks are exempt, since a desktop app has no fixed web origin |
|
||||
| `PUBLIC_WEB_URL` | The address the website is served on. Must match what you type in the browser, scheme included, or server rendered pages disagree with the browser |
|
||||
| `CORS_ORIGINS` | Browser origins allowed to call the API, comma separated. Must include `PUBLIC_WEB_URL`. Kiosks are exempt, since a desktop app has no fixed web origin |
|
||||
|
||||
Video encoding on the kiosk is tunable per device, without rebuilding:
|
||||
|
||||
|
||||
Executable
+153
@@ -0,0 +1,153 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SUBNET=""
|
||||
OPEN_TO_ALL="no"
|
||||
DRY_RUN="no"
|
||||
|
||||
log() { printf '\033[1;34m==>\033[0m %s\n' "$*"; }
|
||||
warn() { printf '\033[1;33m==>\033[0m %s\n' "$*" >&2; }
|
||||
fail() { printf '\033[1;31m==>\033[0m %s\n' "$*" >&2; exit 1; }
|
||||
|
||||
usage() {
|
||||
cat <<'USAGE'
|
||||
PiStation host firewall setup
|
||||
|
||||
sudo ./infra/firewall.sh [options]
|
||||
|
||||
Opens the ports LiveKit needs. The web and API containers publish their ports
|
||||
through Docker, which writes its own rules and is not affected by the host
|
||||
firewall. LiveKit runs on the host network, so it is.
|
||||
|
||||
Options
|
||||
--subnet <cidr> Allow only this network, defaults to the LAN behind your default route
|
||||
--open-to-all Allow from any address instead of a single network
|
||||
--dry-run Print the commands without running them
|
||||
--help Show this message
|
||||
USAGE
|
||||
}
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--subnet) SUBNET="${2:-}"; shift 2 ;;
|
||||
--subnet=*) SUBNET="${1#*=}"; shift ;;
|
||||
--open-to-all) OPEN_TO_ALL="yes"; shift ;;
|
||||
--dry-run) DRY_RUN="yes"; shift ;;
|
||||
--help|-h) usage; exit 0 ;;
|
||||
*) fail "unknown option: $1" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
PORTS_TCP=(7880 7881)
|
||||
PORTS_UDP=(3478)
|
||||
RANGE_UDP_START=50000
|
||||
RANGE_UDP_END=50100
|
||||
|
||||
detect_subnet() {
|
||||
local interface
|
||||
interface="$(ip route show default 2>/dev/null | awk '/default/ {print $5; exit}')"
|
||||
[[ -n "$interface" ]] || return 1
|
||||
ip -o -f inet route show scope link dev "$interface" 2>/dev/null | awk '{print $1; exit}'
|
||||
}
|
||||
|
||||
run() {
|
||||
if [[ "$DRY_RUN" == "yes" ]]; then
|
||||
printf ' %s\n' "$*"
|
||||
else
|
||||
"$@" >/dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
if [[ "$OPEN_TO_ALL" == "no" && -z "$SUBNET" ]]; then
|
||||
SUBNET="$(detect_subnet || true)"
|
||||
[[ -n "$SUBNET" ]] || fail "could not work out your LAN subnet, pass --subnet or --open-to-all"
|
||||
fi
|
||||
|
||||
if [[ "$DRY_RUN" == "no" && $EUID -ne 0 ]]; then
|
||||
fail "run this with sudo, or pass --dry-run to see what it would do"
|
||||
fi
|
||||
|
||||
apply_ufw() {
|
||||
if [[ "$OPEN_TO_ALL" == "yes" ]]; then
|
||||
for port in "${PORTS_TCP[@]}"; do
|
||||
run ufw allow "${port}/tcp"
|
||||
done
|
||||
for port in "${PORTS_UDP[@]}"; do
|
||||
run ufw allow "${port}/udp"
|
||||
done
|
||||
run ufw allow "${RANGE_UDP_START}:${RANGE_UDP_END}/udp"
|
||||
return
|
||||
fi
|
||||
|
||||
for port in "${PORTS_TCP[@]}"; do
|
||||
run ufw allow from "$SUBNET" to any port "$port" proto tcp
|
||||
done
|
||||
for port in "${PORTS_UDP[@]}"; do
|
||||
run ufw allow from "$SUBNET" to any port "$port" proto udp
|
||||
done
|
||||
run ufw allow from "$SUBNET" to any port "${RANGE_UDP_START}:${RANGE_UDP_END}" proto udp
|
||||
}
|
||||
|
||||
apply_firewalld() {
|
||||
if [[ "$OPEN_TO_ALL" == "yes" ]]; then
|
||||
for port in "${PORTS_TCP[@]}"; do
|
||||
run firewall-cmd --permanent "--add-port=${port}/tcp"
|
||||
done
|
||||
for port in "${PORTS_UDP[@]}"; do
|
||||
run firewall-cmd --permanent "--add-port=${port}/udp"
|
||||
done
|
||||
run firewall-cmd --permanent "--add-port=${RANGE_UDP_START}-${RANGE_UDP_END}/udp"
|
||||
else
|
||||
for port in "${PORTS_TCP[@]}"; do
|
||||
run firewall-cmd --permanent "--add-rich-rule=rule family=ipv4 source address=${SUBNET} port port=${port} protocol=tcp accept"
|
||||
done
|
||||
for port in "${PORTS_UDP[@]}"; do
|
||||
run firewall-cmd --permanent "--add-rich-rule=rule family=ipv4 source address=${SUBNET} port port=${port} protocol=udp accept"
|
||||
done
|
||||
run firewall-cmd --permanent "--add-rich-rule=rule family=ipv4 source address=${SUBNET} port port=${RANGE_UDP_START}-${RANGE_UDP_END} protocol=udp accept"
|
||||
fi
|
||||
run firewall-cmd --reload
|
||||
}
|
||||
|
||||
print_manual() {
|
||||
cat <<MANUAL
|
||||
No supported firewall front end was found. If you are running nftables or
|
||||
iptables directly, allow these from ${SUBNET:-any address}:
|
||||
|
||||
tcp ${PORTS_TCP[*]}
|
||||
udp ${PORTS_UDP[*]}
|
||||
udp ${RANGE_UDP_START}-${RANGE_UDP_END}
|
||||
MANUAL
|
||||
}
|
||||
|
||||
if command -v ufw >/dev/null 2>&1; then
|
||||
BACKEND="ufw"
|
||||
elif command -v firewall-cmd >/dev/null 2>&1; then
|
||||
BACKEND="firewalld"
|
||||
else
|
||||
BACKEND="none"
|
||||
fi
|
||||
|
||||
if [[ "$BACKEND" == "ufw" && $EUID -eq 0 ]] && ! ufw status 2>/dev/null | grep -q "^Status: active"; then
|
||||
warn "ufw is installed but not active, the rules will apply once you run: ufw enable"
|
||||
fi
|
||||
|
||||
if [[ "$OPEN_TO_ALL" == "yes" ]]; then
|
||||
log "opening LiveKit ports to any address"
|
||||
else
|
||||
log "opening LiveKit ports to $SUBNET"
|
||||
fi
|
||||
|
||||
case "$BACKEND" in
|
||||
ufw) apply_ufw ;;
|
||||
firewalld) apply_firewalld ;;
|
||||
none) print_manual; exit 0 ;;
|
||||
esac
|
||||
|
||||
log "done via $BACKEND"
|
||||
echo
|
||||
echo " tcp 7880 LiveKit signalling, the websocket browsers connect to"
|
||||
echo " tcp 7881 LiveKit media over TCP, used where UDP is blocked"
|
||||
echo " udp 3478 TURN relay"
|
||||
echo " udp 50000-50100 LiveKit media, the normal path for audio and video"
|
||||
echo
|
||||
Reference in New Issue
Block a user