自建vpn之三:搭建openvpn service和生成客户端Profile

注:本文于2017年6月8日更新,涉及到用tcp还是udp和如何无错误地启动openvpn。
给虚机设定了基本的防护措施后,我们来安装openvpn服务器终端并生成profile文件。以下指令都是root级别。我假定你已经通过命令行连到服务器上。请根据需要在命令行前自行添加sudo或变成root。

我原计划给读者提供一步一步的说明,但那样会太繁琐。前两天注意到github上有人已经把这一切打包成一个shell脚本。我今天看了下,觉得写得很好。经过我成功测试后,推荐给你使用。并且这个脚本对Ubuntu,Debian, CentOS, RedHat啥的都管用。

  1. 请到 https://github.com/Nyr/openvpn-install 下载openvpn-install.sh脚本文件;
  2. 打开命令行,运行:
    bash /EnterRightPathHere/openvpn-install.sh
  3. 脚本程序会自动探测到你的IP网址,按回车键;
  4. 脚本问你用tcp或udp。如果你在大陆,我建议你用udp。udp因为不需要确认数据包安全抵达目的地信息,所以理论上比tcp要快;
  5. 脚本问你port number。我建议你用443。443是https的端口,这样你的vpn和https用同一个端口,我觉得可能更难以堵截;
  6. 脚本程序让你选择DNS。我不建议第一个选项(Current system resolvers)。2和6均可.
  7. 脚本程序让你命名客户端名字。默认是client。我不建议你用默认。建议你根据其所用的设备和数据中心命名,如androidFrankfurt,iphoneFrankfurt,或winPcFrankfurt等等。请用英文字母来命名;
  8. 再敲一次回车,程序就开始运行。运行时间差不多三五分钟,请等待,稍安毋躁。
  9. 运行结束后,openvpn服务器已经搭建完成并开始运行。接下来你要把它产生的.ovpn文件(profile 文件),比如winPcFrankfurt.ovpn输送到你的Windows/MacBook/Linux/Android/iPhone设备上。强烈建议你用WinSCP(Windows)或scp(Linux/Mac)来输送文件,防止在传送途中被偷窥;
  10. 如你需要产生更多的.ovpn文件,只要重新运行
    bash /EnterRightPathHere/openvpn-install.sh
    并选择第一个选项即可。

我注意到新版脚本在我的一个Debian服务器上不能正常启动。为了找到问题所在,在命令行运行:

haidong@localhost:~/openvpn-install-master$ sudo openvpn --config /etc/openvpn/server.conf
Options error: --dh fails with 'dh.pem': No such file or directory
Options error: --ca fails with 'ca.crt': No such file or directory
Options error: --cert fails with 'server.crt': No such file or directory
Options error: --key fails with 'server.key': No such file or directory
Options error: --crl-verify fails with 'crl.pem': No such file or directory
Options error: --tls-auth fails with 'ta.key': No such file or directory
Options error: Please correct these errors.
Use --help for more information.

问题出在openvpn找不到需要的pem、crt、key等文件。只要编辑下/etc/openvpn/server.conf,给上面提到的文件提供绝对路径就可以了。它们都在/etc/openvpn/下面。

祝玩得开心。下一篇,我们来谈谈怎样设立PC、Mac、和Linux客户端来使用vpn。

PS. 本系列其它文章
自建vpn之一:挑选供应商
自建vpn之二:保护你的机器
自建vpn之四:安装启动客户端

自建vpn之二:保护你的机器

选完虚拟机供应商、机器规格、操作系统啥的,机器启动后的第一件事是保护它的安全,尽可能减少被攻击面。我在这里只提供一些最基本建议,主要是在防火墙的设置方面。这里提供的一些指令假定你是用Debian 7或8。你如果用Ubuntu,这些指令基本上可以直接拿过来用。CentOS/Red Hat/Fedora方面的指令类似,请自行查询。如有需要,等我有空专门写CentOS/Red Hat/Fedora的设置。

以下指令都是root级别。我假定你已经通过命令行连到服务器上。请根据需要在命令行前自行添加sudo或变成root。

  1. 给服务器做软件更新,打补丁:
    apt-get update
    apt-get upgrade
    (yum update)
  2. 调整ssh接口端,防范ssh攻击:
    Linux服务器默认ssh接口端是22。很多网络攻击就从这个接口强攻,用程序频繁自动发起无数次的连接申请,所谓的dictionary attack和brute-force attack。把默认的接口改成其它如50683,是防止这种攻击的有效手段。
    用你熟悉的编辑器,打开/etc/ssh/sshd_config,然后查找”Port 22″,把22改成50683后保存文件。
    接下来请重新启动ssh服务:
    service ssh restart
    注意以后的远程连接你要记得加-p 50683
  3. 建防火墙
    apt-get install iptables
    apt-get install iptables-persistent (运行这个指令,系统会问你要不要把现在的设置存下来,说要)
  4. 基本的防火墙设定,IPv4
    用你熟悉的编辑器,打开/etc/iptables/rules.v4,删除里面所有的内容,然后加下面的设置:
  5. *filter
    #  Allow all loopback (lo0) traffic and drop all traffic to 127/8 that doesn't use lo0
    -A INPUT -i lo -j ACCEPT
    -A INPUT -d 127.0.0.0/8 -j REJECT
    
    #  Accept all established inbound connections
    -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
    
    #  Allow all outbound traffic - you can modify this to only allow certain traffic
    -A OUTPUT -j ACCEPT
    
    #  VPN port and forwarding.
    -A INPUT -p udp -m state --state NEW -m udp --dport 1194 -j ACCEPT
    -A FORWARD -s 10.8.0.0/24 -j ACCEPT
    -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
    
    #  Allow SSH connections
    #
    #  The -dport number should be the same port number you set in sshd_config
    #
    -A INPUT -p tcp -m state --state NEW --dport 50683 -j ACCEPT
    
    #  Allow ping
    -A INPUT -p icmp -j ACCEPT
    
    #  Log iptables denied calls
    -A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7
    
    #  Drop all other inbound - default deny unless explicitly allowed policy
    -A INPUT -j DROP
    -A FORWARD -j DROP
    
    COMMIT
    
  6. 基本的防火墙设定,IPv6
    用你熟悉的编辑器,打开/etc/iptables/rules.v6,删除里面所有的内容,然后加下面的设置:
  7. *filter
    
    # Allow all loopback (lo0) traffic and reject traffic
    # to localhost that does not originate from lo0.
    -A INPUT -i lo -j ACCEPT
    -A INPUT ! -i lo -s ::1/128 -j REJECT
    
    # Allow ICMP
    -A INPUT  -p icmpv6 -j ACCEPT
    
    #  Allow SSH connections
    #
    #  The -dport number should be the same port number you set in sshd_config
    #
    -A INPUT -p tcp -m state --state NEW --dport 50683 -j ACCEPT
    
    # Accept inbound traffic from established connections.
    -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
    
    # Log what was incoming but denied (optional but useful).
    -A INPUT -m limit --limit 5/min -j LOG --log-prefix "ip6tables_INPUT_denied: " --log-level 7
    
    # Reject all other inbound.
    -A INPUT -j REJECT
    
    # Log any traffic which was sent to you
    # for forwarding (optional but useful).
    -A FORWARD -m limit --limit 5/min -j LOG --log-prefix "ip6tables_FORWARD_denied: " --log-level 7
    
    # Reject all traffic forwarding.
    -A FORWARD -j REJECT
    
    COMMIT
    
    
  8. 激活防火墙

    iptables-restore < /etc/iptables/rules.v4 ip6tables-restore < /etc/iptables/rules.v6 [/code]

以上是一些很基本的保护措施。让服务器更安全,建议你以后安装Fail2Ban,使用ssh key认证,而不是简单的用户名密码认证,等等等等。接下来,我们就可以设置vpn服务器了。

PS. 本系列其它文章
自建vpn之一:挑选供应商
自建vpn之三:搭建openvpn service和生成客户端Profile
自建vpn之四:安装启动客户端

自建vpn之一:挑选供应商

想自建vpn,就必须有vpn的服务器。这种服务器一般是利用云服务公司提供的虚拟机服务VPS(Virtual Private Server)。

  1. 要有可以国外支付的办法,如信用卡、PayPal啥的;
  2. 业界比较知名的供应商有Amazon EC2,Microsoft Azure,LinodeDigitalOcean等等。这几个应当都可以;
  3. 如果是单纯做vpn翻墙供自己或小团队使用,供应商的最小配置就可以。我现在用的就是单CPU、128MB内存、10G硬盘小虚机,够我们多台设备一起用;
  4. 挑选数据中心时,不建议用英语国家的数据中心,特别是美国的。一是有安全和隐私方面的担心,相信大家都读过相关新闻;二是至少我尝试过的美国数据中心访问中国的一些网站都慢的要死,如优酷。但我发现西欧的数据中心如德国、荷兰、瑞典就没有这方面的问题。我不知道为什么。
  5. 操作系统当然要用Linux。我建议Debian。接下来的how to我会假定你的操作系统是Debian 7或8。如果你用其它操作系统,接下来的how to仍然会有帮助。

先写到这儿。亲爱的读者,你先去研究下哪个服务更适合你。之后再回来看我的指南。接下来的博客会提供些建议,讲如何提高你的虚拟机的安全。然后我们再说建vpn的事儿。

PS. 本系列其它文章
自建vpn之二:保护你的机器
自建vpn之三:搭建openvpn service和生成客户端Profile
自建vpn之四:安装启动客户端

WordPress post update services and Nginx upstream time out

Starting around last Friday, I think, this site became irresponsive. Checking Tengine/Nginx error logs, here is a sample of what I saw:

2014/03/xx 08:43:40 [error] 3837#0: *6149 connect() to unix:/var/run/php-fastcgi/php-fastcgi.socket failed (11: Resource temporarily unavailable) while connecting to upstream, client: xxx.xx.xxx.xxx, server: haidongji.com, request: "POST /xmlrpc.php HTTP/1.0", upstream: "fastcgi://unix:/var/run/php-fastcgi/php-fastcgi.socket:", host: "www.haidongji.com"
2014/03/xx 08:45:13 [error] 3837#0: *6151 upstream timed out (110: Connection timed out) while reading response header from upstream, client: x.xxx.xx.xxx, server: haidongji.com, request: "GET /wiki/doku.php?id=wiki:dokuwiki HTTP/1.0", upstream: "fastcgi://unix:/var/run/php-fastcgi/php-fastcgi.socket", host: "www.haidongji.com", referrer: "http://www.haidongji.com/"
2014/03/xx 08:46:00 [error] 3837#0: *6159 upstream timed out (110: Connection timed out) while reading response header from upstream, client: xx.xxx.xx.xxx, server: haidongji.com, request: "GET /category/technology/mysql/feed/ HTTP/1.1", upstream: "fastcgi://unix:/var/run/php-fastcgi/php-fastcgi.socket", host: "www.haidongji.com"

So I started researching. A number of web pages, including StackOverflow, recommended increasing values for some or all of the following Tengine/Nginx parameters, so time out wouldn’t occur:

  • fastcgi_read_timeout
  • proxy_connect_timeout
  • proxy_read_timeout
  • proxy_send_timeout

Those suggestion appeared to be reasonable. So I tried raising those parameter values one at a time. Their default value is 60 seconds. I raised them to 600 just to test.

In my case, the problem persisted. The only difference was that the site suffered a slower death and the few minutes it was able to stay alive, the site was terribly slow and unacceptable.

At this point I’d spent hours debugging this. I decided to give myself a break and come back to it the next day. Before falling asleep, I wrote down a note of checking some reputable forums the search engines may not necessarily able to get, such as Linode’s forums. Failing that, I am determined to read up on more documentation and code to get to the bottom of this.

It turned out that Linode’s forum provided the necessary clue to finally resolve this. The problem lies in the WordPress blog publishing update service. The idea behind it was to notify blog aggregators like Technorati/Feedburner (remember them?) as soon as you publish a blog. One of the aggregator sites listed in my WordPress setting decided to not accepting those notifications anymore. Not knowing this, WordPress still tries to send notification out in vain, which caused the whole mess. After removing that URL, everything went back to normal.

On your WordPress admin page, you can find which URL your blog pings to by going to: Settings -> Writing -> Update Services. Update: The same problem happened again. So I removed pingomatic.com also. Now my WordPress does not ping or update anybody. So far the site has been stable.

Hope this helps!

Lesson learned/reinforced:
After working on a problem for a long time and you are stuck, take a break, go for a walk, find a friend to talk to and describe the issue and what you’ve done thus far. You’d be surprised at how effective this can be.

Setting up ownCloud

I’ve spent some of my spare time lately researching on ways to have better control of my calendar, contacts, important files that I sync to different places, and such. My objective is to move those things away from big cloud providers like Google, Microsoft, Dropbox, Skype, and so on. I am happy to report that the open source solution ownCloud provides just what I needed. I was able to set it up today and the tests were successful. Here are some noteworthy points.

  • ownCloud provides clients for Windows, Mac, Linux, iPhone, and Android devices, which is really nice;
  • In my case, the only php component missing was the php GD module. After installation, I restarted my VM and then it worked fine. For database, I used MySQL;
  • Setup was easy. I did the manual install by following instructions here. My web server was Tengine, a fork of Nginx. I used the sample Nginx configuration in the instruction page as the starting point, and it worked just fine;
  • ownCloud recommends using SSL, which I concur. I spent some time researching on certificate options, and decided to use self-signed certificate. The reason is simple: the intended customer is me and my family, therefore I don’t need a Certificate Authority (CA) to tell me that I am using a site that I own 🙂 Not forking out the cash is added bonus. Note, though, that if you are running a commercial site that conducts transactions online, it is necessary to purchase certificates and enable SSL. That’s not the right time to be penny-pinching (or a 铁公鸡);
  • To generate my own self-signed certificate, I followed instructions here. I used the 2048 bit key. I followed the optional step 5 so that I can start Tengine without providing a password;
  • I think ownCloud will be great for companies and teams. If you have control to a web server, which most companies and teams do, then more than likely you’ve got the infrastructure to have your own cloud. For a company/team, I do recommend purchasing SSL certificates, unless your company/team is pretty small;
  • Don’t forget to renew your self-signed certificate as time moves closer to its expiration date. In my case, the validation period is one year. I’ve already set a reminder for me.
  • I’ve really enjoyed using dnsimple. Separating DNS and hosting service really gives me great flexibility in learning and testing out different web technology.

Hope this helps. Let me know if you have comments/suggestions.