rsync实现dropbox-like目录监控自动同步

==== LAN sync ====

本文主要内容,如何利用rsync,lsyncd,ssh工具实现对目录的监控以及自动同步
主要分这么几块描述
先给出如何在局域网内实现以上功能
然后给出如何实现有代理的公司主机通过广域网和家里的本子自动同步
牵涉的内容有NAT,端口映射,SSH,HTTPS,代理相关内容,TPLINK配置

lsyncd的功能:
(1)开源软件lsyncd采用inotify原理监听某一目录,如果目录内发生增、删、改、利用rsync协议自动同步到多个服务器
(2)inotify,从kernel 2.6.13开始正式并入内核,RHEL5支持
(3)可以本地多点目录的监控并实现到远程目录的同步
(4) 在rsync client上通过lsyncd监控并推送数据给rsync server的rsync daemon,rsync server接收lsyncd推送过来的数据,并写入本地磁盘
(5)官方介绍:http://code.google.com/p/lsyncd
注意:而对于那种实时都在变化的数据(例如:数据库),那么这种数据的同步, DRBD 技术是一个更好的选择


本机在局域网内的IP是192.168.36.205
因为同步的数据传输是通过ssh实现的,首先,先把key弄好,这样就避免了每次都要输入密码的麻烦(password-less logins between two hosts)
按以下实现
1. 生成ssh public key,实现passwd-less logins:
yaoyi@localhost ~ $ ssh-keygen -N '' -f ~/.ssh/id_dsa
出现以下提示
Enter passphrase (empty for no passphrase):
<Enter>
Enter same passphrase again:
<Enter>
两个都回车
这样我们就在~/.ssh/下生成"id_dsa"和"id_dsa.pub",接下来将id_dsa.pub拷贝到要同步的主机上
ssh-copy-id -i ~/.ssh/id_dsa.pub yaoyi@192.168.35.155
其中的IP地址192.168.35.155,是局域网内的一台提供ssh服务的主机
拷贝完成之后,提示
Now try logging into the machine, with "ssh 'yaoyi@192.168.35.155'", and check in:
~/.ssh/authorized_keys
to make sure we haven't added extra keys that you weren't expecting.

试试看ssh yaoyi@192.168.35.155,这时候应该就不需要密码就能登录了

2.安装rsync和lsyncd
rsync应该都已经默认安装好了,而lsyncd,如果是archlinux则可以利用yaourt安装

3.配置lsyncd
原来的lsyncd用xml做配置文件,最新的版本用的是lua配置,具体参考这里http://code.google.com/p/lsyncd/wiki/Lsyncd20Manual
用lua的原因就是能和c很好整合,并且能替代完成c中的一些逻辑部分,而使c更注重和操作系统的交互,将其不擅长的比如垃圾回收,哈希表等交给lua处理

将lsyncd路径下/usr/share/doc/lsyncd/lrsyncssh.lua拷贝一份到任意位置比如/home/yaoyi/sync_conf.lua
其中字段修改如下
sync{default.rsyncssh, source="/home/yaoyi/sync_test", host="linyaoyi@192.168.35.155", targetdir="sync/"}

4. 在本机和服务器的$HOME下各自建一个测试目录sync_test和sync

5. 以非守护进程模式运行lsyncd,检查是否有错误
lsyncd -nodaemon /home/yaoyi/sync_conf.lua
输出信息
06:11:07 Normal: recursive startup rsync: /home/yaoyi/sync_test/ -> yaoyi@192.168.35.155:sync/
06:11:08 Normal: Startup of '/home/yaoyi/sync_test/' finished.
06:11:08 Normal: Finished Blanket on /home/yaoyi/sync_test/ = 0
06:11:39 Normal: Deleting list
sync//.beatme.swp
sync//.beatme.swpx
06:11:40 Normal: Finished a list = 0

6. 随意丢一些文件到目录中,看是否自动进行同步,注意输出,以及服务器同步目录的结果

7. 将lsyncd运行在后台模式下,监视目录
lsyncd /home/yaoyi/sync_conf.lua

到这里局域网内基本就可以跑通了.

==== 花生壳域名 ====

在描述外网对家访问的之前,先要把路由IP地址是动态变化的问题解决.
adsl拨号上网,是动态IP,所以几乎不可能由公司主机直接通过IP访问家中路由
花生壳域名是动态域名,提供将一个固定的域名映射到动态IP上,也就是说,我在公司的主机上只需要输入
ssh yaoyi@yaoyi011.gicp.net
花生壳的服务器就会帮忙解析到路由的IP上,从而公司主机关心的只是域名输入是否正确,而对应的IP是多少,就不需要留给花生壳的服务器处理.

如果您的路由器已经支持花生壳动态域名解析,请忽略在路由器配置自行设定,忽略这一步。

具体的操作步骤如下

1. 先在花生壳的官网进行注册,记住用户名和密码,之后在本机安装花生壳程序的时候需要

2. 在花生壳官网上下载相应的linux版本,并解压缩至phlinux_install目录中
  # cd phlinux_install
  执行安装脚本
  # ./install.sh
  执行安装脚本后,将自动以互动配置模式的phlinux程序
  输入web服务的地址,直接回车
  Runing phlinux for first configuration……
  Peanuthull Linux-core 1.0 by oray.net, copyright 2005

  No user configuration found, entering interactive mode automatically!

  Peanuthull Linux-core Interactive startup.

  Please input service address(press ENTER use phservice.oray.net):

  输入花生壳服务器地址,直接回车

  Please input server address(press ENTER use PH031.Oray.Net):

  此处提示输入您的花生护照登陆名

  Please input username(press ENTER use ):

  此处提供输入花生护照登陆密码

  Please input password:

  系统提示是否保存配置文件,在这里输入yes回车.

  Save to configuration file (/etc/phlinux.conf)?(yes/no):

  以上操作完成,系统将自动登录花生壳服务器,用户可以通过web方式查看当前花生壳客户端的运行状态.

  花生壳客户端使用 6160端口提供web检测服务,例如 http://192.168.0.1:6160/

  此监测页面将完全反应当前花生壳的运行状态.

好,如果监测页面正常,那就说明花生壳和花生壳服务器连接正常,并且能提供解析服务

在usr/bin/给phlinux建立一个软链接
并使该服务在后台运行
>>phlinux -d


==== WAN sync(主机在公网) ====

当然,利用lsyncd和rsync的目的是希望能将自己在公司主机上的数据同步回家里进行备份,所以光在局域网里可用是不够的

1.端口映射或DMZ主机
因为家里机子是通过路由连接到到公网
首先,路由本身就是一个NAT服务器,局域网内的多台主机能够共享一个IP上网,也就是基于这个NAT,NAT就是网络地址转换
网络地址转换(NAT,Network Address Translation)属接入广域网(WAN)技术,是一种将私有(保留)地址转化为合法IP地址的转换技术,它被广泛应用于各种类型Internet接入方式和各种类型的网络中。原因很简单,NAT不仅完美地解决了lP地址不足的问题,而且还能够有效地避免来自网络外部的攻击,隐藏并保护网络内部的计算机

而端口映射和NAT的关系是动态端口映射其实也就是NAT网关的工作方式
而静态端口映射: 就是在NAT网关上开放一个固定的端口,然后设定此端口收到的数据要转发给内网哪个IP和端口,不管有没有连接,这个映射关系都会一直存在。就可以让公网主动访问内网的一个电脑。
端口映射过程就如同:你家在一个小区里B栋2410室,你朋友来找你,找到小区门口,不知道你住哪层哪号?就问守门的保安,保安很客气的告诉了他你家详细门牌,所以你朋友很轻松的找到了你家。这个过程就是外网访问内网通过端口映射的形象比喻.
这个过程也就是NAT工作的接收部分,公网将数据包发送给路由器,然后路由器将依据包中的端口以及标识信息将数据包发送给相应的局域网内的主机

再举个动态端口映射发送部分,也就是NAT发送方式:内网中的一台电脑要访问新浪网,会向NAT网关发送数据包,包头中包括对方(就是新浪网)IP、端口和本机IP、端口,NAT网关会把本机IP、端口替换成自己的公网IP、一个未使用的端口,并且会记下这个映射关系,为以后转发数据包使用。然后再把数据发给新浪网,新浪网收到数据后做出反应,发送数据到NAT网关的那个未使用的端口,然后NAT网关将数据转发给内网中的那台电脑,实现内网和公网的通讯.当连接关闭时,NAT网关会释放分配给这条连接的端口,以便以后的连接可以继续使用。

好,那我们要访问家中的主机,就需要在路由器上做一个端口映射,使得我们在访问家中路由IP(即真实的公网IP)的时候,路由会自动转发到家中主机相应端口

路由器设置(TP-LINK):

转发规则->虚拟服务器
填写服务端口为22(sshd默认绑定在22口)
填写主机内网IP比如192.168.1.100
保存生效

这样的话,比如路由公网IP为58.56.66.76
外网某太主机A执行
A>ssh yaoyi@58.56.66.76

在/etc/ssh/下有sshd_config和ssh_config文件,ssh_config是配置client,其中port设置为22,意味着命令ssh yaoyi@58.56.66.76意在想要和该IP主机的22号口进行通信,
而sshd_config中配置port 22,意思是,作为提供sshd的server端,是监听在22端口的,显然,两台主机的ssh_config和sshd_config要匹配,这样才能进行有效的通信,即A主机监听在22端口,B也主动请求连接A的22端口

由于路由器端口映射的实现,所以访问路由IP 58.56.66.76,路由会自动将数据报转发到所设置IP的主机的22端口.

另外,如果要想局域网的主机被公网直接访问到,除了端口映射以外,还可以在路由器上将主机设置成DMZ主机,这样该主机就完全暴露在外网当中拉,至于什么是DMZ主机,自己google把


以上的分析不是针对只有http代理的公司内网主机访问家里主机的,而是一台没有限制的公网主机访问家里主机,以上的这些设置就足够进行ssh访问了
但是,倘若在公司内,所有数据包都统一通过代理与公网交互,并且代理只提供http服务,那就比较麻烦了

 

 

==== wan sync(主机在公司,且通过http代理访问外网) ====

比如当你在公司的电脑输入ssh -v yaoyi@yaoyi011.gicp.net,其中-v表示显示连接详细信息,输出如下
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: Applying options for *
debug1: Connecting to yaoyi011.gicp.net [121.204.47.200] port 22
debug1: connect to address 121.204.47.200 port 22: Connection timed out
ssh: connect to host yaoyi011.gicp.net port 22: Connection timed out

说明代理拒絶为ssh服务提供转发
首先我们需要proxycommand来辅助我们穿越代理,辅助的工具是corkscrew
在学校、公司大多时候都需要通过代理服务器上网,想在linux下通过代理服务器 ssh 的话可以使用 Corkscrew 小工具
下载 corkscrew-2.0.tar.gz 后解压编译,然后拷贝编译生成的 corkscrew 到用户的主目录下的 .ssh 中:
$ tar zxvf corkscrew-2.0.tar.gz
$ cd corkscrew-2.0
$ ./configure
$ make
$ cp corkscrew $HOME/.ssh/

打开 .ssh/config,增加以下几行:

$ vi .ssh/config

Host yaoyi011.gicp.net
ProxyCommand /home/yaoyi/.ssh/corkscrew proxy.server.address 8081 %h %p
TCPKeepAlive yes
ServerAliveInterval 5

注意:把上面的 yaoyi011.gicp.net 即是 ssh 的服务器地址(可以有多个,可以是域名也可以是 IP 地址);把 proxy.server.address 3128 换成相应的代理服务器地址和端口号,如;TCPKeepAlive 用来与 ssh 服务器保持连接。

ssh 服务器为了安全考虑发现客户端长时间闲置的话会主动断开 ssh 连接,如果不想 ssh 自动断开,ssh 客户端需要打开 TCPKeepAlive 选项定时给服务器发 TCP 包来欺骗服务器,让 ssh 服务器感觉客户端还在 “活动” 中。同时 ssh 服务器端也需要打开 TCPKeepAlive 选项(也就是说,ssh 客户端配置和 ssh 服务器端配置都要打开 TCPKeepAlive):

# vi /etc/ssh/sshd_config
TCPKeepAlive yes

 
好,在这些配置完成之后,再次运行
>>ssh yaoyi@yaoyi011.gicp.net
输出如下
OpenSSH_5.6p1, OpenSSL 1.0.0b 16 Nov 2010
debug1: Reading configuration data /home/yaoyi/.ssh/config
debug1: Applying options for yaoyi011.gicp.net
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: Applying options for *
debug1: Executing proxy command: exec /home/yaoyi/.ssh/corkscrew 192.168.9.25 8081 yaoyi011.gicp.net 22
debug1: identity file /home/yaoyi/.ssh/id_rsa type -1
debug1: identity file /home/yaoyi/.ssh/id_rsa-cert type -1
debug1: permanently_drop_suid: 1000
debug1: identity file /home/yaoyi/.ssh/id_dsa type 1
debug1: identity file /home/yaoyi/.ssh/id_dsa-cert type -1
Proxy could not open connnection to yaoyi011.gicp.net: Proxy Error ( The specified Secure Sockets Layer (SSL) port is not allowed. ISA Server is not configured to allow SSL requests from this port. Most Web browsers use port 443 for SSL requests. )
ssh_exchange_identification: Connection closed by remote host

这个意味着该代理只提供http或https转发服务,80是http端口,443是https端口,而ssh默认是绑定在22口,因此服务器拒絶转发.

那,就换一个思路,我们改变ssh的端口,让其伪装成443端口的数据,这样,代理就会给与转发了.
修改本机/etc/ssh/ssh_config,其中的port为443
修改家里主机/etc/ssh/sshd_config,其中的port为443
修改路由的端口映射,更改为443
这样便可以成功进行通信了.
在ssh正常之后,按之前局域网的方法通过lsyncd和rsync建立同步

另外/etc/services里面列出了服务的标准端口号,但更改端口并不是在这个位置

 

==== 接下来打算实现双向同步 ====

家里的两台主机,一台当做中转,家里的另一台主机以及公司的主机都通过ssh连接到中转机,然后在中转机上读写,实现家中主机对公司的访问

A机: 公司局域网(company)
B机:公网linux主机(public)
C机: 家里的notebook(home)

一、
A机:
company@localhostt:~$ ssh -CfNg -R 7001:localhost:22 username@B //A机和B机通过安全管道建立连接, B机监听本机7001端口,一旦该端口出现connection,就forward给A机,整个的连接是B机7001->B机443->A机443->A机22(为了躲避proxy故把A的ssh client和B的sshd&ssh端口号都改成443,否则正常是B机7001->B机22->A机22),22必须是A机sshd的监听端口号,因为443的secure shell已经建立,A机443->A机22只是本机端口转发,所以sshd监听的端口号可以任意配置,如可以是33,44,etc.

二、
C机:
home@localhost:~$ ssh -CfNg -L 7000:localhost:7001 username@B //将B机上的7001端口连至C机7000端口即C:7000->C:443->B:443->B:7001,整个管道就是C:7000->C:443:->B:443->B:7001->B:443->A:443->A:22

三、
C机:
home@localhost:~$ ssh -p 7000 Ausername@localhost //整个管道为C:7000->C:443->B->443->B:7001->B:443->A:443->A:22

ssh连接是有方向的,C是ssh发起方,C实现的是本地端口转发,将443数据转发给7000,再传输给B机7001
而A机创建的是远程端口转发,远程B机7001端口转发给B机443,并通过ssh client发回A机443口。

如果要启动图形程序,则server上需要修改/etc/ssh/sshd_config配置,取消以下注释
...
AllowAgentForwarding yes
AllowTcpForwarding yes
X11Forwarding yes
X11DisplayOffset 10
...

执行A机上的图形程序,比如 thunar,也可登录后执行
C机:
home@localhost:~$ ssh -X -p 7000 Ausername@localhost thunar
可能会出现如下提示

Xlib: extension "RANDR" missing on display "localhost:10.0".
The program 'thunar' received an X Window System error.
This probably reflects a bug in the program.
The error was 'BadWindow (invalid Window parameter)'.
(Details: serial 170 error_code 3 request_code 25 minor_code 0)
(Note to programmers: normally, X errors are reported asynchronously;
that is, you will receive the error a while after causing it.
To debug your program, run it with the --sync command line
option to change this behavior. You can then get a meaningful
backtrace from your debugger if you break on the gdk_x_error() function.)

将-X改成-Y通常就可以运行了,因为-X是secure X11-forwarding, -Y不是,故可以执行更多程序

当然稍微变通一下,如果B机和C机都在家,就不需要那么多繁琐的转发,可以直接再B机上访问A机
跳过第二步,第三步修改为
__public__@localhost:~$ ssh -p __7001__ Ausername@localhost
但是如果在C机上执行
__home__@localhost:~$ ssh -p __7001__ Ausername@B
则会提示如下错误
ssh: connect to host localhost port 7001: Connection refused
之前的所有连接其实都是通过443端口衔接起来的,但因为B机sshd监听的端口号是443,C机ssh直接访问7001一定是被拒绝的,所以要从C机访问,就必须配置端口转发,因为B:7001和C:7000转发的前提是B:443和C:443已经建立连接,也就是说
在C机上执行ssh -p __7001__ Ausername@localhost 是企图建立C:443和B:7001的直接连接,因为B机的sshd为443口提供服务,7001自然就被拒绝连接
在C机上执行home@localhost:~$ ssh -CfNg -L 7000:localhost:7001 username@B 是 建立C:443->B:443的连接,然后再此连接基础上,配置端口转发即C:7000->C:443->B:433->B:7001
这就是如果C机要访问A机,需要-R和-L转发的原因

而对于B机,执行__public__@localhost:~$ ssh -p __7001__ Ausername@localhost 本机上将443端口数据发送给7001,当然没有问题
另外,如果换成__public__@localhost:~$ ssh -p __7001__ Ausername@your_public_domain 就不行,因为默认要建立ssh连接,出错的理由同C机

附ssh命令参数

ssh是命令行工具,格式如下:

ssh [-1246AaCfghkMNnqsTtVvXxY] [-b bind_address] [-c cipher_spec]
[-D port] [-e escape_char] [-F configfile] [-i identity_file]
[-L port:host:hostport] [-l login_name] [-m mac_spec] [-o option]
[-p port] [-R port:host:hostport] [-S ctl] [user@]hostname [command]

主要参数:

SSH命令参数:

-a:利用这个参数,可以使转发的认证代理无效。其结果是使已装入内存的口令无效。如
果愿意,你也可以针对每台主机指定这个参数,而不是使其成为全程的设置。

-c cipher:可以通过这个参数为你的网上传输指定一个用来加密数据的密钥对。

-C:该参数将使ssh压缩所有通过Secure Shell客户端发送的数据,包括输入、输出、错误消息及转发数据。它使用gzip算法,压缩级别可通过设置配制文件中的参数Compressicn Level来指定。这对于缓慢的传输线路特别有用的。但对于传输速度已经很快的网络则显得没有必要。同样,你可以利用配制文件针对每台主机配置这个参数。

-f:该参数将ssh连接送入后台执行。这在验证已经完成且TCP/IP转发已经建立的情况下会生效,通常和-N一起用。这对在远程主机上启动X程序显得十分重要。其后用户将被提示要求输入口令(提供的认证代理不运行),然后将连接送往后台。

-g:该参数允许远程主机通过端口转发与主机端口相连,通常情况下仅允许本地主机这样做。

-k:这个参数使Kerberos转发功能无效。

-l login_name:这个参数指定你在远程主机上的登录用户名。默认情况下该用户名与你
在本地机上的用户名相同。它可以通过配置文件为不同的主机量体裁衣。这个参数是一个很
实用的参数,因为许多人在不同的主机上有着不同的用户名。

-L port:host:hostport这个参数转发在本地主机上的指定端口与远程主机上的指定端口
连接完成的信息。

-n :这个参数与-f参数类似。然而,在需要敲入口令时它将不会工作。标准输入由
/dev/null重定向而得到,当SecureShell客户端被送往后台时必须使用它。这个参数在用来发送X流量至远程主机时被普遍地使用。最好在使用该参数时启用认证代理。

-o option:在命令行参数未被定义时,该参数用来从配置文件中传递参数。这包括
StrictHostke yChecking和Use Rsh,它们没有自己的命令行参数。

-p port:可以指定哪个端口用作SecureShell客户端与服务器的连接。默认值为22,它为
SecureShell而保留。记住,除非特殊指定,用于服务器的端口号在/etc/services文件中定义。可以通过配置文件针对不同的主机而分别设置。

-P:使用大于1023的端口号(非特权的端口)。不能使用这些端口进行rhost认证。(无论是
它自身还是与RSA的组合)。

-q:这个参数选用哑模式。这意味着任何信息,包括警告与诊断信息都不会被显示出来。
在你碰到认证或连接问题时,最好关闭该模式。

-R port:host:hostport该参数转发远程主机指定端口到本地主机指定端口上的连接。它
和-L参数的工作过程刚好相反。套接字监听远程主机上的端口,只要针对该端口有一个连接,它将被转发到本地主机和主机端口。该转发端口可以在不同的主机上通过配置文件来进行不同的配置。特权端口只能在以超级账号登录到远程主机时转发。

-t该参数通过指定一个伪终端迫使SecureShell客户端以交互模式工作,即使在给定命令
的情况下也是如此。它被用于执行在远地主机上的基于屏幕的程序。

-V:该参数打印出客户端的版本号后退出。

-v :详尽模式。该参数使ssh打印出调试信息,在调试连接、认证及配置问题时该参数特
别有用。

-x:该参数用于X流量转发,X被公认为在启动时是不安全的,对安全敏感的站点最好设
置这个参数。该参数可以通过配置文件为每一台主机分别设置。

-N 不执行ssh命令即不登录到远程主机,这个对于只实现端口转发来说比较有用

posted @ 2012-01-06 23:50  linyaoyi  Views(1544)  Comments(0)    收藏  举报