本文介紹在安裝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效率高。
平臺簡介
- “硬”件平臺:Xen PV, 215M Memory, 512M Swap, 1T Transfer
- 操作系統:CentOS release 5.6 (Final)
- 內核:2.6.18-194.32.1.el5xen i686 i386 GNU/Linux
- 網絡:1 IP, 1 Network Adapter(eth0)
配置概覽
PPTP的配置主要有下面五個步驟:
- 驗證內核是否加載了MPPE模塊
- 安裝所需的軟件包
- 配置PPP和PPTP的配置文件
- 打開內核的IP轉發功能
- 啓動pptpd守護進程
- 配置iptables防火牆放行和轉發規則
詳細步驟
開機以後,首先是登錄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的配置文件:
接下來需要對ppp和pptpd進行配置,編輯它們的幾個配置文件。如果有Linux基礎的話,當然推薦使用vi/vim來編輯配置文件。如果不熟悉也不想熟悉vi,那麼可以用更容易上手的nano替換下面我將要使用的vi命令。本文不涉及文本編輯器的基礎知識,只需要知道如何打開文件、編輯文件、保存文件和退出文本編輯器就可以了。
這些配置文件中,#號開頭的行均爲註釋,對配置不起作用。我們不必關心註釋,所以下面我將使用類似
grep ^[^#] /etc/ppp/options.pptpd
這樣的命令,過濾出配置文件中有效的行顯示在本文正文中。你在編輯的時候,只需要添加或修改這些有效的行,把不需要的行前面加上#號註釋掉即可。
–ppp–
配置ppp需要編輯它的兩個配置文件,一個是option(選項)文件,一個是用戶賬戶文件。首先編輯option文件:
vi /etc/ppp/options.pptpd
我編輯這個文件時,它已經是存在的,並且其中的內容也幾乎不需要編輯,如果這個文件不存在,自行創建它並填入下面的有效配置就行了。下面是這個文件中有效的行:
- name pptpd
- refuse-pap
- refuse-chap
- refuse-mschap
- require-mschap-v2
- require-mppe-128
- ms-dns 8.8.8.8
- ms-dns 8.8.4.4
- proxyarp
- lock
- nobsdcomp
- novj
- novjccomp
- nologfd
其中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
這個文件中有效的行也很少:
- option /etc/ppp/options.pptpd
- logwtmp
- localip 192.168.0.1
- remoteip 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相關的幾項:
- 允許GRE(Generic Route Encapsulation)協議,PPTP使用GRE協議封裝PPP數據包,然後封裝成IP報文
- 放行1723端口的PPTP服務
- 放行狀態爲RELATED,ESTABLISHED的入站數據包(正常提供服務的機器上防火牆應該都已經配置了這一項)
- 放行VPN虛擬網絡設備所在的192.168.0.0/24網段與服務器網卡eth0之間的數據包轉發
- 爲從VPN網段192.168.0.0/24轉往網卡eth0的出站數據包做NAT
如果你其他的防火牆規則已經配置好無需改動,只需要增加上述相關VPN相關的規則,那麼執行下面幾條命令即可(第三條一般不用執行,除非你原來的防火牆連這個規則都沒允許,但是多執行一遍也無妨):
- iptables -A INPUT -p gre -j ACCEPT
- iptables -A INPUT -p tcp -m tcp --dport 1723 -j ACCEPT
- iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
- iptables -A FORWARD -s 192.168.0.0/24 -o eth0 -j ACCEPT
- iptables -A FORWARD -d 192.168.0.0/24 -i eth0 -j ACCEPT
- iptables -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段。
在我們這臺服務器上,還需要一些其他的服務:
- 22端口的SSH(非常重要!如果不小心連這個都忘了,基本就只能給VPS服務商發Ticket了)
- 21端口的FTP控制
- 80端口的Web服務
- 允許響應各種icmp請求
根據上述需求,加上服務器的基本要求,我寫了下面的shell腳本。這個腳本默認DROP掉沒有明確允許的規則,然後允許包括上面VPN相關的規則和上述幾項其他服務所需的規則。可以根據你的實際需求,修改這個腳本,然後執行這個腳本快速部署iptables規則。
- #!/bin/bash
- ### Clear Old Rules
- iptables -F
- iptables -X
- iptables -Z
- iptables -t nat -F
- iptables -t nat -X
- iptables -t nat -Z
- ### * filter
- # Default DROP
- iptables -P INPUT DROP
- iptables -P FORWARD DROP
- iptables -P OUTPUT DROP
- # INPUT Chain
- iptables -A INPUT -p gre -j ACCEPT
- iptables -A INPUT -i lo -p all -j ACCEPT
- iptables -A INPUT -p tcp -m tcp --dport 21 -j ACCEPT
- iptables -A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
- iptables -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
- iptables -A INPUT -p tcp -m tcp --dport 1723 -j ACCEPT
- iptables -A INPUT -p icmp -m icmp --icmp-type any -j ACCEPT
- iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
- # OUTPUT Chain
- iptables -A OUTPUT -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT
- # FORWARD Chain
- iptables -A FORWARD -s 192.168.0.0/24 -o eth0 -j ACCEPT
- iptables -A FORWARD -d 192.168.0.0/24 -i eth0 -j ACCEPT
- ### * nat
- # POSTROUTING Chain
- iptables -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。然後編輯其內容,例如:
- DEVICE=eth0:0
- BOOTPROTO=static
- ONBOOT=yes
- IPADDR=123.123.123.124
- NETMASK=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的情況:
- #!/bin/bash
- # Clear Old Rules
- iptables -F
- iptables -X
- iptables -Z
- iptables -t nat -F
- iptables -t nat -X
- iptables -t nat -Z
- ### * filter
- # Default DROP and ACCEPT
- iptables -P INPUT DROP
- iptables -P FORWARD DROP
- iptables -P OUTPUT DROP
- # INPUT Chain
- iptables -A INPUT -p gre -j ACCEPT
- iptables -A INPUT -i lo -p all -j ACCEPT
- iptables -A INPUT -p tcp -m tcp -d 123.123.123.123 --dport 21 -j ACCEPT
- iptables -A INPUT -p tcp -m tcp -d 123.123.123.123 --dport 22 -j ACCEPT
- iptables -A INPUT -p tcp -m tcp -d 123.123.123.123 --dport 80 -j ACCEPT
- iptables -A INPUT -p tcp -m tcp -d 123.123.123.123 --dport 443 -j ACCEPT
- iptables -A INPUT -p tcp -m tcp -d 123.123.123.124 --dport 1723 -j ACCEPT
- iptables -A INPUT -p icmp -m icmp --icmp-type any -j ACCEPT
- iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
- # OUTPUT Chain
- iptables -A OUTPUT -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT
- # FORWARD Chain
- iptables -A FORWARD -s 192.168.0.0/24 -o eth0 -j ACCEPT
- iptables -A FORWARD -d 192.168.0.0/24 -i eth0 -j ACCEPT
- ### * nat
- # POSTROUTING Chain
- iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -o eth0 -j MASQUERADE
這樣配置完成後,對公開的Web域名進行端口掃描,就只能掃描到80等端口,而VPN服務使用的域名IP不公開,就保證了安全性。我手欠掃描了一下我們的服務器,結果就成了這樣:
- [root@sheldon ~]# nmap -sS gnailuy.com
- Starting Nmap 5.21 ( http://nmap.org ) at 2011-07-20 20:46 CST
- Nmap scan report for gnailuy.com (One of our IP address)
- Host is up (0.31s latency).
- Not shown: 996 filtered ports
- PORT STATE SERVICE
- 21/tcp open ftp
- 22/tcp open ssh
- 80/tcp open http
- 443/tcp open https
- Nmap done: 1 IP address (1 host up) scanned in 17.44 seconds
- [root@sheldon ~]# nmap -sS vpnservers.domain.name
- Starting Nmap 5.21 ( http://nmap.org ) at 2011-07-20 20:53 CST
- Nmap scan report for vpnservers.domain.name (Our another IP address)
- Host is up (0.32s latency).
- Not shown: 999 filtered ports
- PORT STATE SERVICE
- 1723/tcp open pptp
- Nmap done: 1 IP address (1 host up) scanned in 24.52 seconds
後記
這篇文章是邊爬搜索引擎邊學習邊實驗寫成的,在摸索的過程中學習,確實學到了不少東西。學習和配置服務器的過程中,我不斷的Google到相關的文章,中文的英文的已經有一大把,於是我就在想,我寫這篇文章,應該完成哪些現有的資料尚不完善的地方。技術上我只是個初學者,除了搜索、思考、組織之外,暫時沒有可能創造出新的技術來,於是只好從語言組織、信息翔實程度和對配置細節的解釋上儘量提高本文的含金量,希望成爲中文文章中比較有用的一篇,能夠爲其他有這方面想法的朋友提供一些小小指引。
非常感謝在Twitter上爲我出主意的 @alexwwang 和 @helijohnny,他們的寶貴意見促成了本文目前的樣子。如果本文中還有哪些不足甚至紕漏,請千萬不吝賜教;或者如果你想要和我探討這方面的技術,都歡迎與我聯繫。可以@gnailuy on Twitter,或者也可以在我的About Me頁面找到更多其他聯繫方式。
© 2011, Yuliang Jin. All rights reserved.
This post is under a Creative Commons Attribution-ShareAlike 3.0 Unported License.