SSH, SCP 不输入密码

On 2009/12/16, in Linux, by admin

经常在不同linux机器之间互相scp拷文件,每次总是要输入密码才可行。

通过ssh-keygen生成公钥,在两台机器之间互相建立信任通道即可。假设本地机器client,远程机器为server。

1. 生成rsa keygen

[winter@client winter] $ ssh-keygen -b 1024 -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/winter/.ssh/id_rsa): <Enter>
Enter passphrase (empty for no passphrase): <Enter>
Enter same passphrase again: <Enter>
Your identification has been saved in /home/winter/.ssh/id_rsa.
Your public key has been saved in /home/winter/.ssh/id_rsa.pub.
The key fingerprint is:
33:d4:7b:9c:87:04:cf:14:40:22:6d:c7:15:78:97:6a winter@client

直接上面公钥和私钥存放地址可以直接回车,私钥密码可以直接回车,也可以输入。

2. 查看.ssh目录下了多私钥和公钥文件

[winter@client winter] $ ls .ssh/
id_rsa  id_rsa.pub  known_hosts

3. 拷贝公钥到目标机器上,并改名成authorized_keys

首次scp命令时候还是会提示输入密码,还有是否继续链接的提示,以后

4. 测试ssh进入

[winter@client winter] $ ssh 192.168.0.110

5. ok,搞定!

[winter@server winter] # it's ok!
Tagged with:  

Apache 虚拟主机配置笔记

On 2009/12/15, in Apache, by admin

环境:Linux Apache2.2 (路径 /usr/local/apache)

步骤:

1. 修改 conf/httpd.conf,找到如下位置,去除 # 注释符

# Virtual hosts
Include conf/extra/httpd-vhosts.conf

2.修改 conf/extra/httpd-vhosts.conf

<VirtualHost *:80>
    ServerAdmin [email protected]
    DocumentRoot "/usr/aa"
    ServerName ww.aa.com
    ServerAlias ww.aa.com
    ErrorLog "logs/ww.aa.com-error_log"
    CustomLog "logs/ww.aa.com-access_log" common
</VirtualHost>

注意CustomLog这行,默认给的配置是:”logs/dummy-host.example.com-access_log common”

这个其实是错误的,Apache启动时候会报错,common这个应该放在双引号外面:

Syntax error on line 32 of /usr/local/apache/conf/extra/httpd-vhosts.conf:
CustomLog takes two or three arguments, a file name, a custom log format string or format name, and an optional "env=" clause (see docs)

另外还有个问题,在Apache+Tomcat时候出现的,在配置好mod_jk之后,通过默认80端口访问jsp总会提示403禁止访问,纳闷了!后来 才发现是Directory配置问题,因为每个VirtualHost配置的目录不是默认的DocumentRoot目录,在Apache2以后对于权限 和安全有了更高的要求,所以必须手动配置下每个Directory属性。

<Directory "/usr/aa">
    Options Indexes FollowSymLinks
    AllowOverride None
    Order allow,deny
    Allow from all
</Directory>

OK,到这里虚拟主机部分已经配置完成!

补充一点,加上日志按天保存,避免一个巨大无比的文件!

CustomLog "|/usr/local/apache/bin/rotatelogs /usr/local/apache/logs/ww.aa.com-access-%y%m%d.log 86400 480 " combined
Tagged with:  

Apache Mod_Perl实现 URL Rewrite

On 2009/12/15, in Apache, Perl, by admin

相信apache的mod_rewrite模块都很熟悉了,今天这儿换个思路,利用mod_perl来实现下,发现竟然是如此的简单!

首先得保证apache已经安装了mod_perl模块,具体安装配置可以看上一篇文章哦。

修改下http.conf配置,添加一下内容:

PerlTransHandler MyTrans # MyTrans 这个是自己添加的处理模块名

具体MyTrans.pm脚本如下:

package MyTrans;

use strict;
use Apache2::Const qw(DECLINED);

sub handler {
    my $r = shift;
    my $uri = $r->uri;
    my ($id) = ($url =~ m|^/news/(.*)\.html|);
    $r->uri("/news.php");
    $r->args("id=$id");
    return Apache2::Const::DECLINED;
}
1;

实现就是:/news/12345.html  => /news.php?id=12345

Tagged with:  

Apache Mod_Perl 防盗链

On 2009/12/15, in Apache, Perl, by admin

大体思路是这样的,比如有 一个地址:http://www.aa.com/down/1.mp3,不幸搜索引擎或者迅雷扒到了,就无偿为他们奉献流量了。 但是假如在http://www.aa.com/down/1.mp3?key=123,key参数每天变化或者几分钟变化一次,在apache服务端校 验下这个参数,不正确则显示拒绝访问或者找不到的话,那样防盗链的效果就算达到了把。

modperl强大到可以任意应用apache内部API,官方地址是:http://perl.apache.org 。根据apache版本选择相应的modperl版本,现在大部分都apache2了,就选择modperl2把。具体安装配置可以看官方文档。

先建立/home/httpd/modperl/startup.pl(目录请自行修改),内容如下:

use strict;

use lib qw(/home/httpd/modperl); # 把这个路径加入到perl lib路径

use Apache2::RequestRec ();
use Apache2::RequestIO ();
use Apache2::Connection ();
use Apache2::RequestUtil ();
use Apache2::ServerUtil ();
use Apache2::Log ();
use Apache2::Request ();

1;

部分本机httpd.conf配置:

LoadModule perl_module                modules/mod_perl.so
LoadModule apreq_module             modules/mod_apreq2.so
PerlPostConfigRequire /home/httpd/modperl/startup.pl
<Location /down >
    SetHandler modperl # 设置该目录交给modper处理
    PerlAccessHandler Down # Down是模块名称
    PerlSetVar key 123 # 设置校验参数值
</Location>

mod_apreq2.so这个模块需要安装Apache2::Request,具体安装:http://pyh7.spaces.live.com/blog/cns!47D8D44208AC51E5!128.entry

startup.pl文件一般modperl应用都有,加载一些常用库,可以在apache启动时预先载入,避免重复加载。

修改这些后可以重启下apache,看下logs/error_log里最后是否有mod_apreq和mod_perl字样,如果有就说明成功了。剩下都就是写校验的perl脚本了,/home/httpd/modperl/Down.pm,内容如下:

package Down;
use strict;
use Apache2::RequestRec ();
use Apache2::RequestIO ();
use Apache2::Connection ();
use Apache2::RequestUtil ();
use Apache2::ServerUtil ();
use Apache2::Log ();
use Apache2::Const -compile => qw(OK FORBIDDEN);
use Apache2::Request ();

sub handler {
    my $r = shift;
    my $req = Apache2::Request->new($r);
    my $ip = $r->connection->remote_ip;
    my $k = $req->param('key') || ''; # 判断访问时是否带key参数
    my $key = $r->dir_config('key') || '123'; # 加载httpd.conf配置中的key值
    if ($key eq $k) { # 相等可以正常访问
        return Apache2::Const::OK;
    } else { # 否则显示拒绝访问
        my $s = Apache2::ServerUtil->server;
        $s->log_error("[$ip--------forbidden.]");
        return Apache2::Const::FORBIDDEN;
    }
}

1;

提示一下,以上两个perl脚本文件末尾记得加上1;

重启下apache。现在可以通过http://www.aa.com/down/1.mp3和http://www.aa.com/down /1.mp3?key=123测试下。可以看见不加参数拒绝访问了把。这里只是简单的判断,实际上可以根据日期或者IP加密生成一个字符串来判断。

写这个帖子完全是无意中搜索modperl应用时候发现了,具体可以参见:
http://pyh7.spaces.live.com/blog/cns!47D8D44208AC51E5!140.entry

上面的文档已经写都很详细了,包括怎么安装modperl、Apache2::Request等模块以及配置apache的http.conf就不在累赘都重复了。

Tagged with:  

Pexpect通过SSH执行远程命令

On 2009/12/15, in Python, by admin

pexpect是python一个模块,可以通过:easy_install pexpect 来安装。

这里主要是用pexpect执行ssh,查看远程uptime和df -h看硬盘状况。

#ssh_cmd.py
#coding:utf-8
import pexpect

def ssh_cmd(ip, user, passwd, cmd):
    ssh = pexpect.spawn('ssh %s@%s "%s"' % (user, ip, cmd))
    r = ''
    try:
        i = ssh.expect(['password: ', 'continue connecting (yes/no)?'])
        if i == 0 :
            ssh.sendline(passwd)
        elif i == 1:
            ssh.sendline('yes')
    except pexpect.EOF:
        ssh.close()
    else:
        r = ssh.read()
        ssh.expect(pexpect.EOF)
        ssh.close()
    return r

hosts = '''
192.168.0.12:smallfish:1234:df -h,uptime
192.168.0.13:smallfish:1234:df -h,uptime
'''

for host in hosts.split("\n"):
    if host:
        ip, user, passwd, cmds = host.split(":")
        for cmd in cmds.split(","):
            print "-- %s run:%s --" % (ip, cmd)
            print ssh_cmd(ip, user, passwd, cmd)

hosts数组格式是:主机IP:用户名:密码:命令 (多个命令用逗号, 隔开)
可以看出打印出相应的结果了,可以拼成html发送mail看起来比较美观些咯!

Tagged with:  

用Python写了一个计划任务,定时更新Memcached中一个key值,写的很happy,几分钟搞定。

然后在Java Servlet测试,代码写的也很happy,编译 – 刷新,一气呵成。

然后发现值一直是null,再tail日志看看,异常不断:

com.danga.MemCached.MemCachedClient Mon Jul 20 09:37:04 CST 2009 - ++++ exception thrown while trying to get object from cache for key: test_num
 com.danga.MemCached.MemCachedClient Mon Jul 20 09:37:04 CST 2009 - 3
 com.danga.MemCached.NestedIOException: 3
 at com.danga.MemCached.MemCachedClient.get(MemCachedClient.java:1408)
 at com.danga.MemCached.MemCachedClient.get(MemCachedClient.java:1270)

晕倒,记得以前为了让两个语言实现API读写共享,手动去修改了两个的API包,实现了中文互读写。难不成今儿个还要手动去搞一把?

然后手动试了下:

shell> telnet xxxxxx 11211
get test_num
VALUE test_num 4 2
23

经查证VALUE协议返回的是 key flags len \r\n value 这样的格式,大悟:原来flags不一样啊,Java里面对int型赋值以后flags是0,而Python里则不一样,两者序列化的东西不同啊。懒得去 折腾两者序列化有啥不同。来点直接的把。

然后打开Python Memcached API,大概578行_val_to_store_info方法里,可以看到flags部分,是根据变量类型进行定义的,isinstance(val, str) 如果是str则pass。

到这里就简单了,直接在py代码里:mc.set(‘test_num’, str(num))

Java读取OK。

Tagged with:  

mysqldumpslow 慢查询日志分析工具

On 2009/12/15, in MySQL, by admin

mysql自带的这个玩意挺好使的,可以对慢查询里的sql进行排序、计算等操作。

首先得配置my.cnf:

log_slow_queries = /path/slow.log # 定义log位置,注意要有写入的权限

具体的使法如下:

mysqldumpslow -s c -t 40 /path/slow.log

出来的结果是访问次数最多的40个sql,几个参数大概意思如下:

-t 显示多少条
-s 排序,默认是at。c是次数,t是时间,l是lock时间,r是返回结果。如果是ac,at,al,ar则是倒序
-g 可以用正则匹配部分语句

可以参考mysqldumpslow –help,通过这个工具可以看到哪些锁表,或者其他性能问题,还能看到某些SQL_NO_CACHE提示呢,去想办法优化把!

Tagged with:  

发现mysql slave服务器经常因为一些特殊字符或者符号产生的更新语句报错,整个同步也会因此而卡在那,最初的办法只是手动去出错的机器,执行下面三条sql语句,跳过错误即可。

slave stop;
set GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
slave start;

一台slave机器用这样方法还行,多台就麻烦了,就顺手写了个简单的perl脚本,方便统一跳过错误,代码如下:

#!/usr/bin/env perl
use strict;
use warnings;

# get slave status
sub get_status {
    my ($ip, $usr, $pass) = @_;
    my $info = `mysql -u$usr -p$pass -h$ip -e 'show slave status\\G;'`;
    if (($info =~ /Slave_IO_Running: Yes/) && ($info =~ /Slave_SQL_Running: No/)) {
        return 1;
    }
    return 0;
}
# mysql slave skip
sub slaveskip {
    my ($ip, $usr, $pass) = @_;
    print "slave error **\n";
    system("mysql -u$usr -p$pass -h$ip -e 'slave stop;'");
    system("mysql -u$usr -p$pass -h$ip -e 'set GLOBAL SQL_SLAVE_SKIP_COUNTER=1;'");
    system("mysql -u$usr -p$pass -h$ip -e 'slave start;'");
}

my @hosts = qw/
192.168.0.101:root:tt1234
192.168.0.102:root: tt1234
192.168.0.103:root: tt1234
/;
foreach (@hosts) {
    my ($ip, $usr, $pass) = split ':';
    print "// ----- $ip\n";
    my $count = 1;
    while ($count < 100000) {
        my $status = get_status($ip, $usr, $pass);
        print "i: $count status: $status\n";
        last if $status == 0;
        slaveskip($ip, $usr, $pass);
        select(undef, undef, undef, 0.1);
        $count++;
    }
    print "\n";
}

exit;
Tagged with:  

SSH Tunnel && Memcached

On 2009/12/15, in Memcached, by admin

最近一台服务器放进了移动机房,需要访问原电信机房一台Memcached服务器,Memcached服务是以内网形式启动。

依靠google大神,搜索出解决思路,在本地起一个SSH链接,通过本地一个端口实现对另外机器的映射或者叫做转发。

上周本来已经搞定,本周突发灵异事件,竟然不管了,最后百般尝试,完成结果如下:

移动机器IP:220.xxx.xxx.xxx 电信机器IP:155.xxx.xxx.xxx

在移动机器上执行:

shell > ssh -N -f -L 11211:192.168.0.xxx:11211 [email protected]

11211:192.168.0.xxx:11211,格式为:本地端口:memcache启动的IP:端口
这里没有用RSA认证,就直接输入密码。-N 是不需要shell,-f 是程序后台执行,其他参数参见ssh –help。

shell > ps aux

可以看见进程已经在了,下面开始测试代码。

>>> import memcache
>>> mc = memcache.Client(['127.0.0.1:11211'],debug=True)
>>> print mc.get('name')
Tagged with:  

使用 Perl 快速解析 Apache Log

On 2009/12/15, in Apache, Perl, by admin

功能简述

统计出日志里一个或多个页面总共访问的次数,比如aa.jsp, bb.jsp这样页面分别多少次。

实现简述

Apache单个日志文件800M。

最初程序使用Python编写,按行来统计,分别使用in(最慢)和index方法去查找,然后使用了正则匹配,程序运行时间从最初的1分50多秒优化到1分10秒左右,参考了qyb博客中提到的gc.disable(),有了一定的提升,最终还是需要1分左右。

然后随意用了Perl写了一个,用了最土鳖的<LOG>这样的按行分析,最后正则匹配,然后++,速度竟然在40-50秒之间,惊叹!后来经过shucho指点,在正则部分采用了预编译,效果那是相当惊人!800M文件只用了7秒左右。卧槽!

程序片段

# --------------------------------------------------------------------
use strict;
use Benchmark;

my $LOG_FILE = '/usr/local/apache/logs/access.log';
# 下面qr部分起了关键作用,预编译了表达式
my @EXT_LIST = map {qr/$_/} qw{
aaServlet
bbServlet
};

my $startime = new Benchmark;
my %result;
map {$result{$_} = 0} @EXT_LIST;
open LOG_FILE, $LOG_FILE;
while (<LOG_FILE>){
    foreach my $ext (@EXT_LIST){
        $result{$ext}++ if $_ =~ /$ext/;
    }
}
close LOG_FILE;

while (my ($key, $value) = each(%result)){
    $key =~ s/\(\?-xism:(.*?)\)/$1/g;
    print "$key:\t$value\n";
}

printf "** %s\n\n", timestr(timediff(new Benchmark, $startime));
Tagged with:  
iBlog by PageLines

WP SlimStat