Git 统计代码量

最近有一个需求是要统计 Git 仓库里每个人的代码量,于是上网搜了一下,找了一些相关命令:

指定用户名版

git log --author="_Your_Name_Here_" --pretty=tformat: --numstat | awk '{ add += $1; subs += $2; loc += $1 - $2 } END { printf "added lines: %s, removed lines: %s, total lines: %s\n", add, subs, loc }' -

这句话可以输出当前项目内指定用户名的用户的代码量统计,结果如下:

added lines: 30400 removed lines: 21317 total lines: 9083

使用 ls-file 实现不指定用户版统计行数版

git ls-files -z | xargs -0n1 git blame -w | ruby -n -e '$_ =~ /^.*\((.*?)\s[\d]{4}/; puts $1.strip' | sort -f | uniq -c | sort -n

这段代码比较有意思,它扫描了当前分支的每个文件,然后用 Git 的 blame 功能输出每个人的代码行数,最后用系统命令 sort 和 uniq 实现计数。

结果如下:

   8 aaa
   9 bbb
 145 ccc
 146 ddd
 261 eee

扫描 Log 统计增删行数版

git log --shortstat --pretty="%cE" | sed 's/\(.*\)@.*/\1/' | grep -v "^$" | awk 'BEGIN { line=""; } !/^ / { if (line=="" || !match(line, $0)) {line = $0 "," line }} /^ / { print line " # " $0; line=""}' | sort | sed -E 's/# //;s/ files? changed,//;s/([0-9]+) ([0-9]+ deletion)/\1 0 insertions\(+\), \2/;s/\(\+\)$/\(\+\), 0 deletions\(-\)/;s/insertions?\(\+\), //;s/ deletions?\(-\)//' | awk 'BEGIN {name=""; files=0; insertions=0; deletions=0;} {if ($1 != name && name != "") { print name ": " files " files changed, " insertions " insertions(+), " deletions " deletions(-), " insertions-deletions " net"; files=0; insertions=0; deletions=0; name=$1; } name=$1; files+=$2; insertions+=$3; deletions+=$4} END {print name ": " files " files changed, " insertions " insertions(+), " deletions " deletions(-), " insertions-deletions " net";}'

这段比较复杂,我也没有认真解读,直接贴结果吧:

aaa,: 353 files changed, 9359 insertions(+), 3844 deletions(-), 5515 net
aaa,bbb,: 4 files changed, 144 insertions(+), 2 deletions(-), 142 net
ccc,: 114 files changed, 2301 insertions(+), 481 deletions(-), 1820 net
ddd,: 27 files changed, 1856 insertions(+), 757 deletions(-), 1099 net
eee,: 1726 files changed, 32841 insertions(+), 22719 deletions(-), 10122 net
eee,fff,: 13 files changed, 209 insertions(+), 211 deletions(-), -2 net
ggg,: 53 files changed, 1153 insertions(+), 1170 deletions(-), -17 net
fff,: 2445 files changed, 69875 insertions(+), 62148 deletions(-), 7727 net
fff,eee,: 30 files changed, 394 insertions(+), 472 deletions(-), -78 net
bbb,: 37 files changed, 781 insertions(+), 216 deletions(-), 565 net
hhh,: 4 files changed, 34 insertions(+), 4 deletions(-), 30 net

比较奇怪的是会列出两个人同时修改,可能是 merge 操作,没有深究。

扫描 Log 单独统计每个人的增删行数加强版

git log --format='%aN' | sort -u | while read name; do echo -en "$name\t"; git log --author="$name" --pretty=tformat: --numstat | awk '{ add += $1; subs += $2; loc += $1 - $2 } END { printf "added lines: %s, removed lines: %s, total lines: %s\n", add, subs, loc }' -; done

直接上输出:

aaa	added lines: 34, removed lines: 4, total lines: 30
bbb	added lines: 2301, removed lines: 481, total lines: 1820
ccc	added lines: 1856, removed lines: 757, total lines: 1099
ddd	added lines: 30400, removed lines: 21317, total lines: 9083
eee	added lines: 1153, removed lines: 1170, total lines: -17
fff	added lines: 1153, removed lines: 1170, total lines: -17
ggg	added lines: 72886, removed lines: 64233, total lines: 8653
hhh	added lines: 814, removed lines: 216, total lines: 598
iii	added lines: 9503, removed lines: 3846, total lines: 5657

第三方小工具版

使用这个工具可以直接输出非常漂亮的统计表格:

https://github.com/oleander/git-fame-rb

gem install git_fame
cd /path/to/gitdir && git fame
Total number of files: 2,053
Total number of lines: 63,132
Total number of commits: 4,330

+------------------------+--------+---------+-------+--------------------+
| name                   | loc    | commits | files | percent            |
+------------------------+--------+---------+-------+--------------------+
| Johan Sørensen         | 22,272 | 1,814   | 414   | 35.3 / 41.9 / 20.2 |
| Marius Mathiesen       | 10,387 | 502     | 229   | 16.5 / 11.6 / 11.2 |
| Jesper Josefsson       | 9,689  | 519     | 191   | 15.3 / 12.0 / 9.3  |
| Ole Martin Kristiansen | 6,632  | 24      | 60    | 10.5 / 0.6 / 2.9   |
| Linus Oleander         | 5,769  | 705     | 277   | 9.1 / 16.3 / 13.5  |
| Fabio Akita            | 2,122  | 24      | 60    | 3.4 / 0.6 / 2.9    |
| August Lilleaas        | 1,572  | 123     | 63    | 2.5 / 2.8 / 3.1    |
| David A. Cuadrado      | 731    | 111     | 35    | 1.2 / 2.6 / 1.7    |
| Jonas Ängeslevä        | 705    | 148     | 51    | 1.1 / 3.4 / 2.5    |
| Diego Algorta          | 650    | 6       | 5     | 1.0 / 0.1 / 0.2    |
| Arash Rouhani          | 629    | 95      | 31    | 1.0 / 2.2 / 1.5    |
| Sofia Larsson          | 595    | 70      | 77    | 0.9 / 1.6 / 3.8    |
| Tor Arne Vestbø        | 527    | 51      | 97    | 0.8 / 1.2 / 4.7    |
| spontus                | 339    | 18      | 42    | 0.5 / 0.4 / 2.0    |
| Pontus                 | 225    | 49      | 34    | 0.4 / 1.1 / 1.7    |
+------------------------+--------+---------+-------+--------------------+

 

CentOS Bash Proxy 设置

今天在服务器上做一个 Bash 代理的配置,想要将某些地址去除代理,于是搜了一下,基本上答案都是:

export no_proxy="localhost,127.0.0.1,192.168.0.0/24"

这样的答案。但是实际使用的过程中,我发现这跟我就是在误导别人,因为如果像上面那样写,你在访问 192.168.0.1 的时候会发现还是走了代理。

经过尝试,下面几种写法都是无效的:

127.0.0.0
127.0.0.0/8
127/8
127.*.*.*
127.

特此记录一下,避免后人踩坑。。。

MYSQL的NOW和SYSDATE函数的区别

在MySQL Performance Blog博客上看到一篇文章介绍now()和sysdate()函数。

想起很多朋友专门问在MySQL里面提供now()和sysdate()函数,都是表示取得当前时间,他们之间有什么区别。我们下面来详细看一下

首先大家可以看一下下面的一个诡异现象:

mysql> SELECT NOW(),SYSDATE();
+---------------------+---------------------+
| NOW() | SYSDATE() |
+-----------------------------+----------------------------+
| 1999-01-01 00:00:00 | 2012-12-05 09:50:03 |
+---------------------------+----------------------------+
1 row in set (0.00 sec)

很有意思吧?
sysdate()得到的时间是当前时间,而now()取出来的时间竟然是“1999-01-01 00:00:00”。
首先申明,我不是PS或者修改得来的,你看完本文,我会教你在你的MySQL上也得出这样的结果。

另外我们看一下,now()和sysdate()的另外一个区别:

mysql> SELECT NOW(), SLEEP(2), NOW();
+---------------------+----------+---------------------+
| NOW() | SLEEP(2) | NOW( |
+-----------------------------+--------------+-----------------------------+
| 2006-04-12 13:47:36 | 0 | 2006-04-12 13:47:36 |
+---------------------------+--------------+----------------------------+

mysql> SELECT SYSDATE(), SLEEP(2), SYSDATE();
+---------------------+----------+---------------------+
| SYSDATE() | SLEEP(2) | SYSDATE() |
+-----------------------------+--------------+----------------------------+
| 2006-04-12 13:47:44 | 0 | 2006-04-12 13:47:46 |
+---------------------------+--------------+----------------------------+

在使用now()的情况下,虽然我们sleep了2秒,但是大家可以看到两次now()函数输出的结果都是’2006-04-12 13:47:36′
而使用sysdate()的情况下,是两个时间’2006-04-12 13:47:44′,’2006-04-12 13:47:46’,正好相差两秒。

这个最终的原因,大家可以直接查看MySQL的reference对now()函数的解释:http://dev.mysql.com/doc/refman/5.6/en/date-and-time-functions.html#function_now
我简单给大家翻译一下。
now()函数,返回的是当前的时间。但是当前的时间是怎么取的列?

首先,对于now()函数来说,它取的时间是语句开始执行的那个时间,并且在语句执行过程中,这个值都不会变。甚至于,你在执行一个存储过程或者触发器时,这个值都是一直不变的。

这也就解释了,为什么sleep了2秒以后,在SELECT NOW(), SLEEP(2), NOW();语句中,取出的时间值是同一个:’2006-04-12 13:47:36’。

 

然后:now()函数取的当前时间从哪里来?它取自mysql的一个变量”TIMESTAMP”。

很奇怪吧?

其实这个是由于MySQL的replication导致的。你可以想象一下,一个insert into  gguard values (3,now());语句在两台MySQL上插入的值是不是一样?now()如果像sysdate()一样取的是机器的系统时间,那么在MySQL的主库和备库执行同一个这样的SQL语句,主库和备库的这一条数据肯定就不一致了。

主备库不一致的问题必须要解决,两种解决方式:

1、修复这种问题。

2、不使用statement的语句级别复制,而是类似于oracle的,将数据变更记录下来,原样在备库执行一遍。

第二种方式就是大家熟知的,binlog_format=ROW的方式。第一种就是now()不使用机器系统时间,而是取mysql的变量”TIMESTAMP”值。

另外的类似的变量还包括insert_id(用于复制时,AUTO_INCREMENT的取值)等

 

利用mysqlbinlog你可以看到每个binlog event都有一个时间值。

# at 441
#121205 10:06:52 server id 5 end_log_pos 526 Query thread_id=5 exec_time=0 error_code=0
SET TIMESTAMP=1354673212.982122/*!*/;
BEGIN
/*!*/;
# at 526
#121205 10:06:52 server id 5 end_log_pos 642 Query thread_id=5 exec_time=0 error_code=0
use `test`/*!*/;
SET TIMESTAMP=1354673212.982122/*!*/;
insert into gguard values (3,now())
/*!*/;
# at 642
#121205 10:06:52 server id 5 end_log_pos 669 Xid = 26
COMMIT/*!*/;

备库复制执行时,SQL thread在做每个insert或者其他操作前首先要执行SET TIMESTAMP这样的动作,保证now()函数在statement模式下在备库和主库一样。
这里还有另外一种含义:sysdate()函数在statement模式下,主库和备库会不一致,也就是说sysdate在statement复制模式下是不安全的。

 

那么怎么实现上面的SELECT NOW(),SYSDATE();查询出来的时间不一样列,你只需要在之前执行:

SET TIMESTAMP=UNIX_TIMESTAMP('1999-01-01');
SELECT NOW(),SYSDATE();

 
体验now()和sysdate()的神秘吧 🙂

注意:

CURRENT_TIMESTAMP() LOCALTIME() LOCALTIMESTAMP()都是now()函数的同义词,不讨论。
sysdate()没有同义词。
如果你觉得now()函数就够了,你不需要每次都取当前的机器系统时间,那么你可以在MySQL启动时指定–sysdate-is-now,这样的话MySQL会把sysdate()当成now()的一个同义词。

参考:
http://www.mysqlperformanceblog.com/2012/11/28/replication-of-the-now-function-also-time-travel/

[Redis] redis-cli 命令总结

Redis提供了丰富的命令(command)对数据库和各种数据类型进行操作,这些command可以在Linux终端使用。在编程时,比如使用Redis 的Java语言包,这些命令都有对应的方法。下面将Redis提供的命令做一总结。

官网命令列表:http://redis.io/commands (英文)

1、连接操作相关的命令

  • quit:关闭连接(connection)
  • auth:简单密码认证

2、对value操作的命令

  • exists(key):确认一个key是否存在
  • del(key):删除一个key
  • type(key):返回值的类型
  • keys(pattern):返回满足给定pattern的所有key
  • randomkey:随机返回key空间的一个key
  • rename(oldname, newname):将key由oldname重命名为newname,若newname存在则删除newname表示的key
  • dbsize:返回当前数据库中key的数目
  • expire:设定一个key的活动时间(s)
  • ttl:获得一个key的活动时间
  • select(index):按索引查询
  • move(key, dbindex):将当前数据库中的key转移到有dbindex索引的数据库
  • flushdb:删除当前选择数据库中的所有key
  • flushall:删除所有数据库中的所有key

3、对String操作的命令

  • set(key, value):给数据库中名称为key的string赋予值value
  • get(key):返回数据库中名称为key的string的value
  • getset(key, value):给名称为key的string赋予上一次的value
  • mget(key1, key2,…, key N):返回库中多个string(它们的名称为key1,key2…)的value
  • setnx(key, value):如果不存在名称为key的string,则向库中添加string,名称为key,值为value
  • setex(key, time, value):向库中添加string(名称为key,值为value)同时,设定过期时间time
  • mset(key1, value1, key2, value2,…key N, value N):同时给多个string赋值,名称为key i的string赋值value i
  • msetnx(key1, value1, key2, value2,…key N, value N):如果所有名称为key i的string都不存在,则向库中添加string,名称key i赋值为value i
  • incr(key):名称为key的string增1操作
  • incrby(key, integer):名称为key的string增加integer
  • decr(key):名称为key的string减1操作
  • decrby(key, integer):名称为key的string减少integer
  • append(key, value):名称为key的string的值附加value
  • substr(key, start, end):返回名称为key的string的value的子串

4、对List操作的命令

  • rpush(key, value):在名称为key的list尾添加一个值为value的元素
  • lpush(key, value):在名称为key的list头添加一个值为value的 元素
  • llen(key):返回名称为key的list的长度
  • lrange(key, start, end):返回名称为key的list中start至end之间的元素(下标从0开始,下同)
  • ltrim(key, start, end):截取名称为key的list,保留start至end之间的元素
  • lindex(key, index):返回名称为key的list中index位置的元素
  • lset(key, index, value):给名称为key的list中index位置的元素赋值为value
  • lrem(key, count, value):删除count个名称为key的list中值为value的元素。count为0,删除所有值为value的元素,count>0从头至尾删除count个值为value的元素,count<0从尾到头删除|count|个值为value的元素。 lpop(key):返回并删除名称为key的list中的首元素 rpop(key):返回并删除名称为key的list中的尾元素 blpop(key1, key2,… key N, timeout):lpop命令的block版本。即当timeout为0时,若遇到名称为key i的list不存在或该list为空,则命令结束。如果timeout>0,则遇到上述情况时,等待timeout秒,如果问题没有解决,则对keyi+1开始的list执行pop操作。
  • brpop(key1, key2,… key N, timeout):rpop的block版本。参考上一命令。
  • rpoplpush(srckey, dstkey):返回并删除名称为srckey的list的尾元素,并将该元素添加到名称为dstkey的list的头部

5、对Set操作的命令

  • sadd(key, member):向名称为key的set中添加元素member
  • srem(key, member) :删除名称为key的set中的元素member
  • spop(key) :随机返回并删除名称为key的set中一个元素
  • smove(srckey, dstkey, member) :将member元素从名称为srckey的集合移到名称为dstkey的集合
  • scard(key) :返回名称为key的set的基数
  • sismember(key, member) :测试member是否是名称为key的set的元素
  • sinter(key1, key2,…key N) :求交集
  • sinterstore(dstkey, key1, key2,…key N) :求交集并将交集保存到dstkey的集合
  • sunion(key1, key2,…key N) :求并集
  • sunionstore(dstkey, key1, key2,…key N) :求并集并将并集保存到dstkey的集合
  • sdiff(key1, key2,…key N) :求差集
  • sdiffstore(dstkey, key1, key2,…key N) :求差集并将差集保存到dstkey的集合
  • smembers(key) :返回名称为key的set的所有元素
  • srandmember(key) :随机返回名称为key的set的一个元素

6、对zset(sorted set)操作的命令

  • zadd(key, score, member):向名称为key的zset中添加元素member,score用于排序。如果该元素已经存在,则根据score更新该元素的顺序。
  • zrem(key, member) :删除名称为key的zset中的元素member
  • zincrby(key, increment, member) :如果在名称为key的zset中已经存在元素member,则该元素的score增加increment;否则向集合中添加该元素,其score的值为increment
  • zrank(key, member) :返回名称为key的zset(元素已按score从小到大排序)中member元素的rank(即index,从0开始),若没有member元素,返回“nil”
  • zrevrank(key, member) :返回名称为key的zset(元素已按score从大到小排序)中member元素的rank(即index,从0开始),若没有member元素,返回“nil”
  • zrange(key, start, end):返回名称为key的zset(元素已按score从小到大排序)中的index从start到end的所有元素
  • zrevrange(key, start, end):返回名称为key的zset(元素已按score从大到小排序)中的index从start到end的所有元素
  • zrangebyscore(key, min, max):返回名称为key的zset中score >= min且score <= max的所有元素 zcard(key):返回名称为key的zset的基数 zscore(key, element):返回名称为key的zset中元素element的score zremrangebyrank(key, min, max):删除名称为key的zset中rank >= min且rank <= max的所有元素 zremrangebyscore(key, min, max) :删除名称为key的zset中score >= min且score <= max的所有元素
  • zunionstore / zinterstore(dstkeyN, key1,…,keyN, WEIGHTS w1,…wN, AGGREGATE SUM|MIN|MAX):对N个zset求并集和交集,并将最后的集合保存在dstkeyN中。对于集合中每一个元素的score,在进行AGGREGATE运算前,都要乘以对于的WEIGHT参数。如果没有提供WEIGHT,默认为1。默认的AGGREGATE是SUM,即结果集合中元素的score是所有集合对应元素进行SUM运算的值,而MIN和MAX是指,结果集合中元素的score是所有集合对应元素中最小值和最大值。

7、对Hash操作的命令

  • hset(key, field, value):向名称为key的hash中添加元素field<—>value
  • hget(key, field):返回名称为key的hash中field对应的value
  • hmget(key, field1, …,field N):返回名称为key的hash中field i对应的value
  • hmset(key, field1, value1,…,field N, value N):向名称为key的hash中添加元素field i<—>value i
  • hincrby(key, field, integer):将名称为key的hash中field的value增加integer
  • hexists(key, field):名称为key的hash中是否存在键为field的域
  • hdel(key, field):删除名称为key的hash中键为field的域
  • hlen(key):返回名称为key的hash中元素个数
  • hkeys(key):返回名称为key的hash中所有键
  • hvals(key):返回名称为key的hash中所有键对应的value
  • hgetall(key):返回名称为key的hash中所有的键(field)及其对应的value

8、持久化

  • save:将数据同步保存到磁盘
  • bgsave:将数据异步保存到磁盘
  • lastsave:返回上次成功将数据保存到磁盘的Unix时戳
  • shundown:将数据同步保存到磁盘,然后关闭服务

9、远程服务控制

  • info:提供服务器的信息和统计
  • monitor:实时转储收到的请求
  • slaveof:改变复制策略设置
  • config:在运行时配置Redis服务器

Redis高级应用
1、安全性
设置客户端连接后进行任何操作指定前需要密码,一个外部用户可以再一秒钟进行150W次访问,具体操作密码修改设置redis.conf里面的requirepass属性给予密码,当然我这里给的是primos
之后如果想操作可以采用登陆的时候就授权使用:
sudo /opt/java/redis/bin/redis-cli -a primos
或者是进入以后auth primos然后就可以随意操作了

2、主从复制
做这个操作的时候我准备了两个虚拟机,ip分别是192.168.15.128和192.168.15.133
通过主从复制可以允许多个slave server拥有和master server相同的数据库副本
具体配置是在slave上面配置slave
slaveof 192.168.15.128 6379
masterauth primos
如果没有主从同步那么就检查一下是不是防火墙的问题,我用的是ufw,设置一下sudo ufw allow 6379就可以了
这个时候可以通过info查看具体的情况

3、事务处理
redis对事务的支持还比较简单,redis只能保证一个client发起的事务中的命令可以连续执行,而中间不会插入其他client的命令。当一个client在一个连接中发出multi命令时,这个连接会进入一个事务的上下文,连接后续命令不会立即执行,而是先放到一个队列中,当执行exec命令时,redis会顺序的执行队列中的所有命令。
比如我下面的一个例子
set age 100
multi
set age 10
set age 20
exec
get age –这个内容就应该是20
multi
set age 20
set age 10
exec
get age –这个时候的内容就成了10,充分体现了一下按照队列顺序执行的方式
discard 取消所有事务,也就是事务回滚
不过在redis事务执行有个别错误的时候,事务不会回滚,会把不错误的内容执行,错误的内容直接放弃,目前最新的是2.6.7也有这个问题的
乐观锁
watch key如果没watch的key有改动那么outdate的事务是不能执行的

4、持久化机制
redis是一个支持持久化的内存数据库
snapshotting快照方式,默认的存储方式,默认写入dump.rdb的二进制文件中,可以配置redis在n秒内如果超过m个key被修改过就自动做快照
append-only file aof方式,使用aof时候redis会将每一次的函 数都追加到文件中,当redis重启时会重新执行文件中的保存的写命
令在内存中。
5、发布订阅消息 sbusribe publish操作,其实就类似linux下面的消息发布
6、虚拟内存的使用
可以配置vm功能,保存路径,最大内存上线,页面多少,页面大小,最大工作线程
临时修改ip地址ifconfig eth0 192.168.15.129

redis-cli参数
Usage: redis-cli [OPTIONS] [cmd [arg [arg …]]]
-h Server hostname (default: 127.0.0.1)
-p Server port (default: 6379)
-s Server socket (overrides hostname and port)
-a Password to use when connecting to the server
-r Execute specified command N times
-i When -r is used, waits seconds per command.
It is possible to specify sub-second times like -i 0.1
-n Database number
-x Read last argument from STDIN
-d Multi-bulk delimiter in for raw formatting (default: \n)
-c Enable cluster mode (follow -ASK and -MOVED redirections)
–raw Use raw formatting for replies (default when STDOUT is not a tty)
–latency Enter a special mode continuously sampling latency
–slave Simulate a slave showing commands received from the master
–pipe Transfer raw Redis protocol from stdin to server
–bigkeys Sample Redis keys looking for big keys
–eval Send an EVAL command using the Lua script at
–help Output this help and exit
–version Output version and exit

Examples:
cat /etc/passwd | redis-cli -x set mypasswd
redis-cli get mypasswd
redis-cli -r 100 lpush mylist x
redis-cli -r 100 -i 1 info | grep used_memory_human:
redis-cli –eval myscript.lua key1 key2 , arg1 arg2 arg3
(Note: when using –eval the comma separates KEYS[] from ARGV[] items)

常用命令:
1) 查看keys个数
keys * // 查看所有keys
keys prefix_* // 查看前缀为”prefix_”的所有keys

2) 清空数据库
flushdb // 清除当前数据库的所有keys
flushall // 清除所有数据库的所有keys

常用Openssl命令

申请证书

SSL常用于身份验证、数据加密等应用中,要使用SSL,我们密码有自己的证书。数字证书一般要向专业的认证公司(如VeriSign)申请,并且 都是收费的,某些情况下,我们只是想使用加密的数据通信,而不在乎认证,这时就可以自己制作一个证书,自己制作一个证书,有两种方式,一种是Self Signed,另一种是自己制作一个CA,然后由这个CA,来发布我们需要的证书。下面分别介绍这两个方法。

生成Self Signed证书

# 生成一个key,你的私钥,openssl会提示你输入一个密码,可以输入,也可以不输,
# 输入的话,以后每次使用这个key的时候都要输入密码,安全起见,还是应该有一个密码保护
> openssl genrsa -des3 -out selfsign.key 4096

# 使用上面生成的key,生成一个certificate signing request (CSR)
# 如果你的key有密码保护,openssl首先会询问你的密码,然后询问你一系列问题,
# 其中Common Name(CN)是最重要的,它代表你的证书要代表的目标,如果你为网站申请的证书,就要添你的域名。
> openssl req -new -key selfsign.key -out selfsign.csr

# 生成Self Signed证书 selfsign.crt就是我们生成的证书了
> openssl x509 -req -days 365 -in selfsign.csr -signkey selfsign.key -out selfsign.crt

# 另外一个比较简单的方法就是用下面的命令,一次生成key和证书
> openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout privateKey.key -out certificate.crt

生成自己的CA (Certificate Authority)

CA是证书的发布者,CA可以发布其他人的证书,把CA的证书加入系统信任的根证书后,由CA发布的证书也被系统所信任,所以,CA的key是必须小心保护的,一般都要加密保护,并且限制为root权限读写。

# 生成CA的key
> openssl genrsa -des3 -out ca.key 4096

# 生成CA的证书
> openssl req -new -x509 -days 365 -key ca.key -out ca.crt

# 生成我们的key和CSR这两步与上面Self Signed中是一样的
> openssl genrsa -des3 -out myserver.key 4096
> openssl req -new -key myserver.key -out myserver.csr

# 使用ca的证书和key,生成我们的证书
# 这里的set_serial指明了证书的序号,如果证书过期了(365天后),
# 或者证书key泄漏了,需要重新发证的时候,就要加1
> openssl x509 -req -days 365 -in myserver.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out myserver.crt

查看证书

# 查看KEY信息
> openssl rsa -noout -text -in myserver.key
# 查看CSR信息
> openssl req -noout -text -in myserver.csr

# 查看证书信息
> openssl x509 -noout -text -in ca.crt

# 验证证书
# 会提示self signed
> openssl verify selfsign.crt

# 因为myserver.crt 是幅ca.crt发布的,所以会验证成功
> openssl verify -CAfile ca.crt myserver.crt

去掉key的密码保护

有时候每次都要输入密码太繁琐了,可以把Key的保护密码去掉

> openssl rsa -in myserver.key -out server.key.insecure

不同格式证书的转换

一般证书有三种格式:

  • PEM(.pem) 前面命令生成的都是这种格式,
  • DER(.cer .der) Windows 上常见
  • PKCS#12文件(.pfx .p12) Mac上常见

# PEM转换为DER
> openssl x509 -outform der -in myserver.crt -out myserver.der

# DER转换为PEM
> openssl x509 -inform der -in myserver.cer -out myserver.pem

# PEM转换为PKCS
> openssl pkcs12 -export -out myserver.pfx -inkey myserver.key -in myserver.crt -certfile ca.crt

# PKCS转换为PEM
> openssl pkcs12 -in myserver.pfx -out myserver2.pem -nodes

测试证书

Openssl提供了简单的client和server工具,可以用来模拟SSL连接,做测试使用。

# 连接到远程服务器
> openssl s_client -connect www.google.com.hk:443

# 模拟的HTTPS服务,可以返回Openssl相关信息
# -accept 用来指定监听的端口号
# -cert -key 用来指定提供服务的key和证书
> openssl s_server -accept 443 -cert myserver.crt -key myserver.key -www

# 可以将key和证书写到同一个文件中
> cat myserver.crt myserver.key > myserver.pem
# 使用的时候只提供一个参数就可以了
> openssl s_server -accept 443 -cert myserver.pem -www

# 可以将服务器的证书保存下来
> openssl s_client -connect www.google.com.hk:443 remoteserver.pem
# 转换成DER文件,就可以在Windows下直接查看了
> openssl x509 -outform der -in remoteserver.pem -out remoteserver.cer

计算MD5和SHA1

# MD5 digest
> openssl dgst -md5 filename
# SHA1 digest
> openssl dgst -sha1 filename

Ubuntu 14.04 安装 Ejbca (Install Ejbca on Ubuntu 14.04)

[warning]首先,如果不是万不得已,请不要使用 EJBCA,请不要阅读本文章!这个软件真的不是正常人可以驾驭的!如果只是个人兴趣(比如我就是装着好玩),那么请千万不要尝试使用 EJBCA!非常蛋疼!千万不要用!而且这玩意的搭建特别看脸,说不定啥时候就成功了。本文的成功方法并无法复制。[/warning]

这个玩意毕竟是一个商业软件的社区免费版,功能先不说,Bug一定是比商业版多一大堆的。而且官方给的文档也基本都很老了,并且不全,大部分你遇到的问题官方文档都不会说的。官方文档似乎最喜欢教你怎么配置,当然反正按照那个配一样成功不了。。。官方这么做当然另一个目的就是卖收费服务,不然免费的随便配置下就成功了谁还买呢。。。

至于官方的 Quick Start,直接无视吧。如果你按照官方的 Quick Start 成功的把服务搭起来了,那我只能佩服你了。。。反正我一开始一直遵照官方的教程死活也没有成功过一次。直到我找到一篇第三方的教程,才终于成功了一次。原教程地址:http://ejbcacentos.blogspot.hk/2014/04/how-to-install-ejbca-611-on-centos-65.html 因为是全英文的而且需要科学上网来访问,所以我在这里参考这篇教程把我配置的过程写一下。如果按照教程配置不成功请不要提问!我也不知道为什么!我自己配十次能成功一次就很开心了!


介绍

EJBCA 是一个用 Java 编写的可以在网页上完成所有操作的全功能 CA 服务器,只要是 CA 应该支持的功能这个软件全都支持。但是!这个软件的安装完全不像官方说的那么简单!如果你只是想玩玩,建议直接下载官方的虚拟机镜像玩吧。

准备

首先要安装相关依赖。因为我在后端数据库的选择上使用的是 Mysql,所以我需要装这么些东西:
sudo apt-get install openjdk-7-jdk ant ant-optional unzip ntp mysql-server libmysql-java
那篇教程里说 Java 7 会有问题,实际上似乎已经修复了,所以可以直接用。源里 ant 的版本是 1.8.2,满足最低的版本要求,所以也可以直接用,不用下载最新的。libmysql-java 是 Java 连接 Mysql 数据库所需要的必须的组建,因为我使用 Mysql 作为后端,所以需要安装。然后防火墙什么的就不管他了,建议你在确定配置成功的情况下再去搞别的,不然纯属浪费时间。。。

配置 Mysql

mysql 主要是要更改一下默认的编码,确保一直使用 UTF-8 作为编码方式,防止乱码。在 my.cnf 中加入这一段:
#UTF-8
character-set-server=utf8
collation-server=utf8_unicode_ci
init-connect='SET NAMES utf8'
#character-set-client = utf8

然后使用 root 账号登陆,新建数据库和账号:
service mysqld start
mysql_secure_installation
mysql -u root -p
create database ejbcadb;
grant all privileges on ejbcadb.* to 'ejbcadbuser'@'localhost' identified by 'password';
flush privileges;
exit

然后确认一下你刚刚创建的账号可以正常的访问数据库:
mysql -u ejbcadbuser -p
use ejbcadb;
show grants for ejbcadbuser@localhost;
exit

创建用户

建议不要直接使用 root 用户来安装 EJBCA,而是分配专门的账户。所以我们使用 adduser ejbca 添加一个用户。然后执行 su – ejbca,切换到 ejbca 用户下操作。

下载 Ejbca 和 Jboss

wget http://download.jboss.org/jbossas/7.1/jboss-as-7.1.1.Final/jboss-as-7.1.1.Final.zip
wget http://downloads.sourceforge.net/project/ejbca/ejbca6/ejbca_6_2_0/ejbca_ce_6_2_0.zip
unzip *.zip
ln -s ejbca_ca_6_2_0 ejbca
ln -s jboss-as-7.1.1.Final jboss

配置 Jboss

cd /opt/jboss/modules/sun/jdk/main
vi module.xml

在适当位置添加下面几行:(注释不要加进去)
### Start module.xml Delta ###

### End module.xml Delta ###

安装 Mysql 连接组件

cd ~
mkdir -p jboss/modules/com/mysql/main/
ln -s /usr/share/java/mysql.jar
vi module.xml

新建 module.xml 文件,写入如下内容:
### Start module.xml ###










### End module.xml ###
现在可以启动 Jboss 了。打开一个新的终端或者使用 screen 执行 ~/jboss/bin/standalone.sh。日志会写入 ~/jboss/standalone/log/
如果你看到这样的日志,说明 Jboss 应该是启动成功了:
22:51:40,482 INFO [org.apache.coyote.http11.Http11Protocol] (MSC service thread 1-2) Starting Coyote HTTP/1.1 on http--127.0.0.1-8080
22:51:40,688 INFO [org.jboss.as.remoting] (MSC service thread 1-3) JBAS017100: Listening on /127.0.0.1:4447
22:51:40,690 INFO [org.jboss.as.remoting] (MSC service thread 1-2) JBAS017100: Listening on /127.0.0.1:9999
22:51:40,699 INFO [org.jboss.as.server.deployment.scanner] (MSC service thread 1-3) JBAS015012: Started FileSystemDeploymentService for directory /opt/jboss/standalone/deployments
22:51:40,773 INFO [org.jboss.as] (Controller Boot Thread) JBAS015951: Admin console listening on http://127.0.0.1:9990
22:51:40,774 INFO [org.jboss.as] (Controller Boot Thread) JBAS015874: JBoss AS 7.1.1.Final "Brontes" started in 1528ms - Started 130 of 204 services (74 services are passive or on-demand)

接下来给 Jboss 添加 Mysql 连接器:
cd ~/jboss/bin
sh jboss-cli.sh
connect
/subsystem=datasources/jdbc-driver=com.mysql.jdbc.Driver:add(driver-name=com.mysql.jdbc.Driver,driver-module-name=com.mysql,driver-xa-datasource-class-name=com.mysql.jdbc.jdbc.jdbc2.optional.MysqlXADataSource)
:reload
exit

这句话在 ~/jboss/standalone/configuration/standalone.xml 中定义了 Mysql Driver ,然后重启 Jboss。
接下来修改 Jboss 的配置文件,删掉自带的 h2 数据库:
### Start standalone.xml Delta ###

删除这一段:


jdbc:h2:mem:test;DB_CLOSE_DELAY=-1
h2

sa sa

还有这一段:


org.h2.jdbcx.JdbcDataSource

### End standalone.xml Delta ###
好了!现在可以开始配置 Ejbca 了。

配置 Ejbca

Ejbca 的配置文件在这个文件夹里:
~/ejbca/conf/
默认配置文件都以 .sample 结尾。需要修改的话删除 .sample 然后进行相应的修改即可。
cd ~/ejbca/conf
cp certstore.properties.sample certstore.properties
cp cesecore.properties.sample cesecore.properties
cp crlstore.properties.sample crlstore.properties
cp database.properties.sample database.properties
cp ejbca.properties.sample ejbca.properties
cp install.properties.sample install.properties
cp mail.properties.sample mail.properties
cp web.properties.sample web.properties

接下来是要改的配置。这里只放出需要修改的行:
certstore.properties

### Start certstore.properties ###

certstore.enabled=true

certstore.contextroot=/certificates

### End certstore.properties ###

cesecore.properties

### Start cesecore.properties ###

ca.toolateexpiredate=80000000

securityeventsaudit.implementation.X=org.cesecore.audit.impl.log4j.Log4jDevice
securityeventsaudit.implementation.X=org.cesecore.audit.impl.integrityprotected.IntegrityProtectedDevice

securityeventsaudit.implementation.0=org.cesecore.audit.impl.log4j.Log4jDevice
securityeventsaudit.implementation.1=org.cesecore.audit.impl.integrityprotected.IntegrityProtectedDevice
securityeventsaudit.exporter.1=org.cesecore.audit.impl.AuditExporterXml

### End cesecore.properties ###

crlstore.properties

### Start crlstore.properties ###

crlstore.enabled=true
crlstore.contextroot=/crls

### End crlstore.properties ###

database.properties

### Start database.properties ###

datasource.jndi-name=EjbcaDS

database.name=mysql

database.url=jdbc:mysql://127.0.0.1:3306/ejbcadb?characterEncoding=UTF-8
database.driver=com.mysql.jdbc.Driver

database.username=ejbcadbuser

# Change this to your mysql user password:
database.password=pumpkin

### End database.properties ###

ejbca.properties

### Start ejbca.properties ###

appserver.home=/home/ejbca/jboss
appserver.type=jboss

ejbca.productionmode=false

approval.defaultrequestvalidity=28800
approval.defaultapprovalvalidity=28800

healthcheck.amountfreemem=32
healthcheck.dbquery=Select 1 From CertificateData where fingerprint='XX'
healthcheck.authorizedips=127.0.0.1
healthcheck.catokensigntest=true
healthcheck.publisherconnections=true
healthcheck.okmessage=ALLOK
healthcheck.sendservererror=true

ejbca.passwordlogrounds=8

### End ejbca.properties ###

install.properties

### Start install.properties ###

ca.name=mgmtca
ca.dn=CN=mgmtca,O=Your Company,C=US
ca.tokentype=soft
ca.tokenpassword=null

ca.keyspec=4096

ca.keytype=RSA

ca.signaturealgorithm=SHA256WithRSA

ca.validity=3652
ca.policy=null
ca.certificateprofile=ROOTCA

### End install.properties ###

mail.properties

### Start mail.properties ###

mail.jndi-name=java:/EjbcaMail
mail.user=ejbca
mail.password=honeybunny
mail.smtp.host=localhost
mail.smtp.port=25
#mail.smtp.auth=false
#mail.smtp.starttls.enable=false
mail.from=ejbca@yourcompany.net
#mail.debug=false
mail.contentencoding=UTF-8

### End mail.properties ###

web.properties

### Start web.properties ###

superadmin.cn=superadmin
superadmin.dn=CN=${superadmin.cn},O=Your Company,C=US

superadmin.batch=true

httpsserver.hostname=rootca.yourdomain.net
httpsserver.dn=CN=${httpsserver.hostname},O=Your Company,C=US

httpserver.pubhttp=8080

httpserver.pubhttps=8442

httpserver.privhttps=8443
#httpserver.external.privhttps=443

#httpserver.external.fqdn=
#httpserver.external.fqdn=${httpsserver.hostname}

#httpsserver.bindaddress.pubhttp=0.0.0.0
#httpsserver.bindaddress.pubhttps=0.0.0.0
#httpsserver.bindaddress.privhttps=0.0.0.0

web.contentencoding=UTF-8

web.selfreg.enabled=false
web.selfreg.defaultcerttype=1
web.selfreg.certtypes.1.description=User certificate
web.selfreg.certtypes.1.eeprofile=user
web.selfreg.certtypes.1.certprofile=user
web.renewalenabled=false
web.errorpage.notification=An exception has occurred.
web.errorpage.stacktrace=true

web.log.adminremoteip=true

### End web.properties ###
好了!下面可以开始尝试编译了。
cd ~/ejbca
ant deploy

部署的过程中可能会出这么几个问题:
06:05:16,848 ERROR [org.jboss.as.controller.management-operation] (management-handler-thread - 1) JBAS014612: Operation ("composite") failed - address: ([]): java.lang.IllegalArgumentException

06:05:39,477 ERROR [org.hibernate.internal.util.xml.ErrorLogger] (MSC service thread 1-4) HHH000196: Error parsing XML (21) : cvc-complex-type.3.1: Value '1.0' of attribute 'version' of element 'entity-mappings' is not valid with respect to the corresponding attribute use. Attribute 'version' has a fixed value of '2.0'.

15:29:58,915 SEVERE [javax.enterprise.resource.webcontainer.jsf.application] (MSC service thread 1-2) JSF1051: Service entry 'org.jboss.as.web.deployment.jsf.JsfInjectionProvider' does not extend DiscoverableInjectionProvider. Entry will be ignored.
这些问题可以直接无视,这是因为 Jboss 的 Bug。当然,这些问题可能会导致部署失败。那就多试几次吧。。。
如果你在 Jboss 的日志中看到了这个,说明你可能部署成功了:
01:38:38,724 INFO [org.jboss.as] (MSC service thread 1-1) JBAS015874: JBoss AS 7.1.1.Final "Brontes" started in 7761ms - Started 2855 of 2968 services (111 services are passive or on-demand)
01:38:38,769 INFO [org.jboss.as.server] (DeploymentScanner-threads - 2) JBAS018559: Deployed "ejbca.ear"

顺便一说,部署的过程中你会看到大量的:
appserver.error.message:
[echo] jndi.properties.file: /home/ejbca/ejbca_ce_6_2_0/conf/jndi.properties.jboss7

没关系,这个我可以确定是完全正常,丝毫不影响后续的。。。

接下来重启 Jboss ,到之前打开的另一个终端或者 screen , Ctrl+C 结束掉 Jboss ,然后重新启动。
之后,回到 ~/ejbca ,执行 ant install
当你看到:

[echo] Initializing CA with 'mgmtCA' 'CN=mgmtca,O=Your Company,C=US' 'soft'

说明你的配置文件没有问题了,至于各种证书和存储库能不能正常生成,还是看脸。

如果你在终端看到 ant 返回 BUILD SUCCESS ,并且重启 Jboss 后能看到这样的日志,恭喜你,配置成功了!
06:20:59,482 INFO [org.jboss.web] (MSC service thread 1-3) JBAS018210: Registering web context: /${app.name}/publicweb/status
06:20:59,484 INFO [org.jboss.web] (MSC service thread 1-3) JBAS018210: Registering web context: /ejbca/publicweb/apply
06:20:59,491 INFO [org.jboss.web] (MSC service thread 1-3) JBAS018210: Registering web context: /ejbca/publicweb/webdist
06:20:59,506 INFO [org.jboss.web] (MSC service thread 1-3) JBAS018210: Registering web context: /ejbca/publicweb
06:20:59,516 INFO [org.jboss.web] (MSC service thread 1-3) JBAS018210: Registering web context: /ejbca/publicweb/healthcheck
06:20:59,521 INFO [org.jboss.web] (MSC service thread 1-3) JBAS018210: Registering web context: /ejbca/clearcache
06:20:59,521 INFO [org.jboss.web] (MSC service thread 1-3) JBAS018210: Registering web context: /ejbca/ejbcaws
06:20:59,571 INFO [org.jboss.web] (MSC service thread 1-4) JBAS018210: Registering web context: /ejbca
06:20:59,727 INFO [org.jboss.web] (MSC service thread 1-1) JBAS018210: Registering web context: /crls
06:20:59,728 INFO [org.jboss.web] (MSC service thread 1-2) JBAS018210: Registering web context: /certificates
06:21:00,141 INFO [org.jboss.web] (MSC service thread 1-3) JBAS018210: Registering web context: /ejbca/adminweb
06:21:16,576 INFO [org.jboss.web] (MSC service thread 1-1) JBAS018210: Registering web context: /ejbca/doc

WSDL published to: file:/opt/jboss-as-7.1.1.Final/standalone/data/wsdl/ejbca.ear/ejbca-ws-ejb.jar/EjbcaWSService.wsdl

接下来从服务器上将 superadmin.p12 拷贝出来,导入浏览器,就可以访问管理页面了!

当然,按照我的经验,看到这里的人 99% 都是要被坑的,你应该是无法正常安装的。如果没成功的话,不要灰心,多试几次。我将上述过程整整重新执行了一天,才最终装好一个。然后因为要修改一些配置,又挂了。所以说,这玩意能不碰就不碰,我已经在开头警告过了。。。

使用 stunnel 加密原本不支持加密的连接

之前在国内的 TX 云主机上安装了 cow 作为连接国外 ss 的跳板。最近由于 Wifi 安全问题被各种关注,就想到 cow 本身是只支持 http 协议的。也就是说,我跟这个代理的任何通信理论上都能被同一 AP 下的其它机器截获。

为了解决这个问题,同时也作为某些公众 Wifi 禁止连接 VPN 的解决方案,我使用了 stunnel 来将 cow 变为支持 https 的代理服务器。

PS:之所以使用 cow 而不是其它的专业代理服务器,是因为在使用 cow 的时候可以无缝连上国外网站,无痛上 Google ,所以。。。

下面说说配置过程:

因为 stunnel 已经发布到了 epel 源中,所以如果你的 CentOS 添加了 epel 源的话,可以直接 yum install stunnel. 如果想自己编译也不困难,下载源码 ./configure && make && make install 即可。下面主要说说配置:

如果你是用的 epel 源的 stunnel ,你会发现安装包已经自动建立了 /etc/stunnel/ 目录,只不过里面啥都没有。所以我们要先创建配置文件:

vim /etc/stunnel/stunnel.conf

写入如下内容:

cert = /etc/stunnel/stunnel.pem
chroot = /var/run/stunnel
setuid = nobody
setgid = nobody
pid = /stunnel.pid
debug = 7
options = NO_SSLv2
fips = no
compression = zlib

[cow]
accept = 8080
connect = 127.0.0.1:7777

其中[cow]段可以多次重复,这样的话可以一个配置文件加密多个程序,使用端口号区分。
注意,fips = no 如果不加上的话会出现这个错误:

FIPS_mode_set: 2D06C06E: error:2D06C06E:FIPS routines:FIPS_module_mode_set:fingerprint does not match

接下来写一个启动脚本放到 /etc/init.d/ 中:

vim /etc/init.d/stunnel
#!/bin/bash
#
# Script to run stunnel in daemon mode at boot time.
#
# Check http://www.gaztronics.net/ for the
# most up-to-date version of this script.
#
# This script is realeased under the terms of the GPL.
# You can source a copy at:
# http://www.fsf.org/copyleft/copyleft.html
#
# Please feel free to modify the script to suite your own needs.
# I always welcome email feedback with suggestions for improvements.
# Please do not email for general support. I do not have time to answer
# personal help requests.

# Author: Gary Myers MIIE MBCS
# email: http://www.gaztronics.net/webform/
# Revision 1.0 - 4th March 2005

#====================================================================
# Run level information:
#
# chkconfig: 2345 99 99
# description: Secure Tunnel
# processname: stunnel
#
# Run "/sbin/chkconfig --add stunnel" to add the Run levels.
# This will setup the symlinks and set the process to run at boot.
#====================================================================

#====================================================================
# Paths and variables and system checks.

# Source function library (It's a Red Hat thing!)
. /etc/rc.d/init.d/functions

# Check that networking is up.
#
[ ${NETWORKING} ="yes" ] || exit 0

# Path to the executable.
#
SEXE=`which stunnel`

# Path to the configuration file.
#
CONF=/etc/stunnel/stunnel.conf

# Check the configuration file exists.
#
if [ ! -f $CONF ] ; then
  echo "The configuration file cannot be found!"
exit 0
fi

CHROOT=`grep '^chroot' /etc/stunnel/stunnel.conf | head -n 1 | sed 's/ //g' | awk -F= '{ print $2 }'`
PIDFILE=`grep '^pid' /etc/stunnel/stunnel.conf | head -n 1 | sed 's/ //g' | awk -F= '{ print $2 }'`
if [ -n "$CHROOT" ]; then
    PIDFILE=$CHROOT/$PIDFILE
fi

# Path to the lock file.
#
LOCK_FILE=/var/lock/subsys/stunnel

#====================================================================

#====================================================================
# Run controls:

prog=$"stunnel"

RETVAL=0

# Start stunnel as daemon.
#
start() {
  if [ -f $LOCK_FILE ]; then
    echo "stunnel is already running!"
    exit 0
  else
    echo -n $"Starting $prog: "
    $SEXE $CONF
  fi

  RETVAL=$?
  [ $RETVAL -eq 0 ] && success
  echo
  [ $RETVAL -eq 0 ] && touch $LOCK_FILE
  return $RETVAL
}


# Stop stunnel.
#
stop() {
  if [ ! -f $LOCK_FILE ]; then
    echo "stunnel is not running!"
    exit 0

  else

    echo -n $"Shutting down $prog: "
    killproc -p $PIDFILE stunnel
    RETVAL=$?
    [ $RETVAL -eq 0 ]
     rm -f $LOCK_FILE
    echo
    return $RETVAL

  fi
}

# See how we were called.
case "$1" in
   start)
  start
  ;;
   stop)
  stop
  ;;
   restart)
  stop
  start
  ;;
   condrestart)
  if [ -f $LOCK_FILE ]; then
     stop
     start
     RETVAL=$?
  fi
  ;;
   status)
  status -p $PIDFILE stunnel
  RETVAL=$?
  ;;
   *)
    echo $"Usage: $0 {start|stop|restart|condrestart|status}"
    RETVAL=1
esac

exit $RETVAL

保存之后不要忘了给执行权限。
接下来就要配置证书了。将你的证书、私钥、CA证书按照如下顺序合并:

cat server.crt server.key ca.crt >/etc/stunnel/stunnel.pem

然后因为大部分人的私钥都是明文的,所以要注意这个文件的权限。如果文件权限比较危险的话 stunnel 会有提示。

chmod 600 /etc/stunnel/stunnel.pem

最后就是创建 stunnel 需要的临时文件夹并赋予权限了。

mkdir -p /var/run/stunnel/
chown nobody:nobody /var/run/stunnel

这个用户和组按照 stunnel.conf 中所写的来授权。
大功告成!来运行一下吧:

service stunnel start

使用 netstat -ntlp 来看看是否正常开始监听端口。如果监听正常就没有问题啦~

博客正式开启全站强制SSL

由于 Google 宣即将在Chrome浏览器中全面将HTTP网站标记为不安全(http://www.chromium.org/Home/chromium-security/marking-http-as-non-secure),我很早就想将博客开启全站HTTPS了。不过由于我的主机带宽不够,而且地理位置是在香港,所以无法在开启全站HTTPS之后提供较快的图片下载速度。而国内的CDN支持HTTPS的又少的可怜,只好开启了后台HTTPS,但是前台页面都没有开启HTTPS。
今天收到邮件看到七牛云存储做活动,发布了海外加速服务,于是就顺手去看了一眼。没想到无意中发现七牛已经开始给CDN部署HTTPS了。虽然只能使用自定义域名,但是对我没有影响,因为我是使用WP Super Cache插件将博客页面中的资源文件的链接在输出的时候直接替换成CDN的链接的,所以终于可以真正的开启全站HTTPS了。
现在再访问我的博客,如果使用HTTP访问,会被强制302到HTTPS的链接。在这个页面里查看源文件的话可以看到,资源文件都是从
https://dn-maoxian.qbox.me/
这个域名下载的。这就是七牛云存储的CDN域名。有了这个,再也不用担心HTTPS的页面什么CSS都加载不了被浏览器直接Block啦~

附上我的七牛邀请链接:

https://portal.qiniu.com/signup?code=3l7i9c6vk7qky

PS:不过七牛不好的一点是想得到免费额度需要身份认证。。。不过。。。这是国内CDN的通病了。。。没办法。。。这个就要自己权衡了~

开源堡垒机GateOne的安装、配置笔记

因为内部临时需要这么一套系统,所以搜搜查查,搞定了系统部署,使用pam认证的配置。
系统初始化是使用CentOS 6.5 Mini x64版本。

首先exports http_proxy和https_proxy,做好上网准备。

其次查看下安装需求。
http://liftoff.github.io/GateOne/About/index.html#prerequisites

这里有相关的包下载:
https://github.com/liftoff/GateOne/downloads

yum install -y http://download.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
yum update -y

yum install -y python-devel gcc dtach python-pip python-imaging python-kerberos
yum install -y https://github.com/downloads/liftoff/GateOne/tornado-2.4-1.noarch.rpm
cd /usr/local/src
git clone https://github.com/liftoff/GateOne.git

cd GateOne
python setup.py isntall

service gateone start
service gateone stop

vi /etc/gateone/conf.d/10server.conf

origins = [“x.x.x.x”]
address = “x.x.x.x”
https_redirect = True

vi /etc/gateone/conf.d/20authentication.conf
auth = “pam”
pam_realm = “AccessGateway1”
pam_service = “gateone”

vi /etc/sysconfig/iptables
增加80和443端口
service iptables reload

nohup python gateone.py &

在Safari下无法使用,报错如下:
The WebSocket connection was closed. Will attempt to reconnect every 5 seconds…
NOTE: Some web proxies do not work properly with WebSockets.

PC和Android中的Chrome正常。

vi /etc/pam.d/gateone
auth required pam_userdb.so db=/root/pam-test/login
account required pam_userdb.so db=/root/pam-test/login

https://github.com/liftoff/GateOne/issues/118
这里提到是PyPAM,别安装错了。

yum install git pam-devel pam PyPAM pam-devel

然后生成pam db:
vim login.txt
user1
user1passwd

该文件一行用户名一行密码。写好之后wq保存退出。
db_load -T -f login.txt -t hash login.db
然后pam认证需要使用的密码文件就生成好了。之后可以把login.txt删除避免被别人看到用户名密码。
至此GateOne安装完毕。

附:给GateOne添加SSL证书的办法:
修改server.conf
certificate = “/path/to/your/ssl.crt”
disable_ssl = False
ca_certs = “/path/to/your/ca.pem”
keyfile = “/path/to/your/ssl.key”
重新启动,GateOne就会使用你定义的证书来监听443端口了。这样在使用SSL访问的时候就不会出现证书错误了。