2014-10-12

翻墙更舒畅:将ssh隧道设置为windows服务

利用境外vps主机配合putty/plink实现ssh隧道(ssh tunnel)来翻墙方便又安全,但是每次总要开个putty窗口,很是不爽。

今天将小站从aws迁移到linode后,突发奇想,可否将plink相关命令配置成一个windows服务,像linux下的守护进程那样,默默的在后台提供服务?

说干就干,搜索了一下,实现自定义的windows服务有两个工具可以使用,一个是sc,一个是instsrv 。

sc看起来比较符合使用习惯,首先就是他了。

把plink命令保存为脚本:

C:\Users\farnsworth>plink.exe -C -D 127.0.0.1:<local_port> <user_name>@<server_host_name> -pw <passwd>

通过sc create创建新的服务:

C:\Users\farnsworth>sc create my_ssh_tunnel binPath= "C:\Program Files\Putty\linode_ssh_tunnel.bat" \
 type= share start= auto DisplayName= "My-SSH-Tunnel"

[SC] CreateService 成功

PS:

注意sc命令的参数中“=”号后面必须要加个空格。

打开service面板,已经可以看到刚才创建的服务了:

(更多…)

2014-10-12

迁移至linode东京机房

前天收到了亚马逊的邮件,一年免费体验的aws ec2 vps到期了。不知道到期之后是会开始收费,还是会直接停掉instance删掉数据。但是无论哪种方式都不想在这边继续停留了。访问速度太慢,在终端上敲命令一顿一顿的,时间长了真是有点吃不消。

好在之前铁哥们给了一个linode的vps的root,告知可以“随便折腾”。vps位于linode的东京机房,访问速度相当不错。趁着周末,把网站迁移搞定。

搬迁过程很简单,打包 & scp一下文件至新服务器,mysqldump 导出数据库再重新导入。

整个过程很顺利,唯一有点波折的地方在于apache虚拟服务器的配置,在此记录一下。

1、virtual host配置文件命名问题

Ubuntu 14.04 LTS中的apache的配置文件有所变化:

可以看到在这种配置下,virtual host的配置文件必须以.conf为后缀,否则apache将不会加载。在使用a2ensite的时候,会提示找不到对应的site。


# Include generic snippets of statements
IncludeOptional conf-enabled/*.conf

# Include the virtual host configurations:
IncludeOptional sites-enabled/*.conf

比如,pixcase.me的配置文件需要命名为pixcase.me.conf。

猜想这个改动也算是一个优化,以后可以在这个目录下放一些备份之类的文件,而不用担心误操作。

2、默认defalt-site问题

配置完成之后,发现virtual host配置并未生效,检查配置也没有任何问题,后来尝试了一下把默认的000-default.conf关闭,才可以访问。


sudo a2dissite 000-default.conf

重启apache之后顺利打开页面。

最后到godaddy修改DNS记录,改回hosts文件后,等待十分钟左右,浏览器直接访问pixcase.me成功,至此迁移完毕。

–EOF–

2013-12-22

Amazon EC2数据备份之EBS

众所周知,amazon EC2中创建的虚拟机instance在关闭后,数据是不保留的。也就是说,如果instance因为意外操作或者AWS宕机等原因被重启了,哪这个系统中所有的数据就都没有了 🙁

之所以AWS被设计为如此,应该是为了节约资源的考虑。大部分的EC2 instance应该是为纯计算型应用服务的,用的时候创建进行运算服务,运算结果可以由用户导出下载到本地,云中是不需要保存这部分数据的,因此为每个instance保留数据实例,意义并不大。

但是如果想用EC2做web host,数据持久化是必须要面对的问题。针对这个情况 ,amazon提供了对应的EBS服务,elastic block storage 。

通过EBS创建的volum卷可以挂载到指定的instance之上,EBS卷上的数据不会受到关联的instance的启动或者关闭的影响,数据是持久保存的,因此用EBS来实现instance上数据的持久化是最简单的选择。

铺垫了这么多,言归正传,pixcase.me在EC2上毫无保障地裸奔了一个多月之后,今天终于用EBS建起了最基本的数据保障。拖延症和极端的乐观主义果然是有直接关系的,悲观主义者肯定第一天就把数据备份的问题搞定了,怕宕机啊。。。

pixcase.me用wordpress搭建,现在在instance上跑的主要是一个apache和一个mysqld,需要备份的数据只有/var/www目录下的网站代码和上传的文件,另外还需要备份的还有mysql数据库。

在AWS management console里面创建一个新的ebs volum,Amazon Aws Trail免费套装里面EBS有30G的免费额度,之间创建的micro instance只占用了8g,我们还有22G免费额度可用。考虑以后还可能继续折腾,暂时创建了一个8G的新卷,剩下来的额度留着今后折腾别的用~。

EBS卷创建完毕之后,右键点击卷名,选择挂载到我们之前创建到得instance之上。

打开终端,在/dev目录下,可以看到新出现了一个新设备xvdf

root@ip-172-31-5-135:~# cd /dev/
root@ip-172-31-5-135:/dev# ll | grep xvd
brw-rw---- 1 root disk 202, 1 Oct 19 13:50 xvda1
brw-rw---- 1 root disk 202, 80 Dec 22 07:54 xvdf

新创建的EBS卷要格式化后才能使用

root@ip-172-31-5-135:/dev#  sudo mkfs.ext4 /dev/xvdf

然后再挂载到系统之中

root@ip-172-31-5-135:/dev# mkdir -m 000 /vol
root@ip-172-31-5-135:/dev# echo "/dev/xvdf /vol auto noatime 0 0" | tee -a /etc/fstab
root@ip-172-31-5-135:/dev# sudo mount /vol
ubuntu@ip-172-31-5-135:~$ df -h
Filesystem Size Used Avail Use% Mounted on
/dev/xvda1 7.9G 1.2G 6.3G 16% /
udev 288M 8.0K 288M 1% /dev
tmpfs 119M 176K 118M 1% /run
none 5.0M 0 5.0M 0% /run/lock
none 296M 0 296M 0% /run/shm
/dev/xvdf 7.9G 218M 7.3G 3% /vol

新卷挂载完成之后,我们就可以把关键数据迁移到新卷之上了。

首先是拷贝网页代码到新卷之下:

ubuntu@ip-172-31-5-135:~$ cd /vol
ubuntu@ip-172-31-5-135:/vol$ sudo mkdir www ubuntu@ip-172-31-5-135:/vol$ sudo cp -rfp /var/www/* www/

修改对应的apache配置文件,将site的DocumentRoot指向/vol/www
重新加载apache配置,完成数据迁移。

ubuntu@ip-172-31-5-135:/vol$ sudo /etc/init.d/apache2 reload
 * Reloading web server config apache2 [ OK ]

下面是迁移mysql数据库文件,首先拷贝文件到新的EBS卷之下:

ubuntu@ip-172-31-5-135:/vol$ sudo mkdir mysql_datadir
ubuntu@ip-172-31-5-135:/vol$ sudo cp -rfp /var/lib/mysql/* /vol/mysql_datadir/*
ubuntu@ip-172-31-5-135:/vol$ sudo chown mysql.mysql -R /vol/mysqld_datadir


拷贝完数据后,然后修改/etc/mysq/my.cnf,将datadir指向/vol/mysql_datadir。

迁移完毕,重启mysql,然后可耻的失败了 🙁 这是为何?

ubuntu自7.10开始启用了一套新的安全机制AppArmor,这个安全软件会在你的文件系统中创建一个允许应用程序访问的区域(专业术语:应 用程序访问控制)。如果不为MySQL修改AppArmor配置文件,永远也无法为新设置的数据库存储位置启动。


sudo nano /etc/apparmor.d/usr.sbin.mysqld

注释掉/var/lib/mysql/这两行,并加入新的配置


/vol/mysql_datadir/ r,
/vol/mysql_datadir/** rwk,

配置修改完毕后,再次重启mysql


ubuntu@ip-172-31-5-135:~$ sudo /etc/init.d/mysql restart
Rather than invoking init scripts through /etc/init.d, use the service(8)
utility, e.g. service mysql restart

Since the script you are attempting to invoke has been converted to an
Upstart job, you may also use the stop(8) and then start(8) utilities,
e.g. stop mysql ; start mysql. The restart(8) utility is also available.
mysql stop/waiting
mysql start/running, process 8967

大功告成,今晚可以安心睡觉了~ 🙂

2013-10-13

buffalo LS-WXL NAS 部署笔记

从上大学开始到现在所积累的照片和资料现在一直是用一台希捷的3.5寸外置移动硬盘保存着。每次拿出来拷东西的时候,咔咔的读盘声总让人不免担心,万一这块硬盘哪天抽风坏了怎么办。这些数据中包含了无数过往的努力和回忆,一旦丢失,代价实在是难以估量。

组建一套家用的NAS是解决目前的窘境的最好选择。但是群晖之类的NAS不带硬盘动辄上千实在是有点贵,心怀一颗屌丝之心,始终不忍下手。用旧PC改装一个,家中实在是没有地方可以容纳。上个月无聊逛易讯时发现Buffalo LS-WXL NAS正在特价,399购入一台,貌似一个月过后到现在还是最低价,占到便宜的感觉十分开心 :)虽然便宜了点,做工和群晖的高富帅没法比,但是两个硬盘槽位,支持RAID 0/RAID 1,linux系统可以破解,支持Web Access,功能足矣。

光有腹中空空的NAS当然不行,还得往它肚子里塞上硬盘才能工作起来,对比各项参数和口碑,西数的NAS专用红盘是最好的选择,但是价格嘛。。。 最终决定下来,还是入了两块西数的2T绿盘,可靠性差了点,但是有RAID 1,两块互为备份,可靠性还是有保证的。易讯绿盘无货,京东现货入手。

考虑到家里特殊的网络拓扑结构,NAS附近有小米盒子,电视机,还有一个Raspberry PI需要接入网络,装修时墙上只留了一个网口,这么多设备需要一个交换机来互联并接入网络,还需添置一个交换机。家里有一个百兆的TP-Link交换机,但是今后如果想用小米盒子直接samba访问NAS放高清电影的话,百兆网络就难当大任了。交换机这个东西属于耐用品,一般都不容易坏,上淘宝上淘一个二手实用的即可。上上下下比较了一番,Netgear GS105是一个不错的选择,铁壳,千兆,成色不错的货挺多的,找了一个靠谱的商家,加配原装电源一个¥99搞定。两天后到手,成色果然不错,9成新有余,拿在手中沉甸甸的,淘宝掌柜诚不欺我也~

万事俱备,只欠部署。安装之前,来一张全家福先~

buffalo nas

(更多…)

2012-08-31

debian @ x210i 安装笔记

家里现在有两台thinkpad,一台是我的服役5年,状态尚好的T60,另外一台是老婆毕业后新买的x201i。x201i轻巧便携,但无奈屏幕太小,和T60的高分辨率方屏一比,是在是木有太多吸引力。老婆有时在家加班,也霸占着我的T60,x210i基本就闲下来了。

家里有一台电脑闲着,而且是x系 列的thinkpad,我的心思不由得开始活络起来了 🙂

说服了老婆之后,就开始忙活起来了,换硬盘,导数据,下映像,刻盘。没错,我要把小i改造成我的linux工作站,发行版嘛,自然是Debian莫属啦。下面把安装配置过程记录如下自己备忘

一、安装

1、net install on wifi 问题

安装debian,最方便自由的方式,还是选择netinst镜像。但是如此一来的话,需要在安装过程中就有网络的支持。

debian 从squeeze开始支持在net install的过程中使用wifi来连接网络,但是在安装前,首先要解决驱动问题:x210i使用的intel的wifi芯片,是没有开源的实现的。因此讲究纯净的debian在安装光盘中并没有附带其驱动,需要额外下载。

其实debian已经在其apt源中添加了上述驱动包,可以到这里下载:

http://packages.debian.org/sid/all/firmware-iwlwifi/download

下载完成后,使用7-zip将deb包解压,得到下面这些文件:

/lib/firmware/iwlwifi-1000-3.ucode
/lib/firmware/iwlwifi-3945-1.ucode
/lib/firmware/iwlwifi-3945-2.ucode
/lib/firmware/iwlwifi-4965-1.ucode
/lib/firmware/iwlwifi-4965-2.ucode
/lib/firmware/iwlwifi-5000-1.ucode
/lib/firmware/iwlwifi-5000-2.ucode
/lib/firmware/iwlwifi-5150-2.ucode
/lib/firmware/iwlwifi-6000-4.ucode
/lib/firmware/iwlwifi-6000g2a-5.ucode
/lib/firmware/iwlwifi-6000g2b-5.ucode
/lib/firmware/iwlwifi-6050-4.ucode
/lib/firmware/iwlwifi-6050-5.ucode

准备一个u盘(注意要是fat 32格式的,ntfs格式的貌似不会被识别,将上面这些文件拷贝至u盘根目录下。当安装界面提示需要第三方媒介提供iwlwifi*等文件的时候,插入u盘,安装程序会自动搜索并安装网卡驱动。

(更多…)

2012-03-26

The “dollar” in awk

首先贴一个简单的awk命令,猜一下,这个命令执行之后的输出会是什么?

$ echo "" | awk '{OFS=","; $x = 1; $y = 1; $y = $x; $y += 1; print $x, $y;}'

理想中,输出应该是这个样子的:

1,2

但现实中,却是这个样子的:

2,2

这是怎么回事?难道awk的赋值不是值传递(assignment by value),而是引用传递(assigned by reference)?困惑了好久,先RTFM后STFW两招杀手锏下来也毫无结果,人家压根就没提awk还有值传递和引用传递的区别 T_T

盯着这个表达式看了好久,忽然恍然大悟,awk和php还有bash是不一样的,变量前面不需要加”$”引用,把”$”去掉后,一切正常:

$ echo "" | awk '{OFS=","; x = 1; y = 1; y = x; y += 1; print x, y;}' 
1,2

那,加上”$”之后原本的变量的意义又变成什么了呢?为什么有这样看起来像引用传递的结果?

原来在awk中,”$”表示对字段(Field)的引用,诸如$0表示整条记录(Record),$1表示记录中的第一个字段,$2表示第二个,以此类推下去。当然,awk允许非常量类型的字段引用。$n也是可以的,如果n=1,则$n == $1

至此,再来看本文第一个例子,其实可以翻译如下:

$ echo "" | awk '{OFS=","; $0 = 1; $0 = 1; $0 = $0; $0 += 1; print $0, $0;}' 
2,2

在脚本执行期间,x与y的值一直都是未初始化的0,因此,对于$x, $y的操作都是对$0的操作,所以看起来就像是引用一样。

终于搞明白了,可以松口气了,但是花费了近两个小时的时间。

吐槽这些语言语法混杂容易搞混之余,也只能怪自己学艺不精犯下此等低级错误 =。= 记录在此,以敬效尤

2009-05-02

构建Linux下的函数库编译方案

就快离开学校了,最近打算把大学这几年积累下来的代码重构一下,写成类似于ACE那种形式的C++代码库,方便调用。也算是留给学弟学妹们的礼物。

在整理过程中遇到许多问题,感觉都颇有启发性。尤其是构建编译方案的过程,几乎让我重新学习和认识了make工具,收益匪浅。下面就把这个过程和盘托出,权当笔记,也希望对大家有用。

一:初始编译方案:

目录树:

|-- Makefile
|-- README
|-- doc
|   |-- CHANGES
|   |-- COPYING
|   |-- CREDITS
|   |-- INSTALL
|   `-- TODO
|-- inc
|   |-- Exception.h
|   |-- HashTable.h
|   |-- MessageQueue.h
|   |-- Mutex.h
|   `-- Semaphore.h
|-- lib
|-- mks
|   `-- linux.mk
|-- obj
|-- sample
`-- src
    |-- Exception.cpp
    |-- HashTable.tpl
    |-- MessageQueue.cpp
    |-- Mutex.cpp
    `-- Semaphore.cpp

(更多…)

2008-08-25

ubunut 8.04升级笔记

8.04已经发布很长时间了,我的系统还是7.04,最近时间充裕,于是决定升级。

据说使用命令apt-get install dist-upgrade升级,会存在解决不了的依赖性问题,保险起见,使用图形界面的升级程序。

从7.04升级到7.10过程很顺利,速度也很快。简单测试了一下,scim、kaffeine都运行正常,于是继续从7.10升级到8.04。

都是cn99的源,但从7.10到8.04的过程却非常慢,从六点开始,到十点更新数据包还没下载完,只能把电脑留在实验室,明天再来看了。第二天过来,却发现更新过程卡住了

During the step “Setting up locales (2.7.9-4) …” I get the following message:

Generating locales…
en_AU.UTF-8…

top显示,有一个localedef进程占用了99%的CPU,而且已经运行了六个多小时,多半是死掉了。这个时候正是升级过程中最关键的安装阶段,如果直接重启,升级失败,后面就麻烦了。考虑了一下,大不了跳过这个步骤,把其他包装完,以后再解决这个问题。

sudo killall -9 localedef

没反应……,看进程状态,是R+,没道理杀不掉,但重试n遍,屡试无果。

pstree,找到localedef的父进程为locale-gen,

sudo killall -9 locale-gen

成功杀死,localedef进程还是存在,但是升级已经可以往下走。 在后面的过程中还会出现这样的情况,不必理会,直接kill。有一些包会由于依赖性安装失败,诸如sun jdk,但基本的组件可以顺利安装,完成后,重启系统。

重启完后,四处google,发现这已经是一个登录在册的bug,ID号为249340。最简单的解决方法如下:

找到/etc/belocs/locale-gen.conf,将其中的ARCHIVE值从no改为yes,然后

sudo apt-get install update

便可顺利的重新生成locale,并且把升级过程中由于依赖性未安装的包重新装上。

–EOF–

2007-12-17

记一次root引起的血案

从开始用Linux的那天起,就始终被告知平时不要使用root帐户。但我一直认为,偶是程序员,又不是系统管理员,用root调试程序能方便很多,又何必给自己设这么多限制。

记得上次看到不要用root帐户的理由是:“直到你有一天无意间在根目录下rm -rf *,就会知道这么做的后果” 。当时就感觉这话言过其实了,那有人会那么呆啊。

再说我为人谨慎,一般也是不会误删什么的啦。

后来转用ubuntu,这系统做的更绝,直接把root给禁了。但这对于我也是徒劳,因为每次我装完系统,第一件事就是开启root用户。好在用debian用惯了,平时登陆xwindow不像redhat那样直接用root,但开命令行一般直接就是su -。

今天分到个写安装脚本的任务,用bash。

我也没学过bash编程,但想想也简单,就答应了。边学边写,临近晚饭,差不多快写完了。

就在这时,突然发现某个位置似乎对用户交互不合理,于是改之(事后证明是白改,根本不需要也不能这样)。

改完,测试,快到最后一步的时候报错:

rm : can not delete /dev/xxxx

正在纳闷,这是哪出的错。突然意识到大事不好,ctr+c打断执行,可是为时已晚,根目录下的大部分文件都被删掉了,包括/bin目录。

就这样,一百多G的电影、软件、音乐、还有很多代码,都没了。

写安装脚本的vi窗口还没关,能看到代码,仔细检查,发现问题出在了一个条件判断上

echo -n "请输入xxx安装路径[默认:/usr/local/MyPast] "
read PROG_PATH
if [ "PROG_PATH" = "" ]
then
        PROG_PATH="/usr/local/MyPast"
fi

...

rm -rf $PROG_PATH/*

看出来了么?PROG_PATH前少了个”$”。

测试时选择了默认路径,也就是直接回车,read PROG_PATH后变量PROG_PATH的值为空。

而接下来if中的条件判断由于少了个$,导致比较结果为非真。PROG_PATH=”/usr/local/MyPast”没有执行。

到了下面, rm的参数$PROG_PATH/*被解释为/*

所以 rm -rf $PROG_PATH/*就变成了rm -rf /*

“直到你有一天无意间在根目录下rm -rf *,就会知道这么做的后果” 。

妈的,这回我懂了。

看来这两天真是脚本与维护不宜。前天搞坏了数据库里的数据,今天又干掉了一个系统,郁闷。

2007-11-12

pthread in C++

Linux下的编程一直是C语言的天下,但老是用C感觉写的很乏味。用面向对象方法编程,听着都倍有面子。于是决定先在的这个项目用C++来写。虽然不一定能“以C++的思想”来写C++,少会有C++的样子。

但是问题来了:我需要在程序中动态创建一个线程,而pthread不接受C++类的成员函数作为参数。

原因也很简单,类成员是在类被实例化成为对象后才存在的,即在编译时是不存在的,编译器无法取得函数的确切入口地址,自然无法通过编译。

照这个分析,如果把要调用的类成员函数声明为静态的,pthread_create就可以找到函数的地址了。但这样一来的话,由于类中的静态函数无法调用类的非静态成员。线程函数的功能就受到了很大限制,也就没有比要将其放在类中了。

最容易想到的解决方案就是写个C函数,然后再C函数中调用C++对象的成员函数。

比如类为

class foo(){

    public :
        thread();

}

class *f;

void *bar(void *arg){

    f->thread();       

    return NULL;
}

int  main(){

    .........
    f=new foo();
    
    pthread_create(&tid,&tattr,bar,NULL);

}

显然这种发法太笨了,而且对象只能是全局的。

注意到线程函数bar可以有一个任意类型的指针作为参数,那我们何不将对象通过这个指针将对象变为bar的一个参数,从而让我们的程序好看一些。

class foo(){

    public :
        thread();

}


void *bar(void *args){

    foo *f=(foo *)args;

    f.thread();       

    return NULL;
}

int  main(){

    .........
    foo *f=new foo();
    pthread_create(&tid,&tattr,bar,f);

}

如果把上述两种方法结合起来即对象中的静态函数+通过指针参数传递对象,那又会怎么样呢?

class foo(){

    public :
        int thread();

        static void *wrapper(void *args){
            foo *f=static_cast<foo *>(args);
            f->thread();
            return NULL;
        }

}

int  main(){

    .........
    foo *f=new foo();
    pthread_create(&tid,&tattr,foo::wrapper,&f);

}

现在,强迫症患者,是不是觉得整洁清楚很多了呢?

–Reference–
http://www.osix.net/modules/article/?id=450

–EOF–