Moonlight on the Steam Link

I've had issues with Steam in-home streaming on my home network, even when everything is wired over gigabit ethernet or on 802.11ac wifi. It works poorly (fine for a minute sometimes before stutter, lag, disconnection) when streaming between PCs and from PC to Link, so I'm not sure what the hell is going on exactly but I do know that it's very annoying.

However, Moonlight has been working like a champ for me for months. I play Destiny 2 remotely from a Linux desktop most nights, for hours, using Moonlight; no random disconnections, stutter is minimal to nonexistent, and the latency feels impossibly good.

I wondered if I could get some more use out of my Steam Link by running Moonlight on it. Long story short, it took some help from cgutman, the Moonlight dev, but Moonlight on the Steam Link now runs and streams really well on Gigabit, and kind of sort of okay on 802.11ac wifi? It seems like it varies in quality for me on wifi. Sometimes it works as well as gigabit, and sometimes it stutters more.

Anyway. The short version:

  • grab moonlight.tgz and put it on a FAT32-formatted USB flash drive, under folders /steamlink/apps/
  • optional: if you haven't yet, you can touch steamlink/config/system/enable_ssh.txt to enable sshd on your Steam Link, which makes it much easier to update Moonlight and any other Steam Link apps in the future.
  • eject and remove the flash drive from your computer
  • pull the power cable from your Steam Link
  • plug the flash drive into your Steam Link
  • power the Link back on
  • wait for it to install Moonlight and reboot

You should be able to navigate around most of the UI, launch streams, etc, with a controller, but it's not perfect yet so you may want to plug in a mouse. Also, there's a checkbox in the settings to quit the Moonlight app after a stream ends - you may want to turn that on, as otherwise I'm not sure how to get back to the Steam Link home screen without sshing to the Link and running pkill moonlight.

The long version, which you should probably do if you have a Linux machine available and you're the kind of person who's (rightfully, justifiably) paranoid about putting a random tarball from reddit on your Steam Link:

  • git clone git://github.com/ValveSoftware/steamlink-sdk
  • cd steamlink-sdk
  • source setenv.sh
  • rm rootfs/usr/lib/pkgconfig/libpulse*pc (Valve includes the libpulse headers, but not the library, so linking will fail and you'll have a bad time if you don't do this)
  • cd ..
  • git clone git://github.com/moonlight-streaming/moonlight-qt
  • cd moonlight-qt
  • qmake
  • make release
  • mkdir -p steamlink/moonlight/bin
  • cp app/moonlight steamlink/moonlight/bin
  • cp something/icon.png steamlink/moonlight/icon.png
  • cd steamlink
cat > moonlight/toc.txt << EOF
name=Moonlight
icon=icon.png
run=moonlight.sh
EOF
cat > moonlight/moonlight.sh << EOF
#!/bin/sh
exec ./bin/moonlight
EOF
  • chmod a+x moonlight/moonlight.sh
  • tar czf moonlight.tgz moonlight

Now you can use your own moonlight.tgz and follow the rest of the instructions above.


setting up plex in a linux container

In case anybody out there is running a recent Debian (jessie or later), and has ever wondered how much of a hassle it would be to install Plex into a container to segregate it from the rest of your system: It turns out, it's not much of a hassle at all!

You can do something like I did here:

# as root
cd /var/lib/container/
mkdir plex
debootstrap --arch amd64 vivid plex http://archive.ubuntu.com/ubuntu/

# Set the root password for later
systemd-nspawn --directory plex

# Now you should be at a root prompt inside the container!
passwd
# and you can enter a new password.

Now you hold Ctrl and hit ] three times, and it'll kill the container host process.

# assuming you already have a bridge set up for your NIC and it's named lxcbr0:
systemd-nspawn --network-bridge=lxcbr0 --boot --directory plex

That'll get you a fresh minimal Ubuntu Vivid installation, perfect for installing Plex. You can safely ignore the systemd-journald errors on the first boot; updating to the latest packages will fix the errors.

You'll need to bring up the network inside the VM, so log in as root using the password you just set, and run:

dhclient host0

Then add the vivid-updates repo, and upgrade to the latest packages to fix the journald errors from vivid's starting state:

echo 'deb http://us.archive.ubuntu.com/ubuntu/ vivid-updates main' > /etc/apt/sources.list.d/vivid-updates.list
apt-get update && apt-get dist-upgrade

Now you're up to date. Let's add the PlexPass repo and install Plex:

echo 'deb http://shell.ninthgate.se/packages/debian plexpass main' > /etc/apt/sources.list.d/plexmediaserver.list
apt-get update && apt-get install plexmediaserver

(If you don't have a Plex Pass, you can use the regular non-PlexPass repo, just substitute wheezy for plexpass in the above echo command. The wheezy name appears to be hilariously inaccurate, because it doesn't seem to even work on jessie anymore, but I digress.)

Now, hit Ctrl+]]] again, and stop the Plex server in the host, assuming it's on the same machine. You'll want to copy the Application Support folder from your existing Plex server (using these packages, the default location is in /var/lib/plexmediaserver/Library, but your OS may have it in a different place). Just make sure that you copy the Application Support folder into the /var/lib/container/plex/var/lib/plexmediaserver/Library on the host.

Look up the ID of the plex user inside the container. Mine didn't match between host and guest, so I ran:

grep plex plex/etc/passwd | sed -re 's;^plex:x:([0-9]+):([0-9]+):.*$;PLEXUID=\1 PLEXGID=\2;g'
chmod -R {PLEXUID}:{PLEXGID} plex/var/lib/plexmediaserver

Now, you'll want to add some more arguments to your systemd-nspawn so that it can access your media library. My media is on ZFS in /tank/tv and /tank/movies so I used this command:

# assuming you're back in /var/lib/container on the host:
systemd-nspawn --network-bridge=lxcbr0 -bD plex --bind-ro=/tank/tv --bind-ro=/tank/movies

# once the container boots, log in as root again, and set up networking
# I did:
echo "auto host0\niface host0 inet dhcp" >> /etc/network/interfaces

# and then:
systemctl restart networking

Remember to add --bind-ro (or --bind, if you want Plex to be able to write to these files) for each separate filesystem you want visible inside the container.

And now you should have a working Plex running inside a container, on a separate IP address on your local network.

TL;DR Setting up Plex in a container doesn't take long at all, and separates Plex from the resources of the rest of your machine with almost no overhead.

PS: If you haven't already got a bridge for your main interface on the host machine, you can set one up like this, but be careful if you're doing it over SSH!

# as root on the host:
brctl create lxcbr0

# change eth0 to eth1 or em0 or whatever your NIC is called.
brctl addif lxcbr0 eth0 && dhclient lxcbr0

If you have a static IP for your NIC, then you should definitely use ifconfig or ip addr add to configure lxcbr0 in the second part above using the same configuration you previously had on your NIC. You'll want to update your host's /etc/network/interfaces if you're on Debian or Ubuntu on the host system. (Basically just s/eth0/lxcbr0/g on the whole file, and add a new line under the iface lxcbr0 inet <> line that looks like:

        bridge_ports eth0 # or whatever your NIC is

MAKE SURE THAT YOU USE THE brctl addif && syntax IF YOU'RE DOING THIS REMOTELY, OTHERWISE YOUR MACHINE WILL FALL OFF THE NETWORK LIKE A DRUNK.


new design!

Still kicking the tires, and it's taken me a few hours of fiddling, but I've configured punch to spit out HTML for my blog. (Not sure if punch will be sticking around; I mostly wanted to see if I could get it to work, but magneto or pelican may end up being a better fit.)

The design is also shiny and new. I stole some ideas from John August's site, and I built this layout on top of Skeleton—I've gotten tired of seeing bootstrap everywhere, so I figured I'd try something new. The layout is fully responsive now; it should scale properly to phones, tablets, and even giant 30" displays, all without sacrificing readability.

Fonts for this design are Orbitron for the headers and NoticiaText for the body text.