This is just how I setup the current NX main node. As everything when dealing with system administration and network setup, there are plenty of other ways to do it, and this describes only my precise setup. However, if you think of ideas to improve functionality or ease of use, please let me know, I'll be happy to place your contribution here.

Initial setup

Straight to the real thing... I assume that you want to setup a VPN server, allowing PPP/SSH connections. The connections will be setup as described in the NX hookup instructions. Basically, every client will have to supply to you (the server) a SSH RSA public key, that you will add to a file, along with the VPN IP address of the client. The big advantage of this setup is that you only need to add a line per client in a file, and you're done.

  1. Create a user, named for instance "vpn". If you plan to run many separate VPN with various "classes" of users, you can create, say, "vpnfoo" and "vpnbar", or "foo" and "bar" in a "vpn" group, as you like.
  2. Grab the vpnwrapper script, and put it somewhere - I suggest /usr/local/bin, or ~vpn. It should be owned by root, and in mode 755 (the vpn user should not be able to modify it).
  3. Change the shell for the vpn user to the vpnwrapper. You can do that with chsh, or edit your passwd file (vipw is your friend).
  4. While we're modifying passwd entries, change the password field of the vpn user to a star ("*"), so this user won't be able to login thru password-based authentication. That leaves us only with SSH key-based authentication. If your system provides rhosts-based access, check that it can't work for vpn user.
  5. You should have a SSH daemon operating on your server. If not, install it now. RSA key authentication should be enabled (it's the default, so you should not have to mess with a lot of things...)
  6. Create the directory : ~vpn/.ssh ; and put an empty file named authorized_keys in it.
  7. You should now install sudo. You can use something else, but then, the details are up to you. I used a standard sudo, and put the following line in sudoers file (you generally edit sudoers with the visudo command) :
    vpn     ALL=(ALL)       NOPASSWD:       /usr/sbin/pppd
    The goal of this is to allow the vpn user to start the pppd process as root, thus allowing it to specify any parameter it likes (if you use a pppd SUID, you can't specify arbitrary parameters and need extra per-client configuration).
  8. You're done.
  9. Well, I lied. You should right now choose an IP addressing plan ; for instance, I decided that the IP address of the endpoint would be 192.168.0.179 (why? because I use a pseudo-anycast setup, where services are located on the 192.168.0.0/24 subnet, and 179 is the port used by BGP).
  10. You may want to run some kind of routing daemon. I recommend Zebra or MRTD, personnally I use Zebra. Configuring Zebra is out of the scope of this document, but if there is sufficient demand, I'll provide explanations about how to setup Zebra on a VPN server node. In the meanwhile, you can consult how to setup Zebra on the client side (here), as it is not so different.

Adding clients

Normally, clients should send you a SSH RSA key (looks like : "1024 33 2103948298LotsOfNumbers20349839"), a symbolic name (that you will use to discriminate connections), and the IP address they want. If you approve their choice, just add a line in ~vpn/.ssh/authorized_keys, like the following one :
command="symbolicname lo.ca.l.ip:re.mo.te.ip extraoptions" 1024 35 234983TheirPublicKey230498"
You can skip the extraoptions part ; I never use it but you could put "debug" here : these options will be passed to the pppd program.

What does vpnwrapper do ?

The first part just checks that it's called as a user login shell :
#!/bin/sh
function syntax () {
        echo 'Syntax: '"$0"' -c   [extraparams]'
        exit 1
}
[ "$1" = "-c" ] || syntax
Then, it extracts various parameters (as they will be given by the command="symbolicname localip:remoteip extraoptions" stanza in authorized_keys) :
PARAMS=($2)
NAME="${PARAMS[0]}"
IP="${PARAMS[1]}"
PARAMS[0]=
PARAMS[1]=
Next, it checks the format of local and remote IP address. It's not a bulletproof check, but it will catch some typos (but not 123.456.789.0 addresses) :
DIGIT='[0-9]'
BYTE=$DIGIT?$DIGIT?$DIGIT
IPA=$BYTE\.$BYTE\.$BYTE\.$BYTE
echo "$IP" | grep -Eq "$IPA:$IPA" || syntax
We do a bit of logging. No syslog or whatever, but this logs the date, the hostname (for log consolidation), the PID (to track pppd messages in syslog), the name of the client, the extra parameters. Note that we could also use a more elaborated setup where we would log the deconnection of clients, to calculate connection times. But I did not need this feature so I did not implement it.
echo "$(date) | $HOSTNAME | $$ | $NAME | $PARAMS" >> ~/vpn.log
Finally, we start pppd. Notice the linkname option, which allows you to track pppd processes in /var/run by the name of the client instead of requiring you a lookup to the log or whatever.
exec sudo /usr/sbin/pppd noauth linkname "$NAME" "$IP" ${PARAMS[@]}
Please note that there is no locking mechanism or whatever, so if a client connects twice using the same key, that won't kill the first connection whatsoever. But if a connection crashes, LCP wiil terminate it after rougly 30 seconds with pppd default parameters.

How do I setup DNS?

This is out of the scope of this document. If there is sufficient demand, I'll explain how to setup a "rogue" TLD, using BIND and stubs zones.

Troubleshooting

Just create a SSH RSA key, add it to the authorized_keys file (with some command="whatever 192.168.0.179:192.168.0.180" thekeyitself), and try to login using the key (ssh -i fileholdingthekey -t vpn@localhost). You should get the beginning of the LCP negociations, which usually goes
}#!}!}!} }4}"}&} } } } }%}&}/H}=}'}"}(}"~~~~~~~~
or the like. If that does not work, try running a debug server : "sshd -dp 222", and connect to it using "-p222" to the client SSH command line. If that still does not help, feel free to contact me. I don't grant a quick response, but I'll be happy to improve this document.
First release of this document ; orthographic corrections and comments are welcome !
skaya@enix.org