This page is about setting up a VPN connection to connect a LAN or single client to a PPTP server running Microsoft’s PPTP software. Setting up to connect to a non-MS server generally requires a different configuration.

This is a work in progress – when I’ve succeeded in getting the connection going, I’ll remove this notice and announce the page.

Dramatis personae

The Scene: A (home) network on ADSL behind a NATing firewall, trying to connect to a VPN, giving the home network full access to the “main” LAN over the VPN link.

  • The Home Network
  • The Firewall’s Internal IP Address
  • The Firewall’s External IP Address
  • A Machine in the Home Network
  • The External IP Address of the VPN Server
  • The Internal IP Address of the VPN Server
  • The VPN Network
  • A Machine in the VPN Network

Kernel set-up

Unfortunately, the necessary PPTP support (specifically, the support for MPPE) isn’t in the kernel yet. This means patching and building a new kernel. The relevant patches are contained in the latest PPP package. Download the latest source tarball and unpack it.

Patching the kernel

In the ppp-2.4.2_cvs_20040102/linux/mppe directory, you will find a whole load of patch files, a few source files (.c and .h) and a shell script called Run the shell script, and tell it where your kernel source tree is:

$ ./ /usr/local/src/linux-2.4.24

Note that it attempts to get the version number of the kernel from the name of the source tree, so if like me you don’t use this convention, you will need to apply the relevant patches and files manually:

  • 2.2 kernels need
    • linux-2.2.20-include.patch
    • linux-2.2.20-make.patch
    • linux-2.2.20-pad.patch
  • 2.4 kernels up to 2.4.18 need
    • linux-2.4.18-include.patch
    • linux-2.4.18-make.patch
    • linux-2.4.18-pad.patch
  • 2.4 kernels from 2.4.19 and up need
    • linux-2.4.18-include.patch
    • linux-2.4.18-make.patch
    • linux-2.4.19-pad.patch

All kernels should have the following files copied into the drivers/net directory:

  • sha1.c
  • sha1.h
  • arcfour.c
  • arcfour.h
  • ppp_mppe_compress.c

Configuring and building the kernel

You will need configured in your kernel the following options:

  • CONFIG_PPP=m (Network Device Support -> PPP (point-to-point protocol) support)

  • CONFIG_PPP_ASYNC=m ( -> PPP support for async serial ports)

  • CONFIG_PPP_MPPE=m ( -> PPP MPPE compression (encryption))

They apparently have to be modular (I haven’t tested with them built-in).

Build your newly configured kernel and modules and install.

Kernel set-up (Alternative)

This section is debian specific as that is what I was using as a base. I’ll assume that you are familiar with how to configure, make and install a kernel.

First, install the kernel patch:

~# apt-get install kernel-patch-mppe

Next, edit your .config file (in your kernel source directory) to include support for PPP and MPPE. Find the CONFIG_PPP option and set it to module.


Beneath this line, add the following line:


Compiling the kernel

First, allow the kernel to be patched:

~# export PATCH_THE_KERNEL=yes

Then cd to your kernel source directory and compile the kernel

/usr/src/linux/# make-kpkg clean /usr/src/linux/# make-kpkg --added-patches mppe --append-to-version -mppe --revision=mppetest01 binary-arch

Then install the new kernel

/usr/src/linux/# cd .. /usr/src/# dpkg -i kernel-image-2.6.6-mppe_mppetest01_i386.deb kernel-headers-mppe_mppetest01_i386.deb 

Reboot to use the new kernel. You can test to see if the patch has worked by typing:

~# modprobe ppp-compress-18 ~#

If this works correctly, you will probably not see any output. If you look at the syslog, you will see:

ppp_mppe: module license 'DSB without advertisement clause' taints kernel. PPP MPPE Compression module registered

User-space Software

You will need a copy of the ppp daemon and tools. These come in the source package you downloaded above. To build the package, you will need the development package of libpcap installed. On Debian, this is the libpcap-dev package.

Configure, build and install:

$ ./configure $ make $ make install

You will also need to install the pptp client application. Again, on Debian, this is in the package “pptp-linux”.

(Notes here about ppp dependencies and equivs package)

User space tools (Debian specific)

To install the client, use:

~# apt-get install pptp-linux


Create a /etc/ppp/options.pptp file and add the following to it:

lock noauth nobsdcomp nodeflate

Add the following to /etc/ppp/chap-secrets (the file may not already exist in which case, create it)

<NT_domain><username> PPTP <password> * PPTP <NT_domain><username> <password> *

Replace <NT_domain> with your NT domain, <username> with your NT username and <password> with your NT password. If you do not need to use a domain to log on, omit <NT_domain> from both lines in the file.

Choose a name for your vpn tunnel and create a file /etc/ppp/peers/<tunnel>. Add the following lines to that file.

pty "pptp --nolaunchpppd" name <NT_domain><username> remotename PPTP require-mppe-128 file /etc/ppp/options.pptp ipparam <tunnel>

To start the vpn tunnel, simply type:

~# pon <tunnel>

And to stop the vpn tunnel:

~# poff <tunnel>


Note: This section assumes that your PPTP server has an internet facing address and an address on the remote lan which is not reachable from the internet (behind some NAT device). In the case where the network you are creating a VPN tunnel to is internet facing, the routing must be configured differently. See “Alternative routing”, below.

Note: This following section pertains to setting up a single client. Documentation on LAN-to-LAN configuration is below.

First, check to see if pptp creates an interface:

~# ifconfig ppp0 ppp0      Link encap:Point-to-Point Protocol {{{           inet addr:  P-t-P:  Mask:


Second, check that ppp creates a route to the tunnel endpoint:

~# route -n Kernel IP routing table Destination     Gateway         Genmask         Flags Metric Ref    Use Iface UH    0      0        0 ppp0       U     0      0        0 eth0         UG    0      0        0 eth0

This should allow you to see the PPTP server’s internal interface:

~# ping -c 4 PING ( 56 data bytes 64 bytes from icmp_seq=0 ttl=128 time=23.6 ms 64 bytes from icmp_seq=1 ttl=128 time=32.8 ms 64 bytes from icmp_seq=2 ttl=128 time=27.1 ms 64 bytes from icmp_seq=3 ttl=128 time=28.9 ms

Next you’ll need to add a route to send all packets to the VPN subnet through the VPN tunnel:

~# route add -net netmask gw dev ppp0

This should add the following line to the output of route -n:   UG    0      0        0 ppp0

You should now be able to talk to any machine on the remote VPN lan.

~# ping -c 4 PING ( 56 data bytes 64 bytes from icmp_seq=0 ttl=127 time=164.3 ms 64 bytes from icmp_seq=1 ttl=127 time=162.4 ms 64 bytes from icmp_seq=2 ttl=127 time=188.8 ms 64 bytes from icmp_seq=3 ttl=127 time=191.3 ms

Alternative routing

If the public IP address of the VPN (i.e. the address you connect to) is within the subnet accessible by the VPN, for example,

  • You connect to
  • You wish to route packets to the subnet / 16

then you need to perform your routing slightly differently.

Check your ppp0 IP address(es) as before:

~# ifconfig ppp0 ppp0      Link encap:Point-to-Point Protocol {{{           inet addr:  P-t-P:  Mask:


Also as before, check that the end-point inside the tunnel can be routed to:

~# route -n Kernel IP routing table Destination     Gateway         Genmask         Flags Metric Ref    Use Iface UH    0      0        0 ppp0       U     0      0        0 eth0         UG    0      0        0 eth0

Now, you need to add two other routing rules: one for the whole VPN network, and another for the external interface of the VPN server:

~# route add gw ~# route add -net dev ppp0

The first rule ensures that the GRE (i.e. the encapsulating packets for the tunnel) get routed through the “real” network. The second rule ensures, as in the routing example in the previous section, that packets for the rest of the VPN get sent through the VPN link.


In order to get through a firewall, you need to enable TCP port 1723 (for the initial negotiation), and GRE packets (for the tunnel encapsulation). If you are running the PPTP client on the firewall, then the following should do the trick:

 1. iptables -A OUTPUT -p tcp --dport 1723 -j ACCEPT  1. iptables -A OUTPUT -p gre -j ACCEPT

If you are running the PPTP client on a machine behind the firewall, you will have to add the above rules to the FORWARD chain instead.

If you are running a private IP range on your internal network, don’t forget to masquerade the connection as well:

 1. iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE


Useful links

The PPTP Client project

Leave a Reply