如何用Discourse搭建一个论坛

Discourse是基于ruby on rails,Ember.js, PostgreSQL 和Redis的开源论坛,是由StackOverflow的联合创始人Jeff Atwood发起的,目的是成为下一代论坛,改变传统论坛的格局,成为论坛界的wordpress。

先说下我的使用感受吧,在try.discourse.org上可以体验的,首先是界面比较清爽,主体是白色的,很简洁。其次是摒弃了“板块”的概念,所有的帖子集中显示,用滚轮一直往下滑好了。然后是发帖和回复都十分方便,直接在当前页都可以完成,内容的编辑支持Markdown和BBCode,编辑的时候还可以在右侧直接预览,插入图片很方便,在网上看到一张图片之后可以右键复制图片,直接Ctrl+V就可以在编辑器内插入图片了,Discourse会自动完成复制并且上传到服务器上。

之前很早就用过Discuz!,但是这个论坛在国内用的实在是太普遍了,很多论坛的长的都是一个样子的。我感觉他最大的缺点是帖子中的每个回复都占用的很大的空间,在回复内容普遍很短的情况下,我每看一行回复都要滚动半个屏幕,这个最不能忍(哦对,还有坑爹的签名图片  = =)。Discourse做的比较合我胃口,一个回复的高度只有Discuz!的三分之一左右。

来说说安装吧,首先你要有个VPS或者云主机,可以使用阿里云,linode或者digitalocean等等,推荐内存是1G。

我安装的时候参照的是这篇文档 ,这个地方是以digital ocean为例来说明的,其他主机都大同小异。部署的时候需要用到docker,这个是个比较火的容器引擎,目前我还没有完全理解容器引擎到底指的是什么,“他可以打包引用和其依赖到linux上,实现虚拟化”,就当是个虚拟机好了恩。我选的是系统是Ubuntu 12.04.3 x64 LTS,按照文档上的教程升级了内核,我没有验证这一步是否是必要的,但是感觉虚拟化可能需要升级内核的东西,做了也无妨。

接下来是clone官方的docker镜像,修改配置文件app.yml,配置文件里面有几个需要注意的事情。ssh-key要设置,就是你从~/.ssh/id_rsa.pub拷贝到github上的那个东西,否则你没办法通过./launcher ssh app进入你的“虚拟机”。还有需要填写的是email地址和网站的host。邮箱相关的内容可能需要稍微折腾一点,我直接用的是mailgun的服务,maildraill貌似不让天朝的同学用,囧。。app.xml中邮箱配置的内容怎么填,mailgun里面都写的很清楚了,而且也说明了怎么在域名服务商那里添加邮件相关的记录。如果你嫌邮箱配置麻烦的话,就先略过吧。

最后执行./launcher bootstrap app和./launcher start app就可以让网站运行了。后续的折腾就是测试邮件是否配置成功,添加github,facebook,twitter的第三方登录功能了。如果你访问的时候出现了502错误,请检查你的内存是否只有512MB,内存小的话很容易出现这样的问题,出现这个问题的时候我一直搞不清楚哪里有问题,一直怀疑是配置错误,后来升级了内存之后就完全正常了。

还有一些缺点,由于网站很依赖javascript,SEO会比较差。其次中文本地化还不够完全,给官方提交什么的貌似比较麻烦。刚开始用,缺点应该还有很多没发现,不过看提交记录貌似挺频繁的,希望能越来越好。

我搭建了个论坛,域名是  http://android.hacking.today , 不过目前还不知道怎么搞。。当你搭建论坛的时候一定要想清楚到底该怎么搞,毕竟内容才是重点,用什么样的论坛不是最重要的。。

继续阅读 →

HTTP协议漫谈:概述

自从学习linux编程以来,一直对与服务器的工作原理十分感兴趣,想写一个,然而暑假由于各种原因耽搁了下来,前几天是课程设计,大概两周时间,我就趁这个时间,简单实现了一下。又恰逢《HTTP权威指南》出版,入手了一本,大概翻了一遍,对于HTTP的细节了解了很多,收获还是很大的。我简单总结一下,巩固知识&&方便以后查看。

HTTP,超文本传输协议,是使用非常广泛的网络协议,我们平时上网看新闻,刷微博都要依靠下面的http协议来传递信息。要传递信息,首先需要客户端发起连接,客户端和服务器建立链接之后,发送HTTP请求报文,服务器接受请求之后返回给客户端一个响应报文。请求和响应都是固定文本格式的,在协议中有明确的定义,之后会详解。HTTP底层是通过TCP进行通讯的,不过我们不必关心TCP的具体细节,只需要知道他提供可靠连接,并且在请求和响应完成后关闭连接(持久链接中有多次请求和响应)。

HTTP的请求可以有好几种,最常见的是GET请求(还有POST,HEAD等),他会向服务器请求资源(即“get”资源),同时会给一个资源的地址,这些东西放在请求报文的开头第一行,我们把这一行称为起始行。

GET /index.html HTTP/1.1\r\n

(更多…)

继续阅读 →

Markdown 简洁入门

最近折腾github比较多,在里面看到很多用Markdown的地方,比如wiki页面编辑,README.md文件,progit,感觉他是一个十分简单的标记语言,于是就打算学学。

Markdown的目标是实现“易读易写”,语法的目标是,“成为一种适用于网络的书写语言”。在写文档或者blog的时候可以避免一些排版上的苦恼。Markdown可以方便地转换为HTML,有对应关系,但他比HTML来的方便,因为不用考虑成对的标签。如果某些Markdown有某些标签没有实现,我们可以在文本中直接使用HTML语言。

在介绍语法之前,现在介绍一款chrome插件 – MaDe,此插件可以在页面右侧实时现实效果,很方便。如果对某些东西有疑惑,试验一下即可:)

(更多…)

继续阅读 →

Boa源码分析 – 4 – 转意处理

build_needs_escape函数目的是要建立一个位图bitmap,表示哪些字符需要转意。此函数在escape.c中,首先到escape.h中看看。

#include "config.h"

/* Highest character number that can possibly be passed through un-escaped */
#define NEEDS_ESCAPE_BITS 128
//表示128位就行
#ifndef NEEDS_ESCAPE_SHIFT
#define NEEDS_ESCAPE_SHIFT 5     /* 1 << 5 is 32 bits */
#endif

#define NEEDS_ESCAPE_WORD_LENGTH (1<<NEEDS_ESCAPE_SHIFT)
//
#define NEEDS_ESCAPE_INDEX(c) ((c)>>NEEDS_ESCAPE_SHIFT)
//index嘛,表示在_needs_escape中的第几个数上表示

/* Assume variable shift is fast, otherwise this could be a table lookup */
#define NEEDS_ESCAPE_MASK(c)  (1<<((c)&(NEEDS_ESCAPE_WORD_LENGTH - 1)))
//NEEDS_ESCAPE_WORD_LENGTH - 1相当于一个掩码,取c最右边的五bit,然后在把1左移这么多位,就可以通过它获得相应位的状态了

/* Newer compilers could use an inline function.
* This macro works great, as long as you pass unsigned int or unsigned char.
*/
#define needs_escape(c) ((c)>=NEEDS_ESCAPE_BITS || _needs_escape[NEEDS_ESCAPE_INDEX(c)]&NEEDS_ESCAPE_MASK(c))
//实现很简洁。。。
extern unsigned long _needs_escape[(NEEDS_ESCAPE_BITS+NEEDS_ESCAPE_WORD_LENGTH-1)/NEEDS_ESCAPE_WORD_LENGTH];
void build_needs_escape(void);

(更多…)

继续阅读 →

Boa源码分析 – 3 – 三个函数简析

下面看一下boa.c里面的三个函数:create_server_socket, drop_privs和 drop_privs。这三个函数都被声明为static表示,静态函数对普通函数的区别就是他只能在当前文件中可见。

static int create_server_socket(void)
{
int server_s;
server_s = socket(SERVER_AF, SOCK_STREAM, IPPROTO_TCP);
//创建套接字SERVER_AF在compat.h中声明被声明为INET或INET6
if (server_s == -1) {
DIE("unable to create socket");
}
//DIE在defines.h中的宏定义为
//#define DIE(mesg) log_error_mesg(__FILE__, __LINE__, mesg), exit(1)
//__FILE__和__LINE__分别表示当前文件和当前行
//log_error_mesg在log.c中有定义,向标准输出输出错误信息

/* server socket is nonblocking */
if (set_nonblock_fd(server_s) == -1) {
DIE("fcntl: unable to set server socket to nonblocking");
}//把套接字设定成非阻塞的,set_nonblock_fd在defines.h中为宏替代real_set_nonblock_fd(在util.c中定义)

/* close server socket on exec so cgi's can't write to it */
if (fcntl(server_s, F_SETFD, 1) == -1) {
DIE("can't set close-on-exec on server socket!");
}//将文件描述符标记设定为1,当执行exec族函数时关闭套接字

(更多…)

继续阅读 →

Boa源码分析 – 2 – boa.c流程

下面来看看boa.c吧

/* set umask to u+rw, u-x, go-rwx */
c = umask(~0600);
if (c == -1) {
perror("umask");
exit(1);
}
devnullfd = open("/dev/null", 0);
/* make STDIN and STDOUT point to /dev/null */
if (devnullfd == -1) {
DIE("can't open /dev/null");
}
if (dup2(devnullfd, STDIN_FILENO) == -1) {
DIE("can't dup2 /dev/null to STDIN_FILENO");
}
if (dup2(devnullfd, STDOUT_FILENO) == -1) {
DIE("can't dup2 /dev/null to STDOUT_FILENO");
}

这里设定了权限掩码为~600,也就是生成文件权限为rw——-,然后打开/dev/null,它相当于一个黑洞,输入任何东西都会丢失,读取也什么都读取不到,因为服务器进程是在守护进程,所以将标准输入输出定向到/dev/null。下面看getopt:
(更多…)

继续阅读 →

Boa源码分析 – 1 – Makefile

boa是一个小型的webserver,设计目标是速度和安全,虽然这个项目已经很多年没有更新了,但是对于初学linux编程,网络编程的同学来说。。还是很有价值的。boa的实际代码量只有7000+(去掉autotools自动生成的东西),初看压力不大。当然还有一些适合学习的开源项目,如thttpd(也是一个http server,代码12000+行),redis(key-value存储系统,和Memcached类似,里面貌似有好多数据结构?两万多行)和coreutils (常用linux命令源码,什么cd,chmod,cp等等),还有好多,github和sourceforge上有很丰富资源。。

直接入题吧,boa也用到了Autotools,但是我实在是搞不清楚autotools的几个命令是怎么组织的。。干脆直接./configure ,开始分析Makefile。
(更多…)

继续阅读 →

make 知识小记

/*写完来吐槽下,,make的语法够多够复杂的。。。*/

make 可以简化编译过程,如果有一个近百个源文件的项目,如果有个文件更改后工程需要重新编译,那么一直用gcc -c a.c这些个命令敲来敲去会屎人的。运行make时候,他会寻找指定目录下(默认是 .)的Makefile文件并且分析依赖关系进行必要的编译。

Makefile文件的基本格式很简单:

目标文件: 依赖文件1 依赖文件2 依赖文件3 。。。。

[tab]编译命令

他的意思是目标文件是依赖于冒号后面几个文件的,如果这些依赖文件有更新的,那么其目标文件也需要更新。
(更多…)

继续阅读 →

grep 用法简述

grep( global search regular expression(RE) and print out the line)是一个在文本中搜索模式并且把有匹配文本的行输出出来的工具,使用的前提是要知道一下正则表达式相关的知识。grep命令的基本格式如下

grep -选项 ‘搜索字符串’ 文件

当我们不加‘文件’参数的时候,grep默认从标准输入读入。每处理一行,如果能搜索到匹配模式的,就将整行输出出来。如果有很多文件,那么搜索到一行,将会在行前面加上文件名前缀。比如搜索当前文件夹下所有文件下有那些行包含‘fcntl‘ ,那么就用 grep ’fcntl‘ *。

不同的选项有不同的效果:

-c 输出匹配的行的数目
-i 忽略搜索串中的字母大小写
-n 输出行号
-v 反向选择,输出不满足要求的行
-a 在二进制文件中查找
-r 递归搜索子文件夹中的文件
-E 使用扩展正则表达式进行匹配, egrep 相当于 grep -E
-Hh h显示文件名前缀,H不显示。默认显示。
-A n 显示匹配行之后n行(After)
-B n 显示匹配行开始到之前n行(Before)
-C n 相当于-A n -B n = =||
-d recurse|read|skip recurse表示递归处理子目录(-d recurse先当于 -r),skip表示忽略,read表示把目录做成一般文件

grep包含的工具还有egre (更多…)

继续阅读 →

GCC编译流程与常用选项

学了很长时间的c和c++,对于gcc的用法还不是很清楚,只会用“gcc a.c -o a”这类的命令。至于预处理,编译,汇编,链接等过程不是十分清楚。前两天到图书馆借了本快速入门的书,学习了下,现在做个小小的总结。

编译的基本流程:

c(.c)和c++(.cc, .cpp, .cxx)的源文件 。

|| gcc -E a.c -o a.i // 如果不加-o参数,gcc会把处理过的源文件放到标准输出中

预处理后的源文件。c源文件预处理后后缀为.i, c++为.ii 。

|| gcc -S a.i //会在当前文件夹下生成a.s

编译后生成的汇编源代码。后缀为.s, .S 。

|| gcc -c a.s //只进行汇编生成目标文件,.o结尾的目标文件可以用(ar crv libabc.a a.o b.o c.o )打包成形如lib×××.a的静态库

目标文件与库文件进行链接,生成可执行文件。

||gcc  a.o //在当前文件夹下生成a.out

基本的过程就是以上四步。其中任何一种状态,用gcc如果不加-c,-E,-S选项都会直接生成可执行文件,如果加上了选项,可以由之前任一状态生成所需要的文件(如gcc -S a.c 可以直接生成a.s,gcc -c a.i可以直接生成a.o )。如果是c++直接换用g++命令就行。

另外gcc -v可以输出编译过程的配置和版本信息。

gcc警告提示: (更多…)

继续阅读 →