利用ssh隧道解决登录vps服务器慢的问题

0. 背景

linode的vps在某些网络下访问比较慢,甚至还有丢包的情况。但是从国内的服务器ping过去,一切正常。之前听说过ssh端口转发及隧道特性,于是考虑在通过正常的国内服务器去登录vps。

1. 传统做法

先登录稳定服务器,然后在上面再通过ssh登录到目标机器。虽然简单直接,但这样的缺点也显而易见,证书管理不方便。

2. SSH隧道方式

这里是基于稳定服务器将vps的端口转发到了本地。

step1 先登录稳定服务器
ssh -L 36000:VPS-IP:22 稳定服务器IP
这里通过稳定服务器,将VPS的22端口转发到了本地的36000端口

step2 登录本地端口
ssh -p 36000 localhost
由于是转发,这里之前在VPS上配置的证书依然可以使用,只是换了一个端口和IP而已。

3. 其他使用场景
本地端口转发还有一个比较实用的场景,就是可以将服务器的内网端口转发到本地。比如,有些开发同学习惯通过本地的IDE连接远程的mysql,这样将数据库的远程访问权限打开有一定安全隐患。体验下另外一种方式:

# 先将远程服务器的192.168.2.110:3307端口映射到本地33070
ssh -L 33070:192.168.2.110:3307 跳板机IP

#登录本地33070端口,注意将host指定为127.0.0.1
mysql -P 33070 -h127.0.0.1 -uusername -p'password'

4. 其他转发方式

除了将远程端口转发到本地(Local Forwarding),还有两种方式:
– 动态端口转发(Dynamic Forwarding)
ssh -D [bind_addr]:port user@server
适合代理方式

– 远程端口转发(Remote Forwarding)
ssh -R [bind_addr]:port:host:hostport user@server
相当于将host:hostport映射到了server:port上

5. 参考资料
SSH端口转发以及应用实例
三种不同类型的ssh隧道
SSH隧道简洁介绍以及SSH隧道实际应用
实战ssh端口转发

将博客转回了wordpress

当初选择drupal是因为它是一个CMS系统,除了blog以外还有其他扩展功能。但是一直以来就使用了blog的功能,而且模块、系统的更新比较频繁,有些是有安全更新。稍不注意,就会错过几个重要更新。最近帮同学搭建了一个团队博客,试用了wordpress,给人耳目一新的感觉。于是就考虑转换。

之前从wordpress转到durpal的时候,有一个免费的模块,很方便;wordpress插件中心虽然也提供转换服务,但是第三方收费的。所以考虑升级sql的方式,有两种版本(23),其实大同小异,我采用的是方法3,不过有几个地方需要注意:

– 那不是个可执行的sql文件,需要将行首的#替换成–
– 需要将comment_parent置为1
– 需要指定博客作者
– 我这里term_data.vid为1的是分类,其他的是tag,创建分类时需要指定下
– 由于是多行,可以在phpMyadmin里直接执行sql

另外,
为了兼容之前的地址,我将rewrite规则也改成了node/xxx形式。

enjoy it!

参考链接:
Drupal 转 WordPress
Drupal to WordPress migration

在同一个mysqld上运行多个端口

服务器的3306端口上已经运行了一个mysql服务,配置文件位于默认的/etc/my.cnf下,现在需要再开一个端口运行mysql服务,希望能重用当前mysql的配置(修改某项共用配置时只需要修改一处即可)。

网上有一篇通过mysqld_multi在同一个mysql下运行多个示例的文章,它是在配置文件的[mysqld_multi]里指定程序路径,[mysqld1]、[mysql2]里分别指定相应的配置。但我还是想直接通过mysqld_safe方式启动,不想在公共配置里指定每一个datadir目录。经过一番摸索,可以这样做:

0. 当前默认端口3306的配置和启动方式:

/etc/my.ini中的配置:

[client]
port        = 3306
socket      = /tmp/mysql.sock

[mysqld]
port        = 3306
socket      = /tmp/mysql.sock

通过如下方式启动

cd /usr/local/stow/mysql-5.0.51a-linux-i686-icc-glibc23
./bin/mysqld_safe 

1. 配置3307端口mysql

1.1 创建数据库

cd /usr/local/stow/mysql-5.0.51a-linux-i686-icc-glibc23
./scripts/mysql_install_db --datadir=/home/zhouguoqiang/tmp/mysql_3307/data

不必理会其中的warning、ERROR信息。此外,如果没有特殊说明,下文均是在当前目录下操作。

1.2 指定3307专有的配置

编辑文件/home/zhouguoqiang/tmp/mysql_3307/my.cnf,添加如下内容:

[mysqld]
port		= 3307
socket		= /tmp/mysql_3307.sock
datadir		= /home/zhouguoqiang/tmp/mysql_3307/data
innodb_data_home_dir = /home/zhouguoqiang/tmp/mysql_3307/data
innodb_log_group_home_dir = /home/zhouguoqiang/tmp/mysql_3307/data

注意,如果使用了innodb类型的数据库或者/etc/my.cnf里指定了innodb目录相关的参数,这里一定要重新指定成适当位置,否则将会共用3306中的innodb_data_home_dir和innodb_log_group_home_dir,进而导致3307端口的mysql启动失败(没有权限或者文件被锁)。

1.3 启动3307端口的数据库

./bin/mysqld_safe --defaults-extra-file=/home/zhouguoqiang/tmp/mysql_3307/my.cnf

需要注意的是,还有一个参数–defaults-file,二者是有区别的:

–defaults-file
加载指定的配置文件,将会完全覆盖/etc/my.cnf中的配置
–default-extra-file
加载配置文件中指定的项,不会完全覆盖/etc/my.cnf中的配置。如果同时在/etc/my.cnf中配置过,将会优先使用指定配置文件里的。

1.4 访问3307端口的数据库

由于默认是3306端口,因此需要指定端口号

mysql -uroot -P 3307 -h 127.0.0.1

必须指定-h,而且不能使用localhost

1.5 停止3307端口的数据库

 mysqladmin  -uroot -S /tmp/mysql_3307.sock shutdown 

参考资料:

  • http://hi.baidu.com/baoobaoo/blog/item/3bd94f2a9432dc3c5343c199.html
  • http://dev.mysql.com/doc/refman/5.1/en/option-files.html

mysql重启后Incorrect information in file相关的错误

修改完/etc/my.cnf的配置一直没有重启,今天重启了一下,看似一切正常,但是却没法访问原有的数据表,出现类似的提示:
Incorrect information in file: ‘./DATABASE_NAME/TABLE_NAME.frm’

仔细查看mysql的错误日志文件,发现提示ib_logfile0文件大小设置不正确:

InnoDB: Error: log file ./ib_logfile0 is of different size 0 5242880 bytes
InnoDB: than specified in the .cnf file 0 268435456 bytes!

下面即时具体受影响的数据表信息。

显然mysql启动时会对比ib_logfileN和配置里设置的文件大小,可见是我更改innodb_log相关的配置导致的:
> innodb_log_file_size = 256M
> innodb_log_files_in_group = 3
< innodb_log_file_size = 5M < innodb_log_files_in_group = 2

改回以前配置就没有问题了。

另外,把相应的ib_logfile删除了,启动时也可以再生成一份。

参考:
http://forums.mysql.com/read.php?22,181434,181701
http://sech.javaeye.com/blog/462740

导出导入数据表中部分记录的方法

今天犯了一个很低级的错误,通过命令行恢复一个mysqldump出来的很大的文件时,由于没有没有将它放到后台进行,运行几个小时之后突然由于超时而中断与远程服务器的连接了。幸好可以通过SQL语句导出导入部分记录的数据:

导出:

SELECT * FROM park_log WHERE pl_id > 51025594 INTO OUTFILE '/tmp/apps_park_log_51025594.txt';

导入:

 LOAD DATA INFILE '/data1/apps_park_log/xB' INTO TABLE park_log;

yejr曾经测试比较,LOAD DATA比导入SQL文件快,但由于LOAD DATA必须所有操作进行完之后才向数据库里写记录,所以有时候往往会感觉LOAD DATA比较慢。我刚操作一个数千万行的文件时,还以为程序没有工作而手动中止了。真是一个活生生的例子。

tcp_window_scaling导致的windows服务器回应迟缓问题

工作遇到了一个奇怪的现象:windows下访问某个IIS服务器没有问题,有的Linux也可以正常访问,但有的Linux访问时,服务器回应十分迟缓。

后来在bbs里有人让我参考kernel相关的一篇文章,原来自从内核2.6.17版本后TCP window scaling的变动导致无法访问某些路由器。

我进行如下设置,解决了问题:
echo 0 > /proc/sys/net/ipv4/tcp_window_scaling

UTF-8、BOM、的问题

有些编辑器,比如M$ Windows的记事本,在创建UTF8编码文件时会在头部添加一个不可见字符。这个字符可以通过vim查看到,而且如果是一个php文件,php4、php5在解析时均会有输出。

原来这个被称作BOM(Byte Order Mark)的不可见字符,是Unicode用来标识内部编码的排列方式的,在UTF-16、UTF-32编码里它是必需的,而在UTF-8里是可选的。因此,才会出现有的编辑器在文件头部添加添加BOM、而有的语法解析器又不作处理的的混乱情况。

根据w3c里FAQ的建议,解决方法就是,删无赦!

btw, 刚才无意中发现,PHP 5.2.5的命令行下去除了BOM的显示,而 PHP 5.2.6确又显示出来了。

参考:

Pure-FTPd配置笔记

以前曾用过Pure-FTPd提供的ftp服务,作为ftp的服务器端,其类似linux下useradd/usermod/passwd工具的用户管理方式,令人印象深刻。最近正好需要配置一台ftp服务器,当然首选这款有良好安全性口碑的Pure-FTPd。

基本需求是这样的:
虚拟用户 – 也就是说提供的ftp用户在系统里并不存在
权限 – 每个用户对自己目录拥有读写权限,但不允许访问其他目录
虚拟目录 – 每个用户目录下面需要添加一个只读的公有目录

以下为配置过程:
1. 安装
当前最新版本为1.0.21,可从官方网站下载。
wget http://download.pureftpd.org/pub/pure-ftpd/releases/pure-ftpd-1.0.21.tar.gz
tar zxvf pure-ftpd-1.0.21.tar.gz
cd pure-ftpd-1.0.21
./configure --prefix=/usr/local/stow/pure-ftpd-1.0.21 --with-puredb
make
sudo make install

其中,--with-puredb 选项代表虚拟用户支持

2. 创建用户
出于安全以及管理方便,我们让虚拟用户共享同一个系统用户。
首先,在系统中添加相应的用户和组,这里以ftpuser和ftpgroup为例:
/usr/sbin/groupadd ftpgroup
/usr/sbin/useradd -g ftpgroup -d /dev/null -s /etc ftpuser

创建虚拟用户的命令是这样的:
pure-pw useradd smzz -u ftpuser -d /home/ftpusers/smzz -m
其中, -u将虚拟用户 smzz 同系统用户 ftpuser 关联在一起。-d参数使 smzz 只能访问其 home 目录。而如果想让他访问整个文件系统,可以用 -D 选项。

此外,pure-pw useradd 的选项还有:

-t 下载带宽限制
-T 上传带宽限制
-n 最大文件数目
-N 磁盘配额(单位M)
-q 上传速度限制
-Q 下载速度限制
-r 允许某些ip/网段的客户端访问
-R 拒绝某些ip/网段的客户端访问
-i 允许本地某些ip/网段访问(allow local host)
-I 拒绝本地某些ip/网段访问(deny local host)
-y 同时最大连接数目
-z 允许连接服务器的时间段,格式hhmm-hhmm,如 -z 0412-1618代表用户只能在凌晨4点12分至下午4点18分连接服务器
-f passwd_file
-F puredb_file
-m

2. 更改用户
pure-pw adduser 唯一不同的是,使用 pure-pw usermod 不是创建一个用户,而是更改已经存在用户的某些属性。
如果想禁用某些属性,可直接添加空值,比如pure-pw usermod -n ''代表不限制文件数目

3. 更改密码
pure-pw passwd smzz -m
所有这些参数都有一个共同选项 -m ,它代表修改完毕之后不必重启Pure-FTPd以及重新生成puredb_file文件

此外,还有类似userdel命令的子选项pure-pw userdel

4. 提交更改
所有用户操作必须提交更改,方能生效。目前有两种形式
a) 通过pure-pw mkdb重新生成数据文件(/etc/pureftpd.pdb)
b) 用户操作时带上-m选项,比如 pure-pw passwd smzz -m

5. 开启服务
/usr/local/sbin/pure-ftpd -j -lpuredb:/etc/pureftpd.pdb &
其中,-j代表用户第一次登录将会创建自己的home目录,-l代表验证方式
此外,匿名、配额、发呆设置、日志文件等选项均可通过相关参数在pure-ftpd启动时设置

6. 虚拟目录
Pure-FTPd并不支持类似windows下ftp服务器那样的虚拟目录,但可以通过其他方式变相实现,比如
mount --bind /home/my_apps/lib /home/ftpusers/smzz/lib

todo:
pure-ftpd的诸多参数

参考:
man pure-ftpd
man pure-pw
pure-ftpd用户管理

vim远程修改文件产生的安全隐患

刚才无意中通过浏览器看到了wordpress配置文件里的信息了,现在想想仍心有余悸。

如果你像我一样,将vim作为首选编辑器;如果你也像我一样,有时候需要远程修改文件。那么,请注意了,通过vim远程修改文件,可能会产生~结尾的备份文件,由于服务器一般都无法解释~后缀文件,这将把代码泄露给客户端。如果巧好是某个配置文件,后果更是不堪设想。

解决方法:
1. 通过设置nobackup和nowritebackup参数,取消vim的自动保存功能
2. 让web服务器解释~后缀文件

gmail也有打盹的时候?

Google的服务一向以稳定而著称,但我却看到了gmail在打盹。

刚才打开浏览器,通过Gmail Notifier 插件登录gmail。其实我以前保存了密码,但它却提示我验证失败,于是我输入密码重新登录。一串提示性的文字一闪而过,大意是说我的网速慢之类的。此后本来应该显示熟悉的gmail首页,但是紧接着却出现了白底黑字的javascript代码,还以为是我搞错了,重新打开一个标签登录,依然如此。

gmail source
具体代码如下(为了便于阅读,我删除了其中的空行):

var BrowserSupport_ = {
IsBrowserSupported : function() {
var agt = navigator.userAgent.toLowerCase();
var is_op = (agt.indexOf("opera") != -1);
var is_ie = (agt.indexOf("msie") != -1) && document.all && !is_op;
var is_ie5 = (agt.indexOf("msie 5") != -1) && document.all && !is_op;
var is_mac = (agt.indexOf("mac") != -1);
var is_gk = (agt.indexOf("gecko") != -1);
var is_sf = (agt.indexOf("safari") != -1);
if (is_ie && !is_op && !is_mac) {
if (agt.indexOf("palmsource") != -1 ||
agt.indexOf("regking") != -1 ||
agt.indexOf("windows ce") != -1 ||
agt.indexOf("j2me") != -1 ||
agt.indexOf("avantgo") != -1 ||
agt.indexOf(" stb") != -1)  {
return false;
}
var v = BrowserSupport_.GetFollowingFloat(agt, "msie ");
if (v != null) {
return (v >= 5.5);
}
}
if (is_gk && !is_sf) {
var v = BrowserSupport_.GetFollowingFloat(agt, "rv:");
if (v != null) {
return (v >= 1.4);
} else {
v = BrowserSupport_.GetFollowingFloat(agt, "galeon/");
if (v != null) {
return (v >= 1.3);
}
}
}
if (is_sf) {
if (agt.indexOf("rv:3.14.15.92.65") != -1) {
return false;
}
var v = BrowserSupport_.GetFollowingFloat(agt, "applewebkit/");
if (v != null) {
return (v >= 312);
}
}
if (is_op) {
if (agt.indexOf("sony/com1") != -1) {
return false;
}
var v = BrowserSupport_.GetFollowingFloat(agt, "opera ");
if (v == null) {
v = BrowserSupport_.GetFollowingFloat(agt, "opera/");
}
if (v != null) {
return (v >= 8.0);
}
}
if (agt.indexOf("pda; sony/com2") != -1) {
return true;
}
return false;
},
GetFollowingFloat : function(str, pfx) {
var i = str.indexOf(pfx);
if (i != -1) {
var v = parseFloat(str.substring(i + pfx.length));
if (!isNaN(v)) {
return v;
}
}
return null;
},
tz_path : ';path=/'
};
if (window.location.href.toLowerCase().indexOf('google.com') > 0) {
BrowserSupport_.tz_path += ';domain=.google.com';
}
document.cookie = "TZ=" + (new Date()).getTimezoneOffset() +
BrowserSupport_.tz_path;
var is_browser_supported = BrowserSupport_.IsBrowserSupported();

仔细看了一下页面上的代码,主要是对域名、时区以及浏览器的兼容性做判断的。值得一提的是它还对pda、sony/com2、safari以及opera等客户端作了专门的判断。

用工具查看页面的http信息,如下:

Etag: "hyuaanj8ksp6"
Last-Modified: Fri, 05 Sep 2003 02:11:15 GMT
Content-Type: text/javascript; charset=UTF-8
Cache-Control: private
Expires: Fri, 21 Dec 2007 15:12:16 GMT
Content-Encoding: gzip
Content-Length: 684
Server: GFE/1.3
Date: Sat, 01 Dec 2007 15:12:16 GMT

200 OK

与此同时,我访问了google提供的企业邮局,则显示正常。