#!/usr/bin/env bash # Run on the travel laptop: closes any Chromium running for you on the remote # machine (Chromium allows one process per profile, so a running instance # would swallow the new window), then launches it there with its window # drawn here. Its audio is forwarded here too (needs pactl on both ends). # # Usage: remote-chromium.sh [--x11] [host] # --x11 classic X11 forwarding instead of waypipe # host ssh host to run Chromium on (default: teemu-thinkpad-ubuntu) set -euo pipefail MODE="waypipe" HOST="teemu-thinkpad-ubuntu" for arg in "$@"; do case "$arg" in --x11) MODE="x11" ;; -*) echo "Unknown option: $arg"; exit 1 ;; *) HOST="$arg" ;; esac done if [ "$MODE" = "waypipe" ] && ! command -v waypipe >/dev/null 2>&1; then echo "waypipe not installed here - run: sudo apt install waypipe (needed on both machines)" exit 1 fi ssh "$HOST" bash -s <<'EOF' # snap build (Ubuntu) and the Debian package - matches the browser binary only, # not shells/editors that merely mention "chromium" PAT='chromium-browser/chrome|/usr/lib/chromium/chromium' if pgrep -u "$USER" -f "$PAT" >/dev/null; then echo "Chromium is running on $(hostname) - closing it gracefully..." pkill -TERM -u "$USER" -f "$PAT" for _ in $(seq 1 10); do pgrep -u "$USER" -f "$PAT" >/dev/null || break sleep 1 done if pgrep -u "$USER" -f "$PAT" >/dev/null; then echo "Still running after 10s - force killing." pkill -KILL -u "$USER" -f "$PAT" fi fi EOF # Audio: Chromium plays through the remote's audio system, so give that system # a virtual speaker that forwards over the tailnet to this machine, and point # only this Chromium at it (PULSE_SINK). The snap sandbox rules out simply # forwarding the audio socket over ssh. Both ends need pactl (pulseaudio-utils). AUDIO_ENV=() LOCAL_MOD="" REMOTE_MOD="" SINK="chromium_to_$(hostname | tr -c 'a-zA-Z0-9\n' '_')" if command -v pactl >/dev/null 2>&1 && ssh "$HOST" command -v pactl >/dev/null 2>&1; then LOCAL_IP=$(tailscale ip -4) REMOTE_IP=$(tailscale ip -4 "$HOST") # unload leftovers from a run that didn't clean up, so reruns don't fail pactl list short modules | awk -v ip="$LOCAL_IP" '/module-native-protocol-tcp/ && index($0, ip) {print $1}' | xargs -r -n1 pactl unload-module ssh "$HOST" "pactl list short modules | awk '/module-tunnel-sink/ && /sink_name=$SINK/ {print \$1}' | xargs -r -n1 pactl unload-module" LOCAL_MOD=$(pactl load-module module-native-protocol-tcp port=4713 listen="$LOCAL_IP" auth-ip-acl="$REMOTE_IP") REMOTE_MOD=$(ssh "$HOST" pactl load-module module-tunnel-sink server="tcp:$LOCAL_IP:4713" sink_name="$SINK") AUDIO_ENV=(env "PULSE_SINK=$SINK") else echo "pactl missing here or on $HOST - no audio forwarding (sudo apt install pulseaudio-utils on both)" fi cleanup() { [ -n "$REMOTE_MOD" ] && ssh "$HOST" pactl unload-module "$REMOTE_MOD" 2>/dev/null [ -n "$LOCAL_MOD" ] && pactl unload-module "$LOCAL_MOD" 2>/dev/null return 0 } trap cleanup EXIT case "$MODE" in waypipe) waypipe ssh "$HOST" "${AUDIO_ENV[@]}" chromium --ozone-platform=wayland ;; x11) ssh -X "$HOST" "${AUDIO_ENV[@]}" chromium ;; esac