Skip to main content

A menu script for Docker media containers, with a VPN routing check

If you run a group of media containers (the *arr apps, download clients, flaresolverr and so on), a small menu script saves typing for the common jobs. The most useful part is a check that download clients really leave through the VPN.

Pick the "media" group by name

media_containers() {
  docker ps --format '{{.Names}}' |
    grep -E 'sonarr|radarr|lidarr|prowlarr|bazarr|sabnzbd|qbittorrent|deluge|transmission|flaresolverr' | sort
}

A simple menu

PS3="Choose: "
select opt in "List containers" "Restart media group" "Check VPN routing" "Quit"; do
  case $REPLY in
    1) docker ps --format 'table {{.Names}}\t{{.Status}}' ;;
    2) read -rp "Restart $(media_containers | wc -l) containers? (y/N) " a
       [[ $a == [yY] ]] && media_containers | xargs -r docker restart ;;
    3) vpn_check ;;
    4) break ;;
  esac
done

Ask for confirmation before bulk actions. A "restart all" that also starts stopped containers will bring back anything you stopped on purpose.

Check that download clients use the VPN

Compare the public IP seen from inside each client with the host's own public IP. They should be different.

vpn_check() {
  local host_ip c ip
  host_ip=$(curl -fsS https://ifconfig.me)
  for c in qbittorrent deluge transmission sabnzbd; do
    docker inspect "$c" >/dev/null 2>&1 || continue
    ip=$(docker exec "$c" curl -fsS --max-time 10 https://ifconfig.me 2>/dev/null) || ip="(no answer)"
    if [[ $ip == "$host_ip" ]]; then echo "LEAK  $c: $ip (same as host)"
    else echo "OK    $c: $ip"; fi
  done
}
  • Many images don't include curl. Use wget -qO-, or run the check from the VPN container (gluetun) that the clients share.
  • Inside [[ ... ]], put spaces before ]]. Writing "$ip"] is a syntax error that only shows up when that branch runs.

Small bash pitfalls in scripts like this

  • Send status messages to stderr (>&2) in functions whose stdout you capture with $(...).
  • Counters set inside cmd | while ... are lost, because the loop runs in a subshell. Use while ...; done < <(cmd) instead.
  • local x=$(cmd); echo $? always reports 0. Declare the variable first: local x; x=$(cmd).