Copy livelink recordings to NAS

Copying LiveLink recordings to a NAS share

This was beyond my skillset to figure out on my own so I’m documenting it here for my own future reference and in case it helps anyone else. I needed help from Claude to get this working, so thanks to them for the brain-power here.

I’m running a LiveKit instance on a Linux host (WSL2 on Windows, but that doesn’t really matter) and want to copy the recordings to a NAS share as soon as they finish writing, so I don’t have to worry about disk space on the host.

Below is the response that got this all working for me. I’ve added some extra context and instructions for my own future reference, but the core of it is Claude’s work.

TODO: clean this up

Let’s do this in three parts: mount the NAS via CIFS, then set up an event-driven watcher (using inotifywait rather than polling/cron, so files get copied the moment they finish writing rather than on a schedule).

I’ll need a couple of specifics from you to fill in the placeholders below: the NAS’s IP/hostname and share name, and where the CIFS credentials file lives on that other Linux host (so you can pull it over).

1. Mount the NAS share via CIFS

Install what’s needed:

sudo apt update && sudo apt install -y cifs-utils rsync inotify-tools

Pull the credentials file from your other host (adjust the path to wherever it actually lives there — commonly /etc/samba/cifs_credentials):

scp youruser@other-host:/etc/cifs_credentials ~/nas-credentials
sudo mv ~/nas-credentials /etc/samba/cifs_credentials
sudo chmod 600 /etc/samba/cifs_credentials
sudo chown root:root /etc/samba/cifs_credentials

It should just contain:

username=your-nas-user
password=your-nas-password

Create the mount point and add an fstab entry:

sudo mkdir -p /mnt/share/media
# /etc/fstab
//<NAS_IP_OR_HOSTNAME>/<SHARE_NAME> /mnt/share/media cifs credentials=/etc/cifs_credentials,iocharset=utf8,uid=1000,gid=1000,vers=3.0,noperm 0 0

Check your actual UID first (id -u) — swap in that number if it’s not 1000.

Mount it and confirm:

sudo mount -a
df -h /mnt/share/media

Heads up on WSL persistence: /etc/fstab only auto-mounts on boot if your WSL distro has systemd enabled. Check with:

systemctl is-system-running

If that errors instead of returning a status, systemd isn’t running, and you’ll need sudo mount -a after every WSL restart (or add it to a startup script — happy to help wire that up if that’s the case).

2. The watcher script

mkdir -p ~/docker/livekit/scripts
cat << 'EOF' > ~/docker/livekit/scripts/sync-recordings.sh
#!/bin/bash
WATCH_DIR=~/docker/livekit/recordings
DEST_DIR=/mnt/share/media/livekit-recordings

mkdir -p "$DEST_DIR"

inotifywait -m -e close_write --format '%f' "$WATCH_DIR" | while read -r filename; do
  if [[ "$filename" == *.mp4 ]]; then
    echo "$(date): copying $filename"
    rsync -av "$WATCH_DIR/$filename" "$DEST_DIR/"
  fi
done
EOF
chmod +x ~/docker/livekit/scripts/sync-recordings.sh

Using close_write rather than create matters here — it fires once Egress has actually finished writing the file, not the instant it appears, so you never copy a half-written recording. This copies (keeps the local file too); if you’d rather move-and-free-local-space, add --remove-source-files to the rsync line.

3. Make it persistent

If systemd is enabled (from step 1’s check):

sudo tee /etc/systemd/system/livekit-recording-sync.service << 'EOF'
[Unit]
Description=Sync LiveKit recordings to NAS
After=network-online.target

[Service]
ExecStart=/home/acedanger/docker/livekit/scripts/sync-recordings.sh
Restart=always
User=acedanger

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now livekit-recording-sync
sudo systemctl status livekit-recording-sync

If systemd isn’t available, run it in the background instead:

nohup ~/docker/livekit/scripts/sync-recordings.sh > ~/docker/livekit/scripts/sync.log 2>&1 &
disown

(This won’t survive a WSL restart on its own — worth pairing with a Windows Task Scheduler entry that runs wsl -e ~/docker/livekit/scripts/sync-recordings.sh at logon if you go this route.)

Test it

Trigger another recording from Discourse, then watch the log:

# systemd:
journalctl -u livekit-recording-sync -f
# or nohup:
tail -f ~/docker/livekit/scripts/sync.log

You should see the “copying …” line appear right as the recording finishes, and the file show up under /mnt/share/media/livekit-recordings.