通过代理使用 GitHub

Git 是非常好用的开发工具,越来越离不开了。 如果要与他人合作项目,GitHub 是很好的平台。 但如果身处受限网络,要管理 GitHub 上的项目, 还是要费一番周折的。

GitHub 网页访问应该不用说了,工具多得是。 我要说的是对项目进行管理,比如 push/pull 操作等。

最简单的方式是通过 https_proxy,比如:

export https_proxy=http://127.0.0.1:8087

然后将仓库地址改为 HTTP 方式。

虽然简单,但有一点不方便,就是进行写操作时, 比如 push ,会需要手工输入用户名和密码, 而不是 GitHub 常用的证书自动认证。

更好的方法还是走 ssh 协议代理, 这需要一个软件 connect-proxy。 Ubuntu 下可以通过 Apt 安装, ArchLinux 下要通过 AUR 安装( 包地址 )。

先要有 Socks 代理,通常,可以使用无限制网络的 VPS, 然后使用 ssh 打个隧道:

# Native ssh
ssh -D 127.0.0.1:22888 -CfNg domain.tld -o ControlPath=/tmp/ssh-22888-domain.tld
# OR
# 使用 authssh 更方便
autossh -M 0 -D 127.0.0.1:22888 -CfNg domain.tld -o ControlPath=/tmp/ssh-22888-domain.tld

可以 telnet localhost 22888 检查通不通。

然后,在 $HOME/.ssh/config 中添加一段:

Host github.com
    # On Ubuntu
    ProxyCommand /usr/bin/connect-proxy -S 127.0.0.1:22888 %h %p
    # OR
    # On ArchLinux
    ProxyCommand /usr/bin/connect -S 127.0.0.1:22888 %h %p

-S 参数如果换成 -H ,就是使用 http 代理, 效果应该和上面的简单方法一样。

最后,将仓库地址改为 SSH 方式。 现在,本地 GitHub 仓库中 push 操作就正常了,简单测试一下 GitHub 登录:

$ ssh -T git@github.com
Hi fwolf! You've successfully authenticated, but GitHub does not provide shell access.

配置安全的共享web服务器(抛砖引玉)

本文所讲的共享web服务器,并非共享文件的服务器,而是多人一起使用的web服务器,各有各自的网站、管理自己的文件,互不干涉,且对系统无影响。鉴于功力较浅,只敢对较信得过的朋友开放这种账号,本文涉及的范围也有限,所以安全漏洞可能还有,请诸位切勿直接用于生产环境。

服务器环境:Ubuntu 8.10, OpenSSH_5.1p1 Debian-3ubuntu1, Apache 2.2.9, PHP 5.2.6-2ubuntu4

登录 – SFTP

传统的 FTP 肯定是不如这个安全,telnet 更不用说了。使用 SFTP 还有一个起始想法是想配置证书自动登录,后来发现 SFTP 客户端(FileZilla)没这功能,就没再作下去,命令行下 scp 的自动登录倒是 和 ssh 的一样很好配置。

网上很多文章介绍把 sftp 用户限制在 $HOME 目录下的方法,使用的是 sshd 的 ChrootGroups 选项,这个选项在我的版本里没有找到,找到另外一篇参考文章使用的是 ChrootDirectory,也很好用。

创建一个用户组,作为所有 sftp 用户的用户组:

$ sudo groupadd sftp

创建用户,设置密码,并归入 sftp 组:

$ sudo useradd -m friend
$ sudo passwd friend
$ sudo usermod -g sftp friend

为了进一步增强安全性,还可以将用户的登录 shell 设置为 /bin/false,是个好习惯,但在本例中并非必须,下面的 sshd 设置也会让用户无法登录 shell (我观察的结果)。

$ sudo usermod -s /bin/false friend

下来就要配置 sshd 了,编辑配置文件 /etc/ssh/sshd_config

# 修改下面这句
#Subsystem sftp /usr/lib/openssh/sftp-server
Subsystem sftp internal-sftp

然后在此配置文件末尾添加:

Match group sftp
    X11Forwarding no
    ChrootDirectory %h
    AllowTcpForwarding no
    ForceCommand internal-sftp

配置含义大概为:凡是 sftp 组的用户,关闭 X 转发,chroot 到 $HOME 目录,关闭 TCP 转发(无法使用隧道了?),强制使用 internal-sftp(这个不明白)。

现在,重启 ssh 服务,用户就只能通过 sftp 访问 /home/friend 下的文件了。

PS: 我发现 sshd 如果配置错误,在 restart 服务的时候会先检查,而不是直接 stop 服务然后在 start 的时候出现错误,搞得服务启不来。大概是考虑到很多人都是远程 ssh 上来进行维护,服务 down 了以后就麻烦了,很贴心的设置。

Apache & PHP

Apache 配置简单,创建 /home/friend/www 目录,约定网站文件都放在这个目录下,然后弄个 Alias 指向就可以了。

但有一个极大的安全隐患需要堵上,用户可以通过编写 PHP 程序,读取系统中任何 www-data 用户有权限访问的文件,包括系统的 shadow 文件,包括 其它用户的网站文件等等。解决这个问题,一种是开启 PHP 的 safe_mode ,安全模式下 PHP 将只能访问 owner 为自己(也就是 www-data)的文件;另外一种是使用 open_basedir,这将限制 PHP 只能打开某一目录树下的文件,并且不可能通过符号链接避开此限制。显然 safe_mode 的副作用太多,后一种方法更适合我的这种情况,配置写到 Apache 的 conf 里就行了:

<Directory /home/friend>
    php_admin_value open_basedir "/home/friend/"
</Directory>

注意open_basedir 后面的参数只代表文件路径的前缀,所以要带上末尾的斜杠,明确指出是目录。

不使用 safe_mode 的另外一个原因是在未来的 PHP6 里就要删掉它了。

缺点

最大的缺点就是 sftp 用户无法自己更改密码,除非自己写个守护程序啥的。这个程序在写的时候要非常小心,因为操作的是系统用户文件,如果遗留有安全漏洞可能会使别人获得其它用户权限。一个折中的方法是写个程序,定期更改密码并通过邮件告知用户,虽不方便但安全性要好一些。

用ssh打通反向隧道,内网也可对外提供服务

一般正规一点的网络环境,大多是这样的:防火墙后分为内网和中立区(DMZ),并且内网和DMZ虽然都能访问外网,互相却是无法直接访问的。内网和DMZ的区别就是,来自外网的访问,都通过防火墙上的规则映射到DMZ里的服务器上,而内网一般是不允许这样的。

现在需要解决的问题就是,在防火墙只能给DMZ开端口,内网和外网不可直接互访的情况下,如果让内网的机器对外提供服务。

ssh是很神奇的,使用它创建的隧道,可以起到代理的作用,数据流的方向是:

本机 -> 隧道 -> 外网

应用到我们的问题中,如果把隧道反过来,就是:

外网 -> DMZ -> 隧道 -> 内网

这就需要用到ssh的反向隧道,它在服务器上打开一个监听端口,这个端口的访问会被隧道传输到本地,结果再通过隧道传到服务器上,从监听端口返回给客户。这样,在我们的应用中,内网机器通过外网访问DMZ服务器,创建ssh反向隧道,就能够对外提供服务了。当然,防火墙上要将相应端口映射到DMZ的服务器上。

比如,在内网登录DMZ服务器:

ssh -R 8082:localhost:82 fwolf@svr5.tld -o ControlPath=/tmp/ssh_svr5_reverse_tunnel

这样,访问DMZ服务器svr5的8082端口,就是在访问本机的82端口。之所以带上-o ControlPath,是为了和其它访问svr5的进程使用不同的master模式(如果不是第一次创建这个master,而是使用了原来的连接的sockts,肯定就不会创建隧道了)。

有几个问题还需要注意一下:

  • 如果DMZ上监听端口小于1000的话,就必须用root用户登录DMZ服务器,比如root@svr5.tld
  • DMZ服务器上的sshd必须开启GatewayPorts选项,在文件/etc/ssh/sshd_config中加入GatewayPorts yes
  • 记得不要idle,参考中有在服务端设置的方法。
  • 如果放在其它脚本,比如/etc/rc.local中执行的话,除了配置自动登录,还可以带上-fN参数,放到后台去。

参考

Update @ 2008-07-25

注意,由于使用了反向隧道,所以ssh隧道实际作用相当于一个代理,访问的来源也自然就都成了127.0.0.1,如果同时还启用了denyhosts,千万记得要把本机地址127.0.0.1放入白名单/etc/hosts.allow,不然就会成为其他登录失败的牺牲品(失败的登录,其来源也成了loopback的地址):

ssh_exchange_identification: Connection closed by remote host
Fatal error: Lost connection with the server

没办法,为了网络通道的畅通,只能牺牲一部分安全性了。

ssh的连接重用

原理很简单,开一个ssh连接在后台放着,以后再有需要用到ssh到同样主机的时候,直接使用这个连接的socket文件,不用再创建连接了,同理,也不需要再进行用户身份验证。

默认是关闭的,可以在~/.ssh/config中打开:

Host *
    ControlMaster auto
    ControlPath ~/.ssh/master-%r@%h:%p

创建“Master”连接就可以用:

ssh -M -N -f fwolf.com

认证成功后会创建socket文件master-fwolf@fwolf.com:22

其它的介绍资料也很多,我是在邮件列表中看到的,惭愧,使用ssh很久了,现在才知道,网上用ssh master ControlMaster搜索资料很多。

实际使用中,我倒有一个反面的感觉,创建了“Master”之后,一般的scp什么的操作的确是快了,可如果单独开一个ssh terminal上去的话,输入的响应速度很变慢。开始以为是这个ssh连接也重用了“Master”的原因,后来加上-o ControlMaster=no参数强制不使用Master,单独创建新连接也是一样,不知道是什么原因导致的。

仔细测试一下效果,首先在已经创建Master的情况下连接主机,执行命令并马上退出:

$ time ssh fwolf.com -C pwd

执行多次,得到的执行时间一般在0.33秒左右,然后关闭Master,再次执行这个命令,平均执行时间为6.7秒,的确是快了许多。

后来才发现,刚才对响应速度“慢”的感觉应该是错误的,可能是由于另外开着一个scp的缘故,scp完成之后,速度就快很多了。之所以会感觉“慢”,其实也是相对而言的,因为单独ssh连接上去之后,也是不中断的持续连接、持续响应,同样没有重新建立连接的时间,速度也是非常快的。开启Master主要对那些一会儿连接、一会儿断开,请求断断续续的情况最有效果。

另外,还有两个比较有用的相关控制命令:

# 检查当前是否已经创建Master连接
$ ssh fwolf.com -O check
Master running (pid=6350)

# 发送断开当前Master连接的请求,比我用的笨kill方式好多了
$ ssh fwolf.com -O exit
Exit request sent.
$ ssh fwolf.com -O check
Control socket connect(/home/fwolf/.ssh/master-fwolf@fwolf.com:22): No such file or directory

参考

Accelerating OpenSSH connections with ControlMaster

用unison来同步你的远程文件夹

不知不觉从邮件客户端切换到使用web的gmail已经很久了,以前使用客户端时的习惯早以丢弃了,同时还养成了把gmail当作工作台的习惯 :)。不过时间流逝,以前只能在公司上网(速度快)收发邮件,现在家里的宽带也不错,同时工作越来越忙,很多时候都要在家里处理一些事情,那么,如果我在公司用mutt把邮件都收下来了,在家里怎么才能看到呢?有没有一种软件能够让我同步公司和家里两台电脑上的maildir目录呢?

答案当然是肯定的,不过不是rsync,rsync只能用来单向传输数据,可如果我在家里收、发了邮件,我希望回到公司之后也能够继续处理,所以我需要双向传输。顺藤摸瓜,就又找到了unison这个好东西,它可以实现双向传输,并且为了节省带宽,只传输变动了的文件,甚至还能够在不同文件系统之间同步。

安装:

apt-get install unison

我安装的版本为2.13.16,不过据unison的官方网站介绍,它已经不再作新的开发了,只是继续维护和小的改进,原来的创始人Benjamin C. Pierce现在在带头搞Harmony,另外一个更广泛意义上的同步工具,不过查了下harmory的资料太少了,并且ubuntu的源中也没有,所以还是先用着unison吧。

直接运行一下unison,就会创建空的配置文件$HOME/.unison/default.prf了,unison的配置文件很有意思,默认的叫default.prf,还可以任意创建多个单独的配置文件(在unison文档中,这些被叫做preference file),在调用的时候,可以指定不同的配置文件,这一点还是非常方便的。

现在,我来创建一个配置文件mail2home.prf,用来同步家里和公司电脑上的$HOME/mail目录,就是mutt的邮件存储目录,内容如下:

# Unison preferences file
# Sync between these too folders
# .prf file cannot recoginize ~, and NOTICE // in ssh address
root = /home/fwolf/
root = ssh://address_of_company_pc//home/fwolf/

# Only process these sub-directories
path = mail
path = .muttrc
path = .unison/default.prf
path = .unison/mail2home.prf

# Include another perference file(.prf)
#Include foo

# ignore all .mp3 files anywhere
ignore = Name *.mp3

# ignore all files with .unison somewhere in their full path
#ignore = Path .unison

# Fastcheck can be open if both side are linux
#fastcheck = yes

log = true
logfile = /home/fwolf/log/unison.log

# imports settings from default.prf
include default

这样,我就可以用一行命令来同步邮件了,注意同步的两台电脑上都要安装unison:

#测试一下。。。
unison mail2home -testserver
#正常运行,有文件需要传输时会提示
unison mail2home
#批模式运行,没有需要merge的情况就不提示啦
unison mail2home -batch

unison通过在$HOME/.unison下创建控制文件来记忆两端的文件状态,并且控制文件在同步的两端也是同步的,所以如果这个文件变得庞大无比,在一次全部同步并保证两端都暂时不会改变的情况下,应该可以删除这个控制文件并且重新开始同步。注意我还没遇到过这种情况,也没有测试过是否可行。

同步位置中有ssh地址时,会提示用户输入ssh的密码,如果ssh能够配置为使用key登录,应该就更方便了,也可以放到cron中定时执行了。

unison同步的速度还是很快的,不过要注意使用-batch同步的时候,一般是以文件最后修改时间来判断覆盖关系的,所以一是要让两端电脑的时间都别太错得离谱,二是记得要使用其他手段备份重要数据!

参考一参考二参考三

hmm…下一步打算注册个大米到gfans论坛玩玩,如果顺利的话,就可以全面启用mutt咯。

Update @ 2008-03-09

发现在path = ???中不能使用表示上级目录的../,加上以后带../的这个文件是同步了,可其它文件却被unison跳过了,如果再加上表示当前目录的.,成了./../以后就更离谱了,差点把我的硬盘全部扫描一遍。

但是部分在replica之外的文件怎么办呢?有一个变通的办法,ln -s到replica目录下,也就是在两个root的目录覆盖范围之下,千万不要再用../了,然后在prf文件中添加:

follow = Name mail_archived.prf
或者
follow = Path links/book

这个例子中,replica定义的是root = /bak/mail,而mail_archived.prf位于/home/fwolf/.unison/下,所以link文件就是:/bak/mail/mail_archived.prf -> /home/fwolf/.unison/mail_archived.prf

注意,如果link在某端的replica中不存在,需要事先创建好,然后就可以通过unison同步了,因为follow=让unison像真实文件一样对待link文件,不存在的话会被同步出一个实体文件来。