.-- .. - .... .-.. --- ...- .

home archive about

CentOS VPS 上搭建 PPTP VPN

03 Jul 2011

本文介绍在安装 CentOS 操作系统的 Xen VPS 上,如何搭建 PPTP VPN 服务。 包括 PPTP 的安装、配置,以及相应的 iptables 规则。 本文暂时不涉及 PPTP 流量控制的部分,等抽空学明白了 FreeRADIUS 再来写续篇。 2011 年 7 月 20 日更新:在安全建议这一部分,增加了使用不同的 IP 地址,分别提供 VPN 服务和 Web 等其他常规服务,以及使用不同 IP 地址时如何书写 iptables 规则的内容。

写在前面

在 Godaddy 一美元 COM 域名的怂恿下,这几天先是拿到了这个 gnailuy.com,然后觊觎了很久的 VPS 也就顺便到手了。所以说万事嘛,总是要有个开端。

按照之前的构想,下个月起这个 VPS 将由我和几个好朋友合租,配置虚拟主机,各自建立自己的小网站,还能合用 VPS 上的 VPN 服务。 从成本上考虑,只要有些钻研技术的精神,加上几个志同道合的朋友,合租一台不太高端的 VPS 自建服务器,应该还是低于同时购买域名、Web 托管以及 VPN 这几样的成本之和的。 这是第一个月,我们会先熟悉熟悉技术,做做各种测试,多学习多发些技术文章,供有同样想法的朋友们借鉴。

正文

在 Google 苦海里游了两天两夜,终于完成了 PPTP VPN 还有这个 Wordpress 小站的基本配置,今天先写一下 VPN。这些天因为嫌 Google 中文首页太丑,搜索资料的时候大都是用英文,本来也打算用英文写这篇文章,但考虑到下面两个原因,于是作罢: 一是到自己这英语写作能力,实在不济; 二是可能热衷于搭建 VPN 的个人或者团体,大概也许基本都是在中国大陆上网的吧,o(∩∩)o...

之所以选择 PPTP VPN,是考虑到客户端连接起来会比较方便。我们几个人主要都是在 Linux Desktop, Windows 还有 Android 上使用 VPN,这些终端原生都有连接 PPTP 的客户端。 当然还有一个原因,就是我们购买的 VPS 是基于 Xen PV 技术的,可以搭建 PPTP。 这个原因本来其实是结果,当初要买基于 Xen PV 的而不是 OpenVZ 的,就是因为打算在上面搭建 PPTP 服务。 BTW,Xen PV 是种半虚拟化技术,不能跑 Windows,但据说比全虚拟化的 Xen HVM 跑 Linux 效率高。

平台简介

我买的服务配置如下:

配置概览

PPTP 的配置主要有下面五个步骤:

详细步骤

开机以后,首先是登录 VPS。我平时用 Linux,就直接 ssh 命令登录上去。 如果是在 Winodws 下,推荐使用 PuTTY,有一点需要注意,就是连接之前最好把字符集设置成 UTF-8,因为 Linux 默认的 locale 都是 UTF-8 了,如果出现非 ASCII 字符,不设置字符集就会出现乱码,具体的设置方法 Google 知道。

下面的所有配置操作都需要 root 权限,如无特别说明,所有命令都在 root 的家目录下执行。顺便,最好在 VPS 上禁用 root 直接登录,尽量建立一个普通用户然后 su 到 root,具体细节偏题了,也请自行 Google。

1、验证内核是否加载了MPPE模块:

内核的 MPPE 模块用于支持 Microsoft Point-to-Point Encryption。 Windows 自带的 VPN 客户端就是使用这种加密方式,主流的 Linux Desktop 也都有 MPPE 支持。其实到了我们这个内核版本,默认就已经加载了 MPPE,只需要使用下面命令验证一下,显示 MPPE ok 即可:

modprobe ppp-compress-18 && echo MPPE is ok

2、安装所需的软件包:

--ppp--

PPTP 使用 PPP 协议对用户数据进行封装,然后将 PPP 数据帧封装在 IP 数据报里,经由 IP 网络传播。因此首先需要支持 PPP 协议,我们使用的完整版 CentOS 已经自带了 ppp 这个软件包,如果你安装的是 Minial CentOS 之类的精简系统,则可能需要下面命令安装 ppp

yum install ppp

作为一个懒人,如果没有特殊的自定义要求,我一般尽量用 yum 安装软件。只要软件源里有,yum 比较方便一些,还能自动解决依赖关系。

--pptpd--

有了 PPP 协议支持,接下来安装 pptpd。 首先到 这里 找到最新版适合你的平台的 pptpd。 CentOS 与 RHEL 通用,Fedora 系统则可以使用后缀含 'fc' 字样的包,然后还需要根据内核选择 32 位或者 64 位的包。 找到正确的软件包以后,复制其 URL,然后用 wget 下载到 root 的家目录(或者rpm -ivh URL 直接安装也行)。譬如我的 32 位内核 CentOS 5,使用下面命令下载:

wget http://poptop.sourceforge.net/yum/stable/packages/pptpd-1.3.4-2.rhel5.i386.rpm

这篇文章默认不考虑 "wget: command not found" 此类初级的错误。 如果看到类似错误,一是检查命令有没有拼错,二是 yum install it,三是 Google it。 其实,这篇文章里总共也用不到几条容易 Not Found 的命令。

下载完成后,安装:

rpm -ivh pptpd-1.3.4-2.rhel5.i386.rpm
--iptables--

同样,如果不是 Minial 的系统,应该不会没有安装 iptables。 这是 Linux 下最流行的防火墙,默认应该就能找到,如果没有,则:

yum install iptables

然后像是 iptables 这样的软件,对服务器非常重要。 虽然还没有配置防火墙的规则,装完就打开吧(只要默认放行 ssh 的 22 端口就没问题),打开以后还需要设置一下,在主要的运行级别自动启动:

/etc/init.d/iptables start
chkconfig --level 35 iptables on

3、配置PPP和PPTP的配置文件:

接下来需要对 ppppptpd 进行配置,编辑它们的几个配置文件。 如果有 Linux 基础的话,当然推荐使用 'vi/vim' 来编辑配置文件。如果不熟悉也不想熟悉 vi,那么可以用更容易上手的 nano 替换下面我将要使用的 vi 命令。 本文不涉及文本编辑器的基础知识,只需要知道如何打开文件、编辑文件、保存文件和退出文本编辑器就可以了。

这些配置文件中,'#' 号开头的行均为注释,对配置不起作用。我们不必关心注释,所以下面我将使用类似

grep ^[^#] /etc/ppp/options.pptpd

这样的命令,过滤出配置文件中有效的行显示在本文正文中。你在编辑的时候,只需要添加或修改这些有效的行,把不需要的行前面加上 # 号注释掉即可。

--ppp--

配置 ppp 需要编辑它的两个配置文件,一个是 option(选项)文件,一个是用户账户文件。 首先编辑 option 文件:

vi /etc/ppp/options.pptpd

我编辑这个文件时,它已经是存在的,并且其中的内容也几乎不需要编辑,如果这个文件不存在,自行创建它并填入下面的有效配置就行了。下面是这个文件中有效的行:

 1name pptpd
 2refuse-pap
 3refuse-chap
 4refuse-mschap
 5require-mschap-v2
 6require-mppe-128
 7ms-dns 8.8.8.8
 8ms-dns 8.8.4.4
 9proxyarp
10lock
11nobsdcomp
12novj
13novjccomp
14nologfd

其中 name 后面的 pptpd 是服务名称,可以任意修改成你喜欢的名字,在后面的配置中将对应的 pptpd 替换为你在这里修改的名字即可。

接下来的几行以 refuse 或者 require 开头的指令,是配置拒绝和接受的加密方式,这里接受的 mschap-v2 和 mppe-128 都是较新的比较安全的加密方式,其中 mppe-128 需要第一步中验证的内核模块支持。

另外两个比较重要的行就是 ms-dns 了,它们指定 VPN 使用的 DNS 服务器。毕竟 VPS 位于国外,所以推荐使用上面通用的 Google Public DNS,当然也可以修改为你的 VPS 所在 ISP 提供的 DNS。

剩下后面几个选项,就不在这里叙述了,需要知道其含义的童鞋可以参考这个 范例文件 中的注释。

接下来修改另一个,存储着用户账户的文件:

vi /etc/ppp/chap-secrets

这个文件非常简单,其中用明文存储 VPN 客户的用户名、服务名称、密码和 IP 地址范围,每行一个账户:

username1 pptpd passwd1 *
username2 pptpd passwd2 *

其中第一第三列分别是用户名和密码; 第二列应该和上面的文件 /etc/ppp/options.pptpd 中 name 后指定的服务名称一致; 最后一列限制客户端 IP 地址,星号表示没有限制。

--pptpd--

下面编辑pptpd的配置文件:

vi /etc/pptpd.conf

这个文件中有效的行也很少:

1option /etc/ppp/options.pptpd
2logwtmp
3localip 192.168.0.1
4remoteip 192.168.0.207-217

其中 option 选项指定使用 /etc/ppp/options.pptpd 中的配置; logwtmp 表示使用 WTMP 日志。

后面两行是比较重要的两行。VPN 可以这样理解,Linux 客户端使用一个虚拟网络设备 ppp0 (Windows 客户端也可以理解成 VPN 虚拟网卡),连接到服务器的虚拟网络设备 ppp0 上,这样客户端就加入了服务器端 ppp0 所在的网络。 localip 就是可以分配给服务器端 ppp0 的 IP 地址,remoteip 则是将要分配给客户端 ppp0 (或者虚拟网卡)的。

这两项都可以是多个 IP,一般 localip 设置一个 IP 就行了,remoteip 则视客户端数目,分配一段 IP。其中 remoteip 的 IP 段需要和 localip 的 IP 段一致。

localip 和 remoteip 所处的 IP 段可以随意些指定,但其范围内不要包含实际网卡 eth0 的 IP 地址。 一般情况下,使用上面配置文件中的配置就好使了,你需要做的只是把 192.168.0.207-217 这个 IP 区间修改成你喜欢的 192.168.0.a-b,其中 1<a<b<255

4、打开内核的 IP 转发功能:

要使 VPN 服务器可以作为网络请求的中转代理,能够使客户端通过 VPN 访问 Internet,还需要开启内核的 IP 转发功能。可以编辑配置文件:

vi /etc/sysctl.conf

找到其中的行:

net.ipv4.ip_forward = 0

修改为:

net.ipv4.ip_forward = 1

然后执行下面命令使上述修改生效:

sysctl -p

5、启动 pptpd 守护进程:

上面配置完成后,就可以启动 pptpd 进程并设置自动启动了,和上面 iptables 的例子类似:

/etc/init.d/pptpd start
chkconfig --level 35 pptpd on

6、配置 iptables 防火墙放行和转发规则:

最后,还需要配置防火墙。这里配置防火墙有三个目的: 一是设置默认丢弃规则,保护服务器的安全; 二是放行我们允许的数据包,提供服务; 三是通过配置 nat 表的 POSTROUTING 链,增加 NAT 使得 VPN 客户端可以通过服务器访问互联网。 总之我们的原则就是,只放行我们需要的服务,其他统统拒绝。

首先介绍跟 PPTP VPN 相关的几项:

如果你其他的防火墙规则已经配置好无需改动,只需要增加上述相关 VPN 相关的规则, 那么执行下面几条命令即可(第三条一般不用执行,除非你原来的防火墙连这个规则都没允许,但是多执行一遍也无妨):

1iptables -A INPUT -p gre -j ACCEPT
2iptables -A INPUT -p tcp -m tcp --dport 1723 -j ACCEPT
3iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
4iptables -A FORWARD -s 192.168.0.0/24 -o eth0 -j ACCEPT
5iptables -A FORWARD -d 192.168.0.0/24 -i eth0 -j ACCEPT
6iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -o eth0 -j MASQUERADE

上述的 IP 段 192.168.0.1/24 可能需要修改成 /etc/pptp.conf 中你配置的 localip 和 remoteip 所在地 IP 段。

在我们这台服务器上,还需要一些其他的服务:

根据上述需求,加上服务器的基本要求,我写了下面的 shell 脚本。这个脚本默认 DROP 掉没有明确允许的规则,然后允许包括上面 VPN 相关的规则和上述几项其他服务所需的规则。 可以根据你的实际需求,修改这个脚本,然后执行这个脚本快速部署 iptables 规则。

 1#!/bin/bash
 2### Clear Old Rules
 3iptables -F
 4iptables -X
 5iptables -Z
 6iptables -t nat -F
 7iptables -t nat -X
 8iptables -t nat -Z
 9
10### * filter
11# Default DROP
12iptables -P INPUT DROP
13iptables -P FORWARD DROP
14iptables -P OUTPUT DROP
15# INPUT Chain
16iptables -A INPUT -p gre -j ACCEPT
17iptables -A INPUT -i lo -p all -j ACCEPT
18iptables -A INPUT -p tcp -m tcp --dport 21 -j ACCEPT
19iptables -A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
20iptables -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
21iptables -A INPUT -p tcp -m tcp --dport 1723 -j ACCEPT
22iptables -A INPUT -p icmp -m icmp --icmp-type any -j ACCEPT
23iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
24# OUTPUT Chain
25iptables -A OUTPUT -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT
26# FORWARD Chain
27iptables -A FORWARD -s 192.168.0.0/24 -o eth0 -j ACCEPT
28iptables -A FORWARD -d 192.168.0.0/24 -i eth0 -j ACCEPT
29### * nat
30# POSTROUTING Chain
31iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -o eth0 -j MASQUERADE

需要注意的是,这个脚本开头首先清除掉了所有 iptables 规则,然后才部署新的规则,如果你需要保留你机器上现有的规则,请千万不要执行前面的清除语句,或者做好旧规则的备份再做实验:

iptables-save > iptables.backup

如果想恢复使用上面命令做好的备份,可以:

iptables-resotre iptables.backup

最后,如果确定所有的 iptables 规则已经合乎你的心意,就可以执行下面命令,将 iptables 规则保存下来。

/etc/init.d/iptables save

安全建议

在 Twitter 上得到了 @alexwwang@helijohnny 的指点,知道 VPN 与这个网站放在一起,可能不安全。他们建议我为 VPS 增加一个 IP,可以让 VPN 服务和 Web 走不同的 IP,这样就不会因为 Web 网站发表的内容轻易暴露 VPN 服务器的 IP 了。 之前我只是在测试机上测试过,今天终于新购得一个 IP 地址,得以把这一部分补全。

单网卡配置多个IP地址

CentOS 下单网卡配置多个 IP 很容易。例如,假设现在网卡 eth0 已经有一个 IP 地址是 123.123.123.123/24,想要增加一个 IP 是 123.123.123.124/24,可以在 /etc/sysconfig/network-scripts/ 目录下增加一个新的虚拟网卡配置文件 ifcfg-eth0:0。 想省事的话可以直接把 ifcfg-eth0 复制成 ifcfg-eth0:0, 然后编辑其内容,例如:

1DEVICE=eth0:0
2BOOTPROTO=static
3ONBOOT=yes
4IPADDR=123.123.123.124
5NETMASK=255.255.255.0

虚拟网卡 eth0:0 配置的信息看起来有些少,其实它会共享实际设备 eth0 的配置信息,因此如上简单的配置就够了。 另外如果在这张网卡上还需要添加更多的 IP 地址,照此例增加 eth0:1、eth0:2 等等虚拟设备既可。

多 IP 的 iptables 配置

然后关于 iptables 配置,思路就是在 INPUT 链上使用 -d 区别目的 IP,只在 Web 等服务使用的 IP 上放行 22 和 80 等几个端口,VPN 服务的 IP 上只放行 1723 端口。

如果喜欢的话也可以为新增加的 IP 绑定一个不同的域名,只要防火墙配置好了,然后 VPN 使用的 IP 域名都不公开,理论上是挺难找到 VPN 服务地址的,这也是自建 VPN 的一个好处。 这里再提供一个 iptables 规则的配置脚本,与上面的脚本类似,只是做了少量的修改,适用于多 IP 的情况:

 1#!/bin/bash
 2### Clear Old Rules
 3iptables -F
 4iptables -X
 5iptables -Z
 6iptables -t nat -F
 7iptables -t nat -X
 8iptables -t nat -Z
 9
10### * filter
11# Default DROP and ACCEPT
12iptables -P INPUT DROP
13iptables -P FORWARD DROP
14iptables -P OUTPUT DROP
15# INPUT Chain
16iptables -A INPUT -p gre -j ACCEPT
17iptables -A INPUT -i lo -p all -j ACCEPT
18iptables -A INPUT -p tcp -m tcp -d 123.123.123.123 --dport 21 -j ACCEPT
19iptables -A INPUT -p tcp -m tcp -d 123.123.123.123 --dport 22 -j ACCEPT
20iptables -A INPUT -p tcp -m tcp -d 123.123.123.123 --dport 80 -j ACCEPT
21iptables -A INPUT -p tcp -m tcp -d 123.123.123.123 --dport 443 -j ACCEPT
22iptables -A INPUT -p tcp -m tcp -d 123.123.123.124 --dport 1723 -j ACCEPT
23iptables -A INPUT -p icmp -m icmp --icmp-type any -j ACCEPT
24iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
25# OUTPUT Chain
26iptables -A OUTPUT -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT
27# FORWARD Chain
28iptables -A FORWARD -s 192.168.0.0/24 -o eth0 -j ACCEPT
29iptables -A FORWARD -d 192.168.0.0/24 -i eth0 -j ACCEPT
30
31### * nat
32# POSTROUTING Chain
33iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -o eth0 -j MASQUERADE

这样配置完成后,对公开的 Web 域名进行端口扫描,就只能扫描到 80 等端口,而 VPN 服务使用的域名 IP 不公开,就保证了安全性。 我手欠扫描了一下我们的服务器,结果就成了这样:

 1[root@sheldon ~]# nmap -sS gnailuy.com
 2Starting Nmap 5.21 ( http://nmap.org ) at 2011-07-20 20:46 CST
 3Nmap scan report for gnailuy.com (One of our IP address)
 4Host is up (0.31s latency).
 5Not shown: 996 filtered ports
 6PORT    STATE SERVICE
 721/tcp  open  ftp
 822/tcp  open  ssh
 980/tcp  open  http
10443/tcp open  https
11Nmap done: 1 IP address (1 host up) scanned in 17.44 seconds
12
13[root@sheldon ~]# nmap -sS vpnservers.domain.name
14Starting Nmap 5.21 ( http://nmap.org ) at 2011-07-20 20:53 CST
15Nmap scan report for vpnservers.domain.name (Our another IP address)
16Host is up (0.32s latency).
17Not shown: 999 filtered ports
18PORT     STATE SERVICE
191723/tcp open  pptp
20Nmap done: 1 IP address (1 host up) scanned in 24.52 seconds

后记

这篇文章是边爬搜索引擎边学习边实验写成的,在摸索的过程中学习,确实学到了不少东西。 学习和配置服务器的过程中,我不断的 Google 到相关的文章,中文的英文的已经有一大把, 于是我就在想,我写这篇文章,应该完成哪些现有的资料尚不完善的地方。 技术上我只是个初学者,除了搜索、思考、组织之外,暂时没有可能创造出新的技术来, 于是只好从语言组织、信息翔实程度和对配置细节的解释上尽量提高本文的含金量, 希望成为中文文章中比较有用的一篇,能够为其他有这方面想法的朋友提供一些小小指引。

非常感谢在 Twitter 上为我出主意的 @alexwwang@helijohnny,他们的宝贵意见促成了本文目前的样子。 如果本文中还有哪些不足甚至纰漏,请千万不吝赐教;或者如果你想要和我探讨这方面的技术,都欢迎与我联系。 可以 @gnailuy on Twitter,或者也可以在我的 About Me 页面找到更多其他联系方式。

Creative Commons License
comments powered by Disqus