Tunneling iTunes through SSH

If you want to listen to your music library on the go, you can tunnel iTunes through SSH in a few easy steps.

First of all, you have to enable sharing in iTunes: iTunes > Preferences > Sharing > Share my library on my local network.

This will announce your library on your local network using multicast DNS, provided by Apple’s implementation of zeroconf: Bonjour. The library can then be accessed on port 3689 of the computer mDNS announced.

Hence, to access your local library on a distant network, we will implement two things: ssh tunneling of port 3689 for the data to be transmitted, and mDNS announcement of the library on the new network so iTunes is aware of where to get it.

We will assume:
– local = where me & my laptop are
– remote = where iTunes is (=server).

Tunneling port 3689

We will tunnel port 3689 of the remote computer to a port of your choice on your local computer:

ssh -N florent@myServer -L 3690:localhost:3689 -f

-L is the standard syntax for SSH tunneling. man ssh tells us the three arguments stands for port:host:hostport; as in “send data received at my own port to the hostport of said host“. Here for example, it means: tunnel all data received on my port 3690 to this SSH connection’s localhost (myServer) on its port 3689.

Feel free to change 3690 to the port of your choice, replace florent@myServer by your own login/host combination, and add a -p if you use a non-standard port for SSH (which is a Good Thing(tm)!).

The -f argument means the SSH tunnel will stay in the background. Finally, -N tells SSH not to execute a command on the remote side (i.e. launch a terminal on the server), meaning we will only use this connection to forward data.

Announcing the library

We will use this command to declare the new library:

dns-sd -P iTunesServer _daap._tcp local 3690 localhost.local 127.0.0.1 &

This command sets up a DNS proxy (-P) called iTunesServer, retransmitting DAAP announcements, on the local domain, on port 3690 of host localhost.local (at address 127.0.0.1).

You should get the following output from dns-sd:

 Registering Service iTunesServer._daap._tcp.local host localhost.local port 3690
 0:24:30.140  Got a reply for service iTunesServer._daap._tcp.local.: Name now registered and active
 0:24:30.140  Got a reply for record localhost.local: Name now registered and active

Note that this will only advertise the library on your own computer. If you want other computers on your network to see the library you’re tunneling to, use the following command, where ComputerName is the Bonjour name of your computer (set in System Preferences > Sharing > Computer Name):

dns-sd -P iTunesServer _daap._tcp . 3690 ComputerName.local ComputerName.local &

Annd your library will show up in iTunes!

iTunes shows the remote library
Victory!

Playback can be a bit choppy if your server’s upload or laptop’s download is low, but it usually should be okay – MP3 and AAC yields great results around 192 to 320 kbps, equivalent to an average 25 to 40 kB/s transfer rate.

Note that this method also allows you to use a password (set up in iTunes) to protect your shared libraries.

18 thoughts on “Tunneling iTunes through SSH”

    1. Hello!

      My whole blog is under the Creative Commons Attribution License, which basically means you can quote my posts anywhere you want. Just make sure to include a link back to the original post on my blog.

      As for the Twitter account… I don’t have one yet, but it’s on my mind. ;)

      Have a good day!

    1. There are a few ways to keep the tunneling active when you close Terminal. Basically, what you need is a way to prevent the processes from receiving the SIGHUP message bash sends when it closes. This can be achieved by sending the processes to the background and disowning them, but the easiest way to do this is to append nohup before the commands, i.e.:
      nohup ssh -N florent@myServer -L 3690:localhost:3689 -f
      nohup dns-sd -P iTunesServer _daap._tcp local 3690 localhost.local 127.0.0.1 &

      This allows you to quit Terminal.app without affecting either SSH or dns-sd.

      Making it permanent is trickier…
      I think you could add the dns-sd line to your .profile and use SSH Tunnel Manager to deal with the SSH. We cannot put the ssh into a script of any kind, because it might close the connection in case of inactivity or if your Mac goes to sleep.

      1. A couple of things that can make it either permanent or semi-permanent:

        The “screen” command opens up a virtual terminal session that you can disconnect from (and reconnect later from another window) but continues (see man page for details).

        Also, the “autossh” command is very very useful. It is not standard on OSX, but can be installed through MacPorts or Fink very easily. From there, you can create a LaunchDaemon (install in /Library/LaunchDaemons) that will start up your ssh process on boot up and keep it running (modify the IPs and ports to your scenario). I am going to investigate setting up a daemon for mDNS next:

        <?xml version=”1.0″ encoding=”UTF-8″?>
        <!DOCTYPE plist PUBLIC “-//Apple//DTD PLIST 1.0//EN” “http://www.apple.com/DTDs/PropertyList-1.0.dtd”>
        <plist version=”1.0″>
        <dict>
        <key>KeepAlive</key>
        <true/>
        <key>Label</key>
        <string>com.myhost.autoossh</string>
        <key>ProgramArguments</key>
        <array>
        <string>/opt/local/bin/autossh</string>
        <string>-M</string>
        <string>33333</string>
        <string>-q</string>
        <string>-2</string>
        <string>-A</string>
        <string>-C</string>
        <string>-N</string>
        <string>-l</string>
        <string>sgarrett</string>
        <string>-L</string>
        <string>3128:127.0.0.1:3128</string>
        <string>-L</string>
        <string>993:127.0.0.1:993</string>
        <string>-L</string>
        <string>25:127.0.0.1:25</string>
        <string>-R</string>
        <string>2221:10.1.7.22:22</string>
        <string>-R</string>
        <string>8080:10.1.7.22:80</string>
        <string>-R</string>
        <string>2222:10.1.7.14:22</string>
        <string>-R</string>
        <string>2210:10.2.51.200:22</string>
        <string>-R</string>
        <string>2211:10.2.51.201:22</string>
        <string>-R</string>
        <string>5959:10.2.51.201:5900</string>
        <string>-R</string>
        <string>2212:10.1.13.100:22</string>
        <string>-R</string>
        <string>8086:10.1.13.100:80</string>
        <string>-L</string>
        <string>3689:localhost:3689</string>
        <string>-T</string>
        <string>-o</string>
        <string>PasswordAuthentication=no</string>
        <string>server.myhost.com</string>
        </array>
        <key>RunAtLoad</key>
        <true/>
        <key>UserName</key>
        <string>root</string>
        </dict>
        </plist>

        Edit Aug. 26, 2011 by admin: recreated the XML that WordPress ate.

        1. Looks like it ate most of the XML text. If you let me know how to post code, I’ll re-comment with the complete XML.

  1. I’ve had better luck with a dns-sd line which reads:

    dns-sd -P “iTunesLib” _daap._tcp. local 3689 local 127.0.0.1 “some text” &

    Differences in trailing dots and “local” vs. “localhost.local” seem to be pervade other websites offering this advice. I don’t know what’s right; I only know what works. :)

    1. Interesting… After some tests; indeed using either local or localhost.local doesn’t change anything, and dns-sd doesn’t mind the trailing dot after tcp. Adding any other dot will result in an error though.

      The biggest change seems to be the TXT record you’re adding with the “some text”, but it doesn’t show at all in the announcement:
      Air:~ florent$ dns-sd -B _daap._tcp local
      Browsing for _daap._tcp.local
      Timestamp A/R Flags if Domain Service Type Instance Name
      21:33:32.486 Add 2 4 local. _daap._tcp. Florent’s Library
      21:33:39.593 Add 2 4 local. _daap._tcp. iTunesServer
      21:33:45.546 Rmv 0 4 local. _daap._tcp. iTunesServer
      21:34:30.636 Add 2 4 local. _daap._tcp. iTunesLib
      21:34:42.291 Rmv 0 4 local. _daap._tcp. iTunesLib

      Oh well… As long as it works! Thanks for your comment. :)

      1. Hello!
        I tried both approaches, but nothing seems to work.

        I’ve established diverse SSH tunnels and have a connection to the machine where the iTunes server is running (ssh -R from iTunes server’s machine).
        I’ve tunneled both services to localhost (SSH and DAAP), but still iTunes won’t show the library.

        Are there any debugging techniques one can use? Besides
        ‘dns-sd -B _daap._tcp local’, which did list the service and other iTunes Libraries from different people on the same net – these libraries where recognized by iTunes btw.

  2. Hello,
    I’m trying to do this kind of tunneling with my iphone, but dns-sd is not a recognized command in iOS.
    Can you help me to find any possibility to do that ??

    Sorry for my english, i’m French !

    1. Hi,
      Very good question… Cydia doesn’t seem to have any dns-sd package either, even though this page seems to say that there is a dns-sd command somewhere (I just tried, and it won’t work on mine).
      This Stack Overflow thread suggests that it’s possible to advertise the dns-sd service from another computer on the same network. For example if you have a Mac connected on the same WiFi as your iPhone, you can run the command on the Mac (you’ll have to tweak it a bit so it doesn’t just announce it to the machine itself/on localhost) and your iPhone will see itself advertised.
      That said, I don’t think iTunes for iPhone can even connect to remote iTunes libraries.
      (I’m French too by the way, so if you want to continue this conversation in French, drop me a line at florent@uponmyshoulder.com instead ;) )

  3. I know this is bumping an old thread, but I had a question. I got my home server iTunes library to show up perfectly on my work computer, but one thing is bothering me. It doesn’t seem to show the play counts like it would if I connected on a local network, and likewise it doesn’t update play counts when after a song finishes like it normally would on the local network. Why would these features be lost during the tunneling process?

  4. My terminal command line is displays:
    “dynamic-oit-vapornet-f-3306:~ username$”

    This persists through restarting the computer which surprised me.

    Does this indicate the proxy is still open? even though I am not 100% sure what this means I would like to be able to get back where I started “computer name:~ username$”

  5. The last option does not seem to work:

    dns-sd -P iTunesServer _daap._tcp . 3690 ComputerName.local ComputerName.local &

    I have the following error:

    computer123:~ johnny$ dns-sd -P iTunesServer _daap local. 3690 computer123.local computer123.local &
    [1] 723
    computer123:~ johnny$ Registering Service iTunesServer._daap._tcp.local. host computer123.local port 3690
    DATE: —Thu 11 Apr 2013—
    8:50:55.798 …STARTING…
    8:50:56.343 Got a reply for record computer123.local: Name in use, please choose another

    It will not allow me to use my own bonjour name here as my system has already used it.

  6. Hi,

    Do you have any thoughts as to how I might accomplish this with a Windows client? I’ve set up the DAAP server successfully, currently it’s hosted with ports open to test so I don’t need a ssh tunnel, and I’ve tested it with another DAAP client (music pump for android) and it works fine there. But windows doesn’t seem to have the dns-sd command and I’m not sure how else to make the service visible to my iTunes. I tried using ‘rendez vous proxy’ but it doesn’t seem to work. Any tips?

    Thanks!

Leave a Reply to bthomas Cancel reply

Your email address will not be published. Required fields are marked *