如何在 Linode 上搭建 Discourse 论坛

最近要准备开始做一件事情:需要从头搭建,运营并管理一个关于电子货币交易所的开源技术社区。这个开源社区包括在线论坛和 Github 上的相关开源项目,论坛用于讨论电子货币交易所的技术话题,以及用开源的方式管理和推动电子货币交易所向前发展。

关于论坛的选型和搭建,因为我一直管理 RubyChina 社区,且 RubyChina 是由华顺和社区的热心网友共同维护的一个开源项目,主要功能包括后台都围绕服务 RubyChina 社区为主,是一个比较典型的 Rails 应用,所以我一开始就考虑基于 RailsChina 来构建这个社区。但是考虑到将来这个社区可能要支持更多的语言,更通用,更好的用户体验以及背后有一个开发团队长期支持,于是 Discourse 成了一个更好的选择,36Kr 有一篇帖子 Discourse 的介绍——打造“下一代的论坛”,Discourse要做论坛界的WordPress

logo.png

Discourse 有一份如何在 Ubuntu Server 上的官方安装文档,我同时参考了这里这里,发现这两份中文文档有些步骤过时了,或者有些步骤可能不是最优方案,或者不求甚解,比如不应该直接用管理员用户来部署应用等问题。加上我自己日常部署应有的一些习惯,所以特地写下来自己如何在 Linode 上搭建论坛的详细步骤,以备将来作为参考。

如果是自己随便玩玩,开个虚拟机或者廉价的小内存 VPS 随便玩玩的话倒也无所谓,但是如果要真的拿来用的话,Discourse 推荐跑两个 Thin (NUM_WEBS=2) 服务进程的话,至少需要:

  • 2G 内存
  • 2G 交换分区
  • 双核处理器

如果要开更多的 Thin 服务进程,则可以处理更多的并发请求,当然内存和处理器都要加倍,注册 Linode 账号,选择数据中心,创建并启动基于 Ubuntu 12.04 TLS 的主机,然后以 root 用户的过程略过,具体可以看 Linode 的 Getting Started 文档。

Linode VPS 的基本设置

首先是简化登录过程,通过配置 SSH Public key 到 VPS 上,这样下次登录 VPS 将不再需要输入密码,在 Mac 下可以简单的通过 ssh-copy-id 搞定。

brew install ssh-copy-id  
ssh-copy-id root@ip_address_of_linode_vps  

上面的步骤会提示输入密码,提升成功后,编辑 ~/.ssh/config 并追加下面内容到文件底部,保存退出,然后就可以直接用 ssh linode_root 命令以管理员身份登录服务器了。

Host linode_root  
  Hostname ip_address_of_linode_vps
  User root
  IdentityFile ~/.ssh/id_rsa
  TCPKeepAlive yes

因为 Linode 上的系统都是预制的,不包含 hostname ,所以登录系统后第一步就是设置 hostname,文档上的例子是用 plato 作为 hostname,你可以选择任何符合 FQDN 规范的主机名。

echo "plato" > /etc/hostname  
hostname -F /etc/hostname  

更新了 hostname 之后,还需要更新 /etc/hosts, 只需要添加一行,将主机的 ip_address 和 hostname 对应即可。

127.0.0.1       localhost  
127.0.1.1       ubuntu  
ip_address      plato  

设置时区,Timezone 如果要选择中国的话,选择 Asia -> Shanghai 就可以了。

dpkg-reconfigure tzdata  

更新系统安装包,这是熟悉 Debian/Ubuntu 的人最熟悉不过的命令了

apt-get update  
apt-get upgrade  

添加一个 discourse 用户,然后把这个用户添加到 sudo 管理员组,这样可以之行 sudo 命令。还可以按照上面的步骤,通过修改 ~/.ssh/config 的方式让 discourse 用户也可以免密码 ssh 登录。

adduser discourse  
usermod -a -G sudo discourse  

完成用户添加后,就没有管理员什么事情了,登出,然后以 discourse 用户登录,下面的操作全部通过 discourse 用户完成。

安装 PostgreSQL 数据库

Discourse 的官方文档以安装 package group 开始,需要安装三个 package group:

  • sudo tasksel install openssh-server
  • sudo tasksel install mail-server
  • sudo tasksel install postgresql-server

其实 Linode 上已经预先安装好了 openssh-server,所以第一个不用安装。关于第二个 mail-server 我认为也不要安装!因为千万不要自己折腾邮件服务器,这个东西其实极为复杂,自建一个玩票可以,但是如果真的在生产环境的话,还是用第三方专业服务比较好。比如 mailgun 或者 postmark,如果专注国内用户的话,我推搜狐的 SendCloud

Discourse 使用 Postgres 数据库,所以这里只需要安装最后一个 postgresql-server。安装完成后需要创建一个数据库用户,并且可以给这个用户设置一个密码。

sudo -u postgres createuser -s discourse  
sudo -u postgres psql -c "alter user discourse password 'your_password';"  

安装 Redis

Redis 是一个基于内存的 key-value 数据库,Discourse 使用 Redis 作缓存以及后台任务队列服务。Discourse 推荐使用最新版本的 Redis 替换掉 Ubuntu 中自带的老旧版本,安装需要用到 apt-add-repository,而这个是由 python-software-properties 提供的,具体安装如下:

sudo apt-get install python-software-properties # 如果 Ubuntu 版本 >= 12.10 则安装 software-properties-common  
sudo apt-add-repository -y ppa:rwky/redis  
sudo apt-get update  
sudo apt-get install redis-server  

安装 Nginx

Discourse 使用 Nginx 作为前端代理服务器,包括提供静态文件的服务以及缓存优化等。Discourse 推荐用最新版本的 nginx,替换掉 Ubuntu 中自带的老旧版本,方法如下:

# 移除现有的安装包
sudo apt-get remove '^nginx.*$'

# 添加 nginx 安装源
cat <<'EOF' | sudo tee -a /etc/apt/sources.list

deb http://nginx.org/packages/ubuntu/ precise nginx  
deb-src http://nginx.org/packages/ubuntu/ precise nginx  
EOF

# 添加 nginx key
curl http://nginx.org/keys/nginx_signing.key | sudo apt-key add -

# 安装 nginx
sudo apt-get update && sudo apt-get -y install nginx  

安装 Ruby

Discourse 是一个用 Ruby 语言写的 Rails 应用,需要用 Ruby 语音来执行。这里通过 RVM 来安装 Ruby。RVM 是一个老牌的 Ruby 版本管理器,用 RVM 安装 Ruby 和同时管理 Ruby 多个版本非常方便。安装过程中,rvm 会自动安装编译 Ruby 需要的依赖包。其实 Discourse 团队非常重视性能,升级到支持 Ruby 2.1.0 已经在日程上了,很可能已经可以用最新版本的 Ruby 来跑应用了。

curl -s -S -L https://get.rvm.io | bash  
source ~/.bash_profile  
rvm install 2.0.0  
rvm use 2.0.0 --default  

安装完成后检查一下当前 Ruby 的版本,能正常看到 Ruby 的版本号就说明 Ruby 安装没有问题。

ruby -v  

安装其他依赖包

sudo apt-get install git imagemagick libpq-dev  

安装 Discourse

从 Github 上 clone Discourse 的源码,然后安装 Discourse 所以来的 gems。

mkdir ~/www  
cd ~/www  
git clone git://github.com/discourse/discourse.git  
cd discourse  
bundle install --deployment --without test  

配置 Discourse

首先需要准备好两个配置文件 discourse.confdiscourse.pill, discourse.conf 基于 quickstart 配置模板定制。

cp config/discourse_quickstart.conf config/discourse.conf  
cp config/discourse.pill.sample config/discourse.pill  

配置 config/discourse.conf

  • db_name 数据库名
  • hostname 你从外部访问论坛的主机名
  • smtp 服务器相关的配置,请以第三方 SMTP 邮件服务器配置信息为主
  • db_* 跟数据库相关的配置,包括数据库用户名,密码,数据主机等信息
  • redis 如果 VPS 上只跑 Discourse,没有其他应用使用 redis 的话,这部分不需要改动

配置 config/discourse.pill

Discourse 使用 Bluepill 来管理 Rails 的进程。

  • 默认应用名称是 "discourse",可以根据需要修改
  • 如果用管理员运行 bluepill 的话,需要注释掉普通用户执行对应的配置信息,具体可以查看文件内的注释内容

继续安装并配置 bluepill

gem install bluepill  
echo 'alias bluepill="NOEXEC_DISABLE=1 bluepill --no-privileged -c ~/.bluepill"' >> ~/.bash_aliases  
rvm wrapper $(rvm current) bootup bluepill  
rvm wrapper $(rvm current) bootup bundle  

初始化数据库

createdb your_db_name  
RUBY_GC_MALLOC_LIMIT=90000000 RAILS_ENV=production bundle exec rake db:migrate  

编译所有的静态文件

Rails 的所有静态文件 (static assets) 是需要预先编译的,编译命令。

RUBY_GC_MALLOC_LIMIT=90000000 RAILS_ENV=production bundle exec rake assets:precompile  

配置 Nginx

首先复制一份配置文件到 nginx 的配置文件目录

sudo cp ~/www/discourse/config/nginx.sample.conf /etc/nginx/conf.d/discourse.conf  

然后修改 /etc/nginx/nginx.conf 文件,在 http section 中添加 server_names_hash_bucket_size 64;

如果 VPS 上的 Discourse 是一个独立应用,则关闭掉 Nginx 的 default 网站。

sudo mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.disabled  

修改 /etc/nginx/conf.d/discourse.conf,包括

  • 配置 server_name
  • 修改 socket count 跟 Thin 服务器的进程数 (NUM_WEB) 一致
  • 将所有的 /var/www 换成 /home/discourse/www
sudo vim /etc/nginx/conf.d/discourse.conf  

配置完成后保存退出,检查 Nginx 的配置是否正确

sudo nginx -t  

让 nginx 重新加载配置文件

sudo services nginx reload  

自动切分 logs 配置

通过系统自带的 logrotate 来切分logs,执行命令 contab -e, 然后添加下面的内容即可。

0 0 * * * /usr/sbin/logrotate /home/discourse/www/discourse/config/logrotate.conf  

启动 Discourse

通过 bluepill 管理 Thin server 并启动 Discourse 的命令是

RUBY_GC_MALLOC_LIMIT=90000000 RAILS_ROOT=/home/discourse/www/discourse RAILS_ENV=production NUM_WEBS=2 bluepill --no-privileged -c ~/.bluepill load /home/discourse/www/discourse/config/discourse.pill  

查看 bluepill 的进程管理信息,可以看到启动了两个 Thin server 以及一个 sidekiq workder 后台任务。

bluepill status  

如果没有配置文件没有什么问题,这个时候在浏览器中访问 url,就应该可以看到 Discourse 论坛界面了。

为了重启后 Discourse 可以自动运行,可以把 bluepill 命令放到 contab 中,执行命令 crontab -e 然后写入下面的内容即可。

@reboot RUBY_GC_MALLOC_LIMIT=90000000 RAILS_ROOT=/home/discourse/www/discourse RAILS_ENV=production NUM_WEBS=2 /home/discourse/.rvm/bin/bootup_bluepill --no-privileged -c ~/.bluepill load /home/discourse/www/discourse/config/discourse.pill