手动安装Discourse论坛程序

“论坛”作为上一代互联网产品,已经淡出了很多人的互联网生活了。不过,我仍然很喜欢“论坛”这一讨论模式。很多像我一样的互联网遗民,依旧喜欢在各论坛中水贴。今天我们就来介绍一下国外非常著名的Discourse论坛程序的安装与配置。

 

1, Discourse论坛程序简介

Discourse程序基于Ruby on Rails, Ember.js, 以及PostgreSQL, 完全免费开源。它拥有丰富的功能,强劲的性能,高稳定性与安全性,以及可以高度自定义的界面。其具体功能可以参考官网:https://www.discourse.org/.

Discourse可以使用Docker搭建,也可以纯手工搭建。Docker搭建比较简单,仅在第2节稍做介绍。手动安装可以让您学习Ruby on Rails程序的部署流程,且在排错搜索中提升自己的运维能力。手动部署的Discourse也可以显著降低系统要求。本文将主要介绍在Ubuntu 18.04 LTS操作系统中Discourse的手动搭建,不使用Docker.

本文许多内容翻译自Linuxbabe, 有删改。本文作者为香菇肥牛,原文链接为https://qing.su/article/install-discourse-without-docker.html,转载需注明原文链接。谢谢!

长文预警,现在开始!

 

2, Docker搭建简介

如果是生产环境,建议您使用Docker来部署Discourse, 因为它易于维护。Docker版本的Discourse是唯一的可以获得官方技术支持的版本。

使用Docker搭建Discourse非常简单,且支持Linux平台。您需要首先安装git, 然后执行下面的命令即可。引导程序将自动为您安装Docker和其他所有需要的组件。

1
2
3
git clone https://github.com/discourse/discourse_docker.git /var/discourse
cd /var/discourse
./discourse-setup

 

3, 手动安装的系统需求

手动安装的步骤仅在Ubuntu 18.04 LTS 64 bit操作系统上测试通过。Ubuntu 20.04 LTS 64 bit操作系统中可以使用一些方法非常麻烦地勉强安装成功(需要使用另一台Ubuntu 18.04的服务器做一次数据库移植),这里不做介绍了。其他Linux平台无法安装通过。

Discourse程序需要系统有至少1 GB内存。安装完毕后系统占用600 MB左右内存。安装过程需要约1-3小时,请留好时间。请将您的域名解析到服务器上。下文将以域名bbs.qing.su为例指代将要搭建的Discourse论坛域名。

 

4, 安装并配置PostgreSQL数据库

首先,安装PostgreSQL数据库程序

1
apt-get install postgresql

安装完毕后,PostgreSQL会自动运行在5432端口。然后,使用postgres账户登录postgresql并新建数据库,用户名,以及密码。

1
2
3
4
5
6
7
8
9
sudo -u postgres psql
        CREATE DATABASE discourse;
        CREATE USER discourse_user;
        ALTER USER discourse_user WITH encrypted password 'qing.su';
        ALTER DATABASE discourse owner TO discourse_user;
        \c discourse;
        CREATE extension hstore;
        CREATE extension pg_trgm;
        \q

这里,我们设置数据库名为discourse, 数据库用户名为discourse_user, 密码为qing.su

 

5, 安装Ruby和Bundler

Discourse是基于Ruby on Rails的,因此需要安装Ruby程序,以及Ruby程序的依赖环境的管理器Bundler.  Ubuntu 18.04版本的官方源中包含了Ruby 2.5版本,Ubuntu 20.04版本的官方源中包含了Ruby 2.7版本。然而,目前Discourse仅支持Ruby 2.6版本。因此,为了方便,我们使用snapd包管理器安装2.6版本的Ruby on Rails.  如果您不信邪地想要在Ubuntu 20.04上安装,这里需要手动编译安装对应的Ruby版本,不知为何snap安装的Ruby和Bundler之后会报错。

1
2
apt-get install snapd
snap install ruby --classic --channel=2.6/stable

第一次使用snap安装软件,需要退出SSH然后重新登录SSH.  重新登录后,继续安装Bundler.

1
/snap/bin/gem install bundler

 

6, 构建Discourse依赖环境

首先,使用git获取Discourse源代码。

1
2
3
4
5
apt-get install git gcc build-essential ruby-dev libxslt-dev libxml2-dev zlib1g-dev libpq-dev imagemagick screen redis-server optipng pngquant jhead jpegoptim gifsicle
git clone https://github.com/discourse/discourse.git
mkdir /var/www/
mv discourse/ /var/www/
cd /var/www/discourse/

然后前往https://github.com/discourse/discourse/releases查看当前的Discourse版本。我这里将使用v2.5.0.

1
git checkout 2.5.0

接下来,开始安装Discourse程序的依赖环境。这里需要安装的组件较多,时间较长,建议使用screen避免掉线后出现错误。

1
2
3
screen -S discourse
RAILS_ENV=production /snap/bin/bundle config set path '/var/www/discourse/vendor/bundle/'
RAILS_ENV=production /snap/bin/bundle install

安装完毕后,按下CTRL + A + D键退出screen.

 

7, 初始化Discourse数据库

依赖环境搭建完毕,我们开始配置Discourse.  编辑数据库连接文件:

1
2
cp config/discourse_defaults.conf config/discourse.conf
vi config/discourse.conf

找到下面几行,依次填入数据库信息:

1
2
3
4
5
db_host = localhost
db_port = 5432
db_name = discourse
db_username = discourse_user
db_password = qing.su

再找到hostname这行,填写论坛的域名:

1
hostname = "bbs.qing.su"

保存退出。再编辑生产环境ruby配置文件:

1
vi config/environments/production.rb

在该文件第5行添加:

1
require 'uglifier'

然后找到下面这行(我这里是第17行):

1
config.assets.js_compressor = :uglifier

将其替换成:

1
config.assets.js_compressor = Uglifier.new(harmony: true)

如下图所示:

保存退出。然后,执行下面的命令初始化数据库:

1
RAILS_ENV=production /snap/bin/bundle exec rake db:migrate

如果该命令执行过程中报错,请再执行一遍。

 

8, 编译静态文件

接下来,我们要编译静态文件,比如javascript文件等。编辑文件/var/www/discourse/lib/tasks/assets.rake, 找到并注释掉下面这行(我这里是第281行)。

1
brotli(path, max_compress)

注释掉这一行的原因是brotli压缩和gzip压缩一起编译的时候会冲突报错。

保存退出后,编译安装静态文件:

1
RAILS_ENV=production /snap/bin/bundle exec rake assets:precompile

 

9, 使用Puma服务器运行Discourse

完整的Discourse部署可以分为后端运行服务器程序与前端反代服务器程序。这一节,我们介绍使用Puma服务器运行Discourse.

编辑文件/var/www/discourse/config/puma.rb, 找到下面这行:

1
APP_ROOT = '/home/discourse/discourse'

将其替换为我们的Discourse安装目录:

1
APP_ROOT = '/var/www/discourse'

然后建好Puma服务器sockets目录:

1
2
mkdir /var/www/discourse/tmp/sockets/
mkdir /var/www/discourse/tmp/pids/

运行Discourse:

1
RAILS_ENV=production bundle exec puma -C /var/www/discourse/config/puma.rb

如果没有以外,屏幕上会显示一大堆内容,比如下面这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
root@server:/srv/www/forum/public_html# RAILS_ENV=production bundle exec puma -C /srv/www/forum/public_html/config/puma.rb
[13383] Puma starting in cluster mode...
[13383] * Version 4.3.5 (ruby 2.6.6-p146), codename: Mysterious Traveller
[13383] * Min threads: 8, max threads: 32
[13383] * Environment: development
[13383] * Process workers: 4
[13383] * Preloading application
[13383] * Listening on unix:///srv/www/forum/public_html/tmp/sockets/puma.sock
[13383] ! WARNING: Detected 4 Thread(s) started in app boot:
[13383] ! #<Thread:0x00005598f921d918@/srv/www/forum/public_html/vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/atomic/ruby_thread_local_var.rb:38 sleep_forever> - /srv/www/forum/public_html/vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/atomic/ruby_thread_local_var.rb:40:in `pop'
[13383] ! #<Thread:0x00005598fd72a4c0@/srv/www/forum/public_html/vendor/bundle/ruby/2.6.0/gems/activerecord-6.0.3.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:334 sleep> - /srv/www/forum/public_html/vendor/bundle/ruby/2.6.0/gems/activerecord-6.0.3.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:337:in `sleep'
[13383] ! #<Thread:0x00005598fe4eb2f8@/srv/www/forum/public_html/vendor/bundle/ruby/2.6.0/gems/message_bus-3.3.1/lib/message_bus.rb:700 sleep> - /srv/www/forum/public_html/vendor/bundle/ruby/2.6.0/gems/redis-4.2.1/lib/redis/connection/ruby.rb:55:in `select'
[13383] ! #<Thread:0x00005598fe4eb0c8@/srv/www/forum/public_html/vendor/bundle/ruby/2.6.0/gems/message_bus-3.3.1/lib/message_bus/timer_thread.rb:38 sleep> - /srv/www/forum/public_html/vendor/bundle/ruby/2.6.0/gems/message_bus-3.3.1/lib/message_bus/timer_thread.rb:123:in `sleep'
[13383] * Daemonizing...

最后出现一个* Daemonizing…说明运行成功。此时,Discourse运行于/var/www/discourse/tmp/sockets/puma.sock.

 

10, 使用Nginx反代Discourse

上一节我们提到,Discourse部署需要后端运行服务器与前端反代服务器。这一节我们将介绍使用Nginx来反代运行了Discourse的Puma后端服务器。

首先,安装Nginx.  生产环境建议编译安装Nginx.  如果是测试环境,您可以直接用源安装Nginx.

1
apt-get install nginx

将程序提供的nginx配置文件复制到Nginx配置文件目录中,并编辑。

1
2
cp config/nginx.sample.conf /etc/nginx/conf.d/discourse.conf
vi /etc/nginx/conf.d/discourse.conf

找到下面这一段,注释掉:

1
2
3
4
upstream discourse {
        server unix:/srv/www/forum/public_html/tmp/sockets/nginx.http.sock;
        server unix:/srv/www/forum/public_html/tmp/sockets/nginx.https.sock;
}

找到下面这一段,取消注释:

1
2
3
#upstream discourse {
#        server unix:/srv/www/forum/public_html/tmp/sockets/puma.sock;
#}

找到server_name行,在后面填写您的论坛域名:

1
server_name bbs.qing.su;

找到下面这一行,注释掉:

brotli_static on;

然后保存退出。新建Nginx缓存文件夹,然后重新载入Nginx配置文件:

1
2
mkdir -p /var/nginx/cache/
service nginx reload

此时,访问您的域名,比如http://bbs.qing.su, 应该可以看到Discourse页面了,如下图。

接着给Nginx配置SSL.  这里将使用Let’s Encrypt免费证书。其他的证书安装类似。

1
2
apt-get install certbot python3-certbot-nginx
certbot --nginx --agree-tos --redirect --hsts --staple-ocsp -d bbs.qing.su

请将bbs.qing.su换成您自己的域名。再编辑文件/etc/nginx/conf.d/discourse.conf,在SSL配置部分添加下面这一行:

1
add_header Content-Security-Policy upgrade-insecure-requests;

如下图所示:

保存退出后,重新载入Nginx配置文件。

1
service nginx reload

再次访问您的论坛域名,比如https://bbs.qing.su, 就可以看到SSL配置成功了。

 

11, 创建管理员账号并配置论坛参数

Discourse安装好之后,需要创建管理员账户。如果您一直跟着我的教程操作,那么您当前的目录位置为Discourse程序目录(/var/www/discourse/)。使用下面的命令可以新建管理员账户:

1
RAILS_ENV=production /snap/bin/bundle exec rake admin:create

按照屏幕提示输入邮箱和密码,就会生成管理员账户。如下图。

然后,重启Puma服务器。

1
RAILS_ENV=production bundle exec pumactl -P /var/www/discourse/tmp/pids/puma.pid restart

此时,访问您的论坛页面,您可以看到类似于下面的窗口,可以用管理员账号登录了。

如果您打开网站后发现是502错误,说明Puma重启失败,可以执行下面的命令启动Discourse:

1
RAILS_ENV=production bundle exec puma -C /var/www/discourse/config/puma.rb

登录之后,点击页面上面的Setup Wizard, 开始设置Discourse参数,比如站点名,站点标题,板块,Logo, 等等。

如果您使用CloudFlare CDN反代您的网站,您需要配置CDN域名,请在后台找到settings -> security -> content security policy src, 然后添加https://bbs.qing.su/cdn-cgi/.  将bbs.qing.su换为您的域名。

 

12, 使用Sidekiq运行后台服务

Sidekiq是一个开源的计划任务执行程序。通过配置Sidekiq, 我们能够实现发送注册邮件等后台任务。这里,我们可以把Sidekiq简单地理解为系统里的cron job.

编辑文件/var/www/discourse/config/sidekiq.yml,在文件末尾添加下面这几行:

1
2
3
4
5
6
7
production:
:concurrency: 2
:queues:
- [critical, 4]
- [default, 2]
- [low]
- [ultra_low]

如果您的访客量较大,可以提高对应的数值。

保存退出,然后新建sidekiq后台服务。新建文件/etc/systemd/system/discourse-sidekiq.service, 内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[Unit]
Description=Discourse sidekiq background processing service
After=multi-user.target

[Service]
Type=simple
User=root
PIDFile=/var/www/discourse/tmp/pids/sidekiq.pid
WorkingDirectory=/var/www/discourse
Environment=RAILS_ENV=production
ExecStart=/snap/bin/bundle exec sidekiq -C config/sidekiq.yml
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

然后运行sidekiq服务:

1
service discourse-sidekiq start

 

13, 为Discourse建立系统服务

如果您一直跟着我的教程操作,那么您当前的目录位置为Discourse程序目录(/var/www/discourse/)。先暂停Puma服务器:

1
RAILS_ENV=production /snap/bin/bundle exec pumactl -P /var/www/discourse/tmp/pids/puma.pid stop

编辑文件/var/www/discourse/config/puma.rb, 然后分别找到下面这两行,注释掉。

1
pidfile "#{APP_ROOT}/tmp/pids/puma.pid"
1
daemonize true

然后新建puma-discourse后台服务。新建文件/etc/systemd/system/discourse.service, 内容为如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[Unit]
Description=Discourse service

[Service]
Type=simple
User=root
PIDFile=/var/www/discourse/tmp/pids/puma.pid
WorkingDirectory=/var/www/discourse
Environment=RAILS_ENV=production
ExecStart=/snap/bin/bundle exec puma -C config/puma.rb
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

然后,运行服务:

1
service discourse start

此时访问您的论坛,应当正常运行了。

 

14, 其他设置

论坛注册或者通知需要使用邮件系统。可以编辑/var/www/discourse/config/discourse.conf文件配置SMTP发信。

找到下面几行:

1
2
3
4
5
6
7
8
smtp_address =
smtp_port = 587
smtp_domain =
smtp_user_name =
smtp_password =
smtp_authentication = plain
smtp_enable_start_tls = true
notification_email =

填上您的邮件服务器信息即可。

我们还可以修改Discourse运行参数,减少其内存占用。编辑文件/var/www/discourse/config/puma.rb, 更改workers和threads值。下面的值对于一个单核, 1 GB内存的VPS较为合适。

1
2
workers 2
threads 4, 16

修改Discourse的任何配置文件后,需要重启服务。

1
service discourse restart

 

到这里,我们成功在Ubuntu 18.04 LTS 64 bit操作系统上安装并配置好了Discourse论坛程序。通过本教程,您还可以学习到Ruby on Rails程序通常的安装部署方法,Puma服务器的使用,Nginx反代与配置SSL, Systemd的写法等各种知识。如果您想在生产环境中使用,建议您使用Docker安装。

本文许多内容翻译自Linuxbabe, 有删改。如果您在安装过程中遇到各种问题,欢迎留言与我讨论。本文作者为香菇肥牛,原文链接为https://qing.su/article/install-discourse-without-docker.html,转载需注明原文链接。谢谢!

Leave a Comment