使用ssl加密Nginx与uptream servers之间的流量

nginx做为一款优秀的反向代理软件,最常见的架构是:

客户 <---> NGINX(反向代理) <---> 后端服务器(upstream servers)

如果nginx和后端服务器都在公网上,按常规配置,nginx与后端服务器之间的流量是明文传输的,很容易受到篡改、嗅探或者被GFW认证。我就遇到了NGINX反代后端服务器时,竟然被劫持了!!!
Nginx作为工作在7层的软件,最常用的加密方式就是https了,我只需要加密nginx到upstream servers之间的流量,不需要浏览器认证,所以自签名证书就够了,此作法需要:

1. 自签名证书
2. 后端服务器配置https
3. nginx配置解密私钥

一、生成自签名证书
使用openssl生成签名证书:

openssl  req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout 52os.net.key -out 52os.net.crt

二、后端服务器配置自签名证书
为了不影响后端的https配置,我启用了一个新端口,配置自签名证书。我后端(upstream servers)也是nginx服务器

server {
    listen     12345;

    ssl on;
    ssl_certificate        "/etc/ssl/certs/52os.net.crt";
    ssl_certificate_key    "/etc/ssl/certs/52os.net.key";

    ...... server configs ......

}

三、NGINX配置upstream加密
nginx(反向代理)配置upstream和解密私钥:

upstream backend {
    server backend1.52os.net.com:12345;
    server 8.8.8.8:12345;
    check interval=3000 rise=2 fall=3 timeout=30000 type=tcp;
    #check interval=3000 rise=2 fall=3 timeout=30000 type=http;
    #check_http_send "GET / HTTP/1.0\r\nConnection: keep-alive\r\nHost:www.52os.net\r\n\r\n";
    #check_http_expect_alive http_2xx http_3xx;

   }

server {
    listen     80;

    ssl_certificate_key    "/etc/ssl/certs/52os.net.key";

    location / {
        proxy_redirect         off;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;

        proxy_pass https://backend;
    }
}

配置好后,nginx到后端的upstream servers就会使用https加密了。
我的NIGNX版本tengine 2.1.2(nginx 1.6.1),nginx版本非常低。如果使用的是官方nginx,版本在1.9.2以上,有另外的模块可以实现Upstream加密的功能,原理是一样的。可以参考官方文章:https://www.nginx.com/resources/admin-guide/nginx-tcp-ssl-upstreams/

使用saltstack初始化系统

目前工作中使用最多的还是Fabric,最近把所有服务器都装上了saltstack,但是目前并没有使用saltstack进行管理,用的最多的还是进行系统和环境的初始化。主要是因为其它同事对saltstack不够熟悉,还有就是生产上的模块和环境都比较复杂,想完全使用saltstack管理还要一个循序渐进的过程,自动化运维想要用还是要趁早建设,越晚束手束脚的地方越多

一、saltstack安装

2.1 简介

saltstack是比较流行的开源配置管理工具,主要特点有:

  1. 基于Python开发,轻量级、灵活、扩展性好
  2. 使用ZeroMQ,确保速度和可靠性
  3. C/S架构,加密通讯,可管理海量客户端,并行能力强
  4. 配置简单、容易学习和使用

主要功能:

  1. 配置管理,自动配置系统和软件环境的状态
  2. 批量命令执行

saltstack软件组件,以下是官方文档中的介绍:

  1. salt-master: 主控制端(Server端),也叫Master
  2. salt-minion: 被控制端(client端),也叫Minion
  3. salt-ssh : 无Minion模式,使用ssh管理客户端,类似ansible
  4. salt-syndic :任务分发的代理,向Minion端发放任务
  5. Execution Modules:执行模块,在Minion系统上执行命令
  6. Runners :即使用salt-run,在Master端执行的命令
  7. Formulas (States):配置管理,描述Minion系统的目标状态
  8. Grains :在minion启动时收集到的系统静态信息
  9. Pillar :在Master端上定义的变量,供满足条件的Minion使用,通常是敏感信息
  10. Reactor : 基于事件触相应的操作
  11. Top File :入口文件
  12. Returners :将Minion执行结果发送给第三方系统

2.2 安装

我是centos系统,直接yum安装,epel源里也有,但是比官方的老一点,推荐使用官方源安装

yum install https://repo.saltstack.com/yum/redhat/salt-repo-latest-1.el6.noarch.rpm

安装并启动Master:

yum install salt-master
service salt-master start

启动salt-master后,zeromq会监听两个端口:

  • 4505:发布消息
  • 4506:接受消息

安装Minion:

yum install salt-minion

启动Minion端之前需在配置文件中指定Master的IP,支持IP和域名:

sed -i 's/#master: salt/master: master.52os.net/' /etc/salt/minion

启动Minion:

service salt-minion start

2.3 认证

master和minion通信之间使用AES加密。minion启动后,会生成公钥和私钥,并将公钥发送给master,被master接受后,master就能对minion发送指令了。同时Master在启动后也会生产公钥和私钥,minion端也会保留master的公钥
Master端查看key状态:

salt-key -L

服务端接受Minion的公钥:

salt-key -a salt-client

执行测试命令:

salt '*'  test.ping

有返回就说明正常通信了,可以用Master管理Minion端了

二、使用saltstack进行配置管理

saltstack的配置管理通过编写sls文件实现,sls文件描述了目标系统的状态,编写sls文件之前,需先在Master端设置保存sls文件的file_roots和pillar_roots,编辑/etc/salt/master,按需添加如下内容:

file_roots:
    base:
        - /etc/salt/base
    prod:
        - /etc/salt/prod

pillar_roots:
    base:
        - /etc/salt/pillar/base
    prod:
        - /etc/salt/pillar/prod

saltstack的sls文件使用YAML定义数据,top.sls文件为states的入口文件

top.sls
base:
 '*':
    - init.*

看一下目录结构:

tree /etc/salt/base
├── init
│   ├── cron.sls
│   ├── date_time.sls
│   ├── dirmode.sls
│   ├── dns.sls
│   ├── files
│   │   ├── limits.conf
│   │   └── resolv.conf
│   ├── history.sls
│   ├── pkg.sls
│   ├── selinux.sls
│   ├── sysctl.sls
│   └── ulimits.sls
└── top.sls

安装并更新常用的软件:pkg.sls

#install epel yum source
epel-release:
    pkg.installed:
        - refresh: True
#install or keep the base packages  latest
init_pkgs:
    pkg.latest:
        - pkgs:
            - yum
            - telnet
            - lrzsz
            - iptables
            - ntpdate
            - crontabs
            - policycoreutils   #selinux modules for saltstack
            - policycoreutils-python

更改时区并校准时间:date_time.sls

include:
    - init.pkg
date_time_setting:
    timezone.system:
        - name: Asia/Shanghai
        - utc: True
cmd.run:
    - name: ntpdate time.windows.com
    - require:
        - init_pkgs

定时任务管理: cron.sls

ntp_cron:
    cron.present:
        - name: ntpdate pool.ntp.org >/dev/null
        - user: root
        - hour: 4

配置系统DNS:dns.sls

/etc/resolv.conf:
    file.managed:
        - source: salt://init/files/resolv.conf
        - user: root
        - group: root
        - mode: 644

更改生产目录权限:dirmode.sls

/web:
file.directory:
    - name: /web
    - user: root
    - group: root
    - dir_mode: 755
    - file_mode: 644
    - recurse:
        - user
        - group
        - mode

记录所有用户bash历史命令到/var/log/bash_history.log:history.sls

/etc/profile:
file.append:
    - text: |
        function log2syslog
        {
        export HISTTIMEFORMAT="[%Y-%m-%d %H:%M:%S] [`who am i 2>/dev/null| awk '{print $NF}'|sed -e 's/[()]//g'`]"
        export PROMPT_COMMAND='\
          if [ -z "$OLD_PWD" ];then
                export OLD_PWD=$(pwd);
          fi;
        if [ ! -z "$LAST_CMD" ] && [ "$(history 1)" != "$LAST_CMD" ]; then
            echo  `whoami`_shell_cmd "[$OLD_PWD]$(history 1)" >>/var/log/bash_history.log;
        fi ;
        export LAST_CMD="$(history 1)";
        export OLD_PWD=$(pwd);'
        }
        trap log2syslog DEBUG
    - unless: grep log2syslog /etc/profile

env_source:
    cmd.run:
        - name: source /etc/profile
        - unless: env |grep  HISTTIMEFORMAT
        - require:
            - file: /etc/profile

关闭selinux:selinux.sls

permissive:
selinux.mode
disabled_selinux:
    file.replace:
        - name: /etc/sysconfig/selinux
        - pattern: SELINUX=enforcing
        - repl: SELINUX=disabled

更改系统最大能打开的文件数:ulimits.sls

/etc/security/limits.conf:
file.managed:
    - source: salt://init/files/limits.conf
    - user: root
    - group: root
    - mode: 644

cmd.run:
    - name: ulimit -a
    - unless:  grep 65535 /etc/security/limits.conf

设置内核参数:sysctl.sls

#本地tcp可使用端口范围
net.ipv4.ip_local_port_range:
    sysctl.present:
        - value: 10000 65000
#设置可以打开的最大文件数
fs.file-max:
    sysctl.present:
        - value: 2000000
#减少swap分区使用
vm.swappiness:
    sysctl.present:
        - value: 0

salt也有一些预先写好的Formulas(Formulas are pre-written Salt States),想省事可以直接拿来用,地址: https://github.com/saltstack-formulas

参考文章:

http://lixcto.blog.51cto.com/4834175/d-1

linux下配置和安装KVM虚拟机

最近要在外网搞一套监控系统,正好有一台服务器配置比较高,也没跑什么重要的业务,就拿来划了一个KVM虚拟机,可能是平时各种虚拟机用的比较多,配置起来感觉比想象中简单的多,简单记录下过程

准备工作

宿主机为centos 6.8 64位,检查宿主机CPU是否支持虚拟化:

cat /proc/cpuinfo | egrep '(vmx|svm)' | wc -l;

结果大于0表示支持

安装kvm

KVM核心软件包:

yum install kvm libvirt python-virtinst qemu-kvm virt-viewer bridge-utils

如果服务器上有桌面环境,想使用图形界面管理器virt-manager,可以安装完整的KVM环境:

yum groupinstall Virtualization 'Virtualization Client' 'Virtualization Platform' 'Virtualization Tools'

验证内核模块是否加载:

lsmod | grep kvm

启动虚拟机管理接口服务:

/etc/init.d/libvirtd start

设置开机启动:

chkconfig libvirtd on

启动libvirtd后,会自动创建了一个网卡,并启动dnsmasq服务,用来为虚拟机分配IP地址

创建虚拟机

下载虚拟机要安装的ISO系统镜像文件,之后需创建存储池,指定在宿主机上虚拟机磁盘的存储位置,创建存储目录:

mkdir -p /opt/kvm

定义一个储存池和绑定目录:

virsh pool-define-as vmspool --type dir --target /opt/kvm

建立并激活存储池:

virsh pool-build vmspool
virsh pool-start vmspool

使用存储池创建虚拟机,并通过vnc连接:

virt-install \
--hvm    \ #全虚拟化
--name=zabbix  \#虚拟机名字
--ram=4096   \ #分配内存
--vcpus=4   \  #分配CPU数
--cdrom=/opt/kvm/iso/CentOS-7-x86_64-DVD-1511.iso \ #使用的ISO
--virt-type=kvm \ #虚拟机类型
--disk  path=/opt/kvm/zabbix.qcow2,device=disk,format=qcow2,bus=virtio,cache=writeback,size=100 \ #磁盘大小,格式
--network default \  #网络设置,defalut为NAT模式
--accelerate \  #KVM内核加速
--graphics vnc,listen=0.0.0.0,port=5922,password=123123\ #vnc配置
--force \
--autostart

之后使用vnc客户端连接 宿主机IP:5922,即可使用图形安装系统;也可以选择nographics模式,无需vnc在命令行下安装,建议使用vnc
安装完成后会生成:

  1. 虚拟机的配置文件:/etc/libvirt/qemu/zabbix.xml
  2. 虚拟硬盘文件:/opt/kvm/zabbix.qcow2
  3. NAT网络配置文件:/etc/libvirt/qemu/networks/default.xml

配置网络

KVM可以配置两种:

  1. NAT网络: 虚拟机使用宿主机的网络访问公网,宿主机和虚拟机能互相访问,但不支持外部访问虚拟机
  2. 桥接网络: 虚拟机复用宿主机物理网卡,虚拟机与宿主机在网络中角色完全相同,支持外部访问

配置NAT网络

默认会有一个叫default的NAT虚拟网络,查看NAT网络:

virsh net-list --all

如果要创建或者修改NAT网络,要先编辑default.xml:

virsh  net-edit default

重新加载和激活配置:

virsh  net-define /etc/libvirt/qemu/networks/default.xml

启动NAT网络:

virsh net-start default
virsh net-autostart default

启动NAT后会自动生成一个虚拟桥接设备virbr0,并分配IP地址,查看状态:

brctl show

正常情况下libirtd启动后就会启动virbr0,并自动添加IPtables规则来实现NAT,要保证打开ip_forward,在/etc/sysctl.conf中:

net.ipv4.ip_forward = 1
sysctl -p

启动虚机并设置自动获取IP即可,如果想手动指定虚拟机IP,要注意配置的IP需在NAT网段内

配置桥接网络

系统如果安装了桌面环境,网络会由NetworkManager进行管理,NetworkManager不支持桥接,需要关闭NetworkManger:

chkconfig NetworkManager off
chkconfig network on
service NetworkManager stop
service network start

不想关闭NetworkManager,也可以在ifcfg-br0中手动添加参数"NM_CONTROLLED=no"
创建网桥:

virsh iface-bridge eth0 br0

创建完后ifconfig会看到br0网桥,如果eth0上有多个IP,更改下相应的文件名,如:ifcfg-eth0:1改为ifcfg-br0:1
编辑虚拟机的配置文件,使用新的网桥:

virsh edit zabbix

找到网卡配置,改为:

<interface type='bridge'>
  <mac address='52:54:00:7a:f4:9b'/>
  <source bridge='br0'/>
  <model type='virtio'/>
  <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</interface>

我是用的br0,为虚拟机添加多块网卡只需复制多个interface,并确保mac address和PCI地址不同即可
重新加载配置:

virsh define /etc/libvirt/qemu/zabbix.xml

重启虚拟机:

virsh shutdown zabbix
virsh start zabbix

之后使用VNC连接虚拟机并设置下网络即可

常用操作

KVM相关操作都通过vish命令完成,参数虽然多,但是功能一目了然,很直观

创建虚拟机快照:

virsh  snapshot-create-as --domain zabbix --name init_snap_1

也可以简写成:

virsh  snapshot-create-as  zabbix  init_snap_1

快照创建后配置文件在/var/lib/libvirt/qemu/snapshot/zabbix/init_snap_1.xml
查看快照:

snapshot-list zabbix

删除快照:

 snapshot-delete zabbix  init_snap_1

排错

  1. ERROR Format cannot be specified for unmanaged storage.
    virt-manager 没有找到存储池,创建储存池即可

  2. KVM VNC客户端连接闪退
    使用real vnc或者其它vnc客户端连接kvm闪退,把客户端设置中的ColourLevel值设置为rgb222或full即可

  3. virsh shutdown 无法关闭虚拟机
    使用该命令关闭虚拟机时,KVM是向虚拟机发送一个ACPI的指令,需要虚拟机安装acpid服务:
    yum -y install acpid && /etc/init.d/acpid start
    否则只能使用virsh destroy 强制关闭虚拟机

参考文章

https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Virtualization_Host_Configuration_and_Guest_Installation_Guide/index.html

asterisk双向回拨功能实现

目前我们公司电话系统经过两年的发展,已经实现了两个异地办公室、上百部分机,三个机房节点,多家voip供应商的之间的互通与网络冗余,算的上一个小型的呼叫中心了,一直比较懒写这方面的文章。最近公司正好有做回拨的需求,随便写篇关于这方面的文章。
需求:客户通过网站前台提交电话号码,电话系统先呼叫指定客服分机或响铃组,客服摘机后系统呼叫客户电话号码,客户接听后开始与客服通话。

我们的电话系统用的是freePBX,系统自带回拨功能(callback)功能比较简单,商业模块(WebCallBack)可以实现web提交号码,但这两个模块都只能先呼叫客户,客户接通后才能呼叫客服,无法自定义呼叫顺序,不满足我们的需求,只能自己开发了。好在asterisk支持自动呼叫脚本(.call files),功能实现起来比较容易,先看一下脚本工作流程:

1. asterisk 启动时需加载pbx_spool.so 模块支持自动呼叫脚本,Freepbx是自动加载的
2. 按需求编写呼叫脚本,保存为扩展名为.call的文件
3. 将.call脚本移到到/var/spool/asterisk/outgoing/目录下
4. 系统检测到该脚本并自动执行呼叫流程

呼叫脚本语法:

发起呼叫的参数:
Channel: <channel>: 呼叫的通道,可以是分机,trunk,响铃组等等
CallerID: "name" <number>  主叫id,即显示的号码和名称
MaxRetries: <number> 呼叫失败后重试次数,不包括原始呼叫
RetryTime: <number>  等待多久重新尝试呼叫
WaitTime: <number>  等待接听超时的时间
Account: 使用的Accoud code,CDR计费方面会用到

呼叫接通后的参数:
Context: <context-name> 使用的拨号方案
Extension: <ext>  拨号方案的目标号码
Priority: <priority> 优先级
Set: 设置变量
Application: 要启动的应用
Data: 应用使用的数据参数
AlwaysDelete: Yes/No 更改时间为将来时,不会删除该文件
Archive: Yes/No  使否将执行过的脚本归档到outgoing_done

来写一个hello world脚本:

channel: SIP/801   ;我的分机号
Callerid: "call" <801>
Application: Playback
Data: hello-world

将脚本保存为helloworld.call,手动复制到/var/spool/asterisk/outgoing/,系统就会拨打分机801,播放hello world后挂机。
我的freepbx对接了很多的voip供应商,freepbx会生产默认拨号方案:outbound-allroutes,根据用户拨号自动选择呼出线路,如我的规则:使用呼出线路1来打10086的拨号为:1 86 75510086。下面在写一个呼叫脚本:

channel: SIP/801   ;分机
Callerid: "回拨" <801>
Context: outbound-allroutes
Extension: 18675510086

这个脚本个功能是先呼叫分机801,在分机801接听后,系统开始呼叫10086,10086接听后801就可以与10086通话了。
这个脚本中分机801接听后,系统大概需要5秒才能接通10086,之间没有任何提示,freepbx的系统自带了一些提示,编写一个拨号方案加入提示,编辑:etc/asterisk/extensions_custom.conf,加入:

[saylast4num]
exten = _XX.,1,NoOp(say last 4 number of client number works) 
exten = _XX.,n,Wait(1)
exten = _XX.,n,Playback(calling)   ;系统提示音 calling
exten = _XX.,n,SayDigits(${EXTEN:-4}) ;读拨打号码的后4位
exten = _XX.,n,Goto(autocall_out,${EXTEN},1) ;跳转到自动呼出的拨号方案
[autocall_out]
include => outbound-allroutes

修改上面的呼叫脚本为:

channel: SIP/801   ;分机
;channel: Local/400@from-internal  ;本地响铃组400
Callerid: "回拨" <801>
Context: saylast4num
Extension: 18675510086

执行一下,801分机接听后系统会提示“calling 0086”,然后呼叫075510086,以这个脚本为模版,将18675510086替换为客户的号码,在用python封装成web api,就可以实现从web接收号码,写相应call脚本到/var/spool/asterisk/outgoing/,实现我们所需的回拨功能,python +flask写几十行代码就可以搞定

其实不使用呼叫脚本,使用originate也能实现,一个简单的shell脚本:

#!/bin/bash
asterisk -x "channel originate SIP/$1 extension $2@outbound-allroutes"

保存为call.sh ,用法: call.sh 801 18675510086
先呼叫客户在接通内部分机的情况,最方便的是直接花50刀买webcallback模块,这个我不多说了

参考文章:

http://www.voip-info.org/wiki/view/Asterisk+auto-dial+out

openvpn的搭建与使用

openvpn多数人用来科学上网,能保证安全性与速度,同时配置和稳定性也非常好。我在生产环境中也使用了很久,但比较懒一直都没有整理文档,这次正好有两台服务器之间要做加密连接,简单整理了一下

一、安装

下载:

wget http://swupdate.openvpn.org/community/releases/openvpn-2.3.11.tar.gz

依赖包:

yum install gcc gcc-c++ make  -y
yum install lzo lzo-devel -y
yum install pam pam-devel -y
yum install openssl openssl-devel -y

编译和安装:

./configure --prefix=/usr/local/openvpn
make && make install

epel源里有openvpn,也可以用yum 安装:

yum install -y epel-release
yum install openvpn easy-rsa

二、SSL证书生成

easy-rsa是openvpn生成服务端证书的脚本,自openvpn 2.3开始easy-rsa已经独立出来,下载:

git clone https://github.com/OpenVPN/easy-rsa
cd easy-rsa/easyrsa3/

初始化生成证书所需的信息,按实际情况修改:

cp vars.example vars

取消并修改以下选项:

set_var EASYRSA_REQ_COUNTRY     "CN"
set_var EASYRSA_REQ_PROVINCE    "Hongkong"
set_var EASYRSA_REQ_CITY        "Hongkong"
set_var EASYRSA_REQ_ORG         "52OS.NET"
set_var EASYRSA_REQ_EMAIL       "admin@52os.net"
set_var EASYRSA_REQ_OU          "52os Openvpn"

其它参数可以默认,也可以按需修改

初始化并创建ca根证书:

./easyrsa init-pki
./easyrsa build-ca

一路回车即可,ca证书需要输入密码,这个密码是给服务器端和客户端签名时用的
创建并签名服务器端证书:

./easyrsa gen-req server-ssl nopass
./easyrsa sign server server-ssl

同样一路回车即可
创建Diffie-Hellman证书,该证书主要作用是确保共享KEY安全穿越不安全网络:

./easyrsa gen-dh

创建并签名客户端证书:

./easyrsa gen-req client-ssl nopass
./easyrsa sign client client-ssl

所有证书文件:

[root@52os.net easyrsa3]# tree pki
pki
├── ca.crt    -->ca证书, server/client 都需要
├── certs_by_serial
│   ├── 01.pem
│   └── 02.pem
├── dh.pem    -->Diffie-Hellman证书,server端需要
├── index.txt
├── index.txt.attr
├── index.txt.attr.old
├── index.txt.old
├── issued
│   ├── client-ssl.crt    --> 客户端证书
│   └── server-ssl.crt    --> 服务器端证书
├── private
│   ├── ca.key
│   ├── client-ssl.key    --> 客户端私钥
│   └── server-ssl.key    --> 服务器端私钥
├── reqs
│   ├── client-ssl.req
│   └── server-ssl.req
├── serial
└── serial.old

三、配置openvpn服务器端和客户端

3.1 服务器端配置

openvpn的源码目录中已经有配置模版了,复制模版:

[root@52os.net openvpn-2.3.11]# cp   sample/sample-config-files/server.conf  /etc/openvpn/

复制证书文件:

[root@52os.net easyrsa3]# cp pki/ca.crt pki/issued/server-ssl.crt pki/private/server-ssl.key /etc/openvpn/

贴一份服务器端配置:

#openvpn监听本地ip地址,可选
;local a.b.c.d
#监听tcp或udp端口,如果有多个服务端,要设置不同的端口
port 1194
#tcp模式还是udp模式
proto tcp
#虚拟网络接口类型:1. TUN :路由模式,工作在三层,无物理地址,效率高;无法与物理网卡桥接,会无视广播包,客户端可以是TUN/TAP
#2. TAP :桥接模式,工作在二层,有物理地址,效率不如TUN;可以与物理网卡桥接,广播包可以通过,客户端必须是TAP
dev tun
#证书配置
ca /etc/openvpn/ca.crt
cert /etc/openvpn/server-ssl.crt
key /etc/openvpn/server-ssl.key
dh /etc/openvpn/dh.pem
#客户端使用的网段
server 10.8.0.0 255.255.255.0
#维持客户和ip的对应关系,重连后能保持虚拟ip
ifconfig-pool-persist ipp.txt
#为客户端推送路由,允许客户端访问其它网段
;push "route 192.168.10.0 255.255.255.0"
#设置所有客户端默认网关为VPN,所有流量经过vpn
;push "redirect-gateway def1 bypass-dhcp"
#为客户端推送DNS
;push "dhcp-option DNS 208.67.222.222"
#允许客户端之间互相访问
client-to-client
#允许多个客户端使用相同证书连接
duplicate-cn
#存活检测,每10秒检测一次,120秒未响应则认为连接丢失
keepalive 10 120
#对数据进行压缩,server和client 需保持一致
comp-lzo
#最大客户端数量
;max-clients 100
#重新连接时,不重新读取key和保持tun/tap设备在线
persist-key
persist-tun
#记录openvpn状态信息
status openvpn-status.log
#记录并追加日志
;log         openvpn.log
;log-append  openvpn.log
#日志级别
verb 5

前台启动,检查配置是否正确:

/usr/local/openvpn/sbin/openvpn --config /etc/openvpn/server.conf

如果启动没有错误,即可以daemon后台运行server:

/usr/local/openvpn/sbin/openvpn --daemon --config /etc/openvpn/server.conf

开启路由转发:

sed -i '/net.ipv4.ip_forward/s/0/1/' /etc/sysctl.conf
sysctl -p

防火墙策略配置:

允许vpn客户端所在网段流量转发到其它网卡:

iptables -I FORWARD -s 10.8.0.0/24 -j ACCEPT

将vpn客户端的流量转到eth0,允许vpn客户端上网,即NAT:

iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j  MASQUERADE

还需根据vpn服务器端的工作模式放开tcp/udp的1194端口,这个规则就不写了

3.2 客户端配置

客户端各系统下都有现成包,配置是通用的,我这里还是在linux下使用openvpn的客户端。

复制一份样板:

cp sample/sample-config-files/client.conf /etc/openvpn/

直接贴一份配置:

client
dev tun
proto tcp
remote openvpn.52os.net  1194
resolv-retry infinite
nobind
persist-key
persist-tun
ca /etc/openvpn/ca.crt
cert /etc/openvpn/client-ssl.crt
key /etc/openvpn/client-ssl.key
remote-cert-tls server
comp-lzo
verb 3

多个vpn client在不同的内网时,可以在client.conf中根据client的网段push路由,会比在server.conf中指定更方便
测试启动:

/usr/local/sbin/openvpn --config /etc/openvpn/client.conf 

启动:

/usr/local/sbin/openvpn --daemon --config /etc/openvpn/client.conf --log /var/log/openvpn.log

总的来说配置还是比较简单的