“论坛”作为上一代互联网产品,已经淡出了很多人的互联网生活了。不过,我仍然很喜欢“论坛”这一讨论模式。很多像我一样的互联网遗民,依旧喜欢在各论坛中水贴。今天我们就来介绍一下国外非常著名的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,转载需注明原文链接。谢谢!