Setting up FreeNX

This document describes how I access the GUI tools on the Linux workstation in my office when I'm working from home. Obviously it's possible to just run all the tools using X11 over the network, but that isn't nearly as responsive as using the GPL version of NoMachine's NX which provides very good compression of the X protocol. Since the FreeNX tools have scant documentation (much of which seems to assume you already know how all the pieces fit together) I figured I'd contribute this how-to.

The full-blown NX environment offers one major feature I don't cover here, namely session management; it's not of much use to me personally, and appears to impose some requirements that I don't want to deal with, so I haven't spent a lot of time investigating setting up the FreeNX tools to support it.

My environment

The remote site consists of a firewall machine running Solaris 9 (which I'll call "remote-fw") and my workstation running Debian sarge ("remote-linux"). I can ssh to remote-fw from the outside world, but not directly to remote-linux.

At home, I have a Windows XP desktop machine which I'll call "local-winxp" and a firewall machine running Debian sarge ("local-fw").

Software Prerequisites

local-winxp: Cygwin, including the multi-window X server.

local-fw: OpenSSH client (standard on Debian)

remote-fw: OpenSSH client and server

remote-linux: OpenSSH server (standard on Debian)

Installing NX software

Since I have to bounce through two firewalls rather than connecting directly to the machine I want to use, and I don't want to add any new user accounts to the firewall machines, I can't use NoMachine's Windows client. It has some specific requirements such as requiring an "nx" user to be accessible on the remote machine.

On both local-fw and remote-linux, I used the FreeNX Debian packages from Kalyxo. Installing them is a snap: just add the following line to the /etc/apt/sources.list file:
deb experimental main
Then run "apt-get update" followed by "apt-get install freenx".

Brief Introduction to Some NX Tools

There are several tools in the FreeNX package, but I'm only using two of them: nxagent and nxproxy. Each of them handles a different aspect of NX's remote-access performance boosts.

nxproxy translates back and forth between X protocol requests and the more efficient NX protocol. You run two copies of this, a "server" copy which is run on or near the machine you'll be sitting in front of and a "client" copy which is run on or near the machine that you want to access remotely. If that naming scheme seems backwards, just keep in mind that it's the same as X's: the server provides display functions to the client applications.

The NX protocol obviously can't be sent over the same TCP connection as the X protocol, so nxproxy opens a secondary connection. In my setup this is on port 4008. The important thing to know about the secondary connection is that it goes in the opposite direction an X connection would go! In a straight remote X configuration, the client side establishes a connection to the server side. But in NX, it's the other way around: the server nxproxy connects to the client nxproxy. This will become important when I describe how I set up my ssh tunneling. (And it makes the terms "server" and "client" even more confusing than they are in the X environment, I might add.)

nxagent is the other piece of the puzzle. If nxproxy translates requests from one protocol to the other, nxagent eliminates the need for some of those requests to be sent in the first place. It does this by acting like a miniature X server from the applications' point of view; it can answer a lot of the typical "give me information about the X server" requests from applications, so that those requests don't have to be forwarded to the real X server.

nxagent runs on or near the remote machine (it wouldn't make much sense to run it on the local machine since the whole point is to reduce the amount of traffic between the local and remote sides!)

Here's a quick diagram of which pieces talk to which, leaving out the complexities of how they talk to each other in the presence of intermediate firewall hosts.

application --- nxagent --- nxproxy --- nxproxy --- X server
|___________ REMOTE HOST _________| |___ LOCAL HOST ___|

It is possible, by the way, to run either nxproxy or nxagent without the other one. But you get the most bang for your NX buck with both of them working together.

Putting the Pieces Together

With a firm picture of all the pieces in mind, the next thing to do is work out how they're going to talk to each other. Here's the sequence of commands I run, and what each one is for.

local-winxp: startx
Launches the Cygwin X server in multi-window mode, so that each X window shows up as a separate top-level window on the Windows XP desktop. This also launches an xterm.
local-winxp: xhost local-fw
I run this in the xterm. It allows local-fw to open X connections to local-winxp; without this, nxproxy couldn't forward requests from the remote side.
local-fw: ssh -L 4008:remote-linux:4008 remote-fw
Logs into the remote site's firewall and sets up the ssh tunnel that will carry all the NX traffic. Any connections to port 4008 on local-fw will be forwarded to port 4008 on remote-linux. This also gives me a shell on remote-fw.
remote-fw: ssh remote-linux
Hops from the remote firewall to the remote Linux box. Gives me a shell on remote-linux.
remote-linux: nxproxy -C :8 &
Starts the NX proxy, which as far as X applications are concerned, will look like the X display number 8 on remote-linux. This will wait for connections on port 4008; it will only wait for a short while before timing out and exiting, so immediately move to the next step:
local-fw: DISPLAY=local-winxp:0 nxproxy -S localhost:8 &
(If you're using csh, run "setenv DISPLAY local-winxp:0" then "nxproxy -S localhost:8 &".) This launches the server NX proxy and tells it to connect to localhost port 4008 which, since we've set up an ssh tunnel, will be forwarded to port 4008 on remote-linux. You should see some output from both of the nxagent processes at this point, as they do some initial handshaking.
(Optional) remote-linux: xterm -display :8
A sanity check to make sure nxproxy is able to forward X traffic properly. When I run this an xterm window appears on local-winxp's screen.
remote-linux: nxagent -display nx/:8 -geometry 1910x1400 :9 &
Opens an nxagent window on local-winxp, and starts accepting X connections from applications on remote-linux on X display number 9. Adjust the -geometry argument as you see fit; I'm running at 1920x1440 resolution on local-winxp, so the above argument creates a full-screen nxagent window. This window acts as a virtual desktop; all your X clients will run inside it. (Eventually there will be an nxagent that doesn't require this, but it doesn't exist yet.)
remote-linux: export DISPLAY=:9
(In csh, this is "setenv DISPLAY :9".) Tells subsequent X applications to connect to nxagent to display their windows.
(Optional) remote-linux: KDEHOME=$HOME/.kde-remote startkde
When I want a full KDE session, I do it like this. I use a non-default KDE_HOME because otherwise KDE will try to "restore" all my windows when it starts, which is no good because those windows are in fact still up and running on remote-linux's display!
(Optional) remote-linux: kwin &
When I don't want a full KDE session, just a window manager, I run kwin directly. Then I can run any applications I need.

Miscellaneous Notes

Eclipse: For some reason Eclipse 3.0 (the GTK version) and NX have a little trouble with one another. I've found that if I try to launch Eclipse from the KDE start menu, or from my ssh connection to remote-linux, I get the splash screen and nothing else. However, for some reason if I launch a terminal window within my nxagent window, then run Eclipse from there, it works fine.