SDB:Discourse without Docker

跳转至: 导航, 搜索
本教学将向您演示如何在 openSUSE 服务器上面直接架设 discourse 论坛系统。

Docker or without Docker?

Docker 只是一种选择,discourse 官方选择了 docker image 作为他们的分发方式。但毕竟 discourse 只是一个 rails 程序,我们完全可以在 openSUSE 上面架设它,这样会避免很多问题(docker 也会死,那时候 debug 起来会多了一层 docker 的东西,可能是 discourse 的问题,也可能是 docker 的问题),也会减少一些内存占用,毕竟 discourse 作为一个论坛程序是要架设在 VPS 上的,少一些内存占用就少一些成本。

安装并配置 PostgreSQL 数据库

   sudo zypper in postgresql-server

查询一下你安装的 postgresql 版本:

   sudo zypper se postgresql

我这里是 postgresql96。接下来安装 hstore 和 pg_trgm 插件:

   sudo zypper in postgresql96-contrib

启动服务:

   sudo systemctl enable postgresql
   sudo systemctl start postgresql

进入:

   su - postgres -c psql

输入以下命令创建 discourse 数据库和 discourse 用户名,并挂载 discourse 所需的两个数据库扩展(注意最后面的分号一定不能丢):

   CREATE DATABASE discourse;
   CREATE USER discourse;
   ALTER USER discourse WITH ENCRYPTED PASSWORD 'password';
   ALTER DATABASE discourse OWNER TO discourse;
   \connect discourse #连接到 discourse 数据库
   CREATE EXTENSION hstore;
   CREATE EXTENSION pg_trgm;
   \q #退出 postgresql 的命令行

接着编辑 /var/lib/pgsql/data/pg_hba.conf,在最下方加上一行

   host    discourse       discourse      ::1/128                  md5
   host    discourse       discourse      127.0.0.1/32                  md5

重启 postgresql 服务

   sudo systemctl restart postgresql

安装并配置 Redis

安装 redis:

   sudo zypper in redis

创建配置:

   cd /etc/redis
   sudo cp -r default.conf.example discourse.conf
   sudo chown redis:redis discourse.conf

编辑配置,打开 discourse.conf 编辑里面的:

   pidfile /var/run/redis/discourse.pid
   logfile /var/log/redis/discourse.log
   always-show-logo no
   stop-writes-on-bgsave-error no
   dir /var/lib/redis/discourse

创建 redis 的 dir:

   install -d -o redis -g redis -m 0750 /var/lib/redis/discourse

touch 一下 logfile 并设置权限:

   touch /var/log/redis/discourse.log
   sudo chown redis:redis /var/log/redis/discourse.log

另外 openSUSE 的 /usr/lib/systemd/system/redis@.service 有问题,对照下面的改一下:

[Unit]
Description=Redis
After=network.target
PartOf=redis.target

[Service]
Type=notify
User=redis
Group=redis
PIDFile=/var/run/redis/%i.pid
PrivateTmp=true
PermissionsStartOnly=true
Environment=REDIS_STATE_DIR_%i=/var/lib/redis/%i

ExecStartPre=-/usr/bin/mkdir -p ${REDIS_STATE_DIR_%i}
ExecStartPre=/usr/bin/chown -R redis:redis ${REDIS_STATE_DIR_%i}
ExecStart=/usr/sbin/redis-server /etc/redis/%i.conf
ExecStop=/usr/bin/redis-cli shutdown
ExecReload=/usr/bin/pkill -HUP ${MAINPID}
LimitNOFILE=10240
Restart=on-failure

[Install]
WantedBy=multi-user.target redis.target

启动服务:

   sudo systemctl daemon-reload
   sudo systemctl enable redis@discourse.service
   sudo systemctl start redis@discourse.service

优化 redis

redis 有以下几个需要优化的地方:

1. stop-writes-on-bgsave-error

这是造成 “MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk” 错误的源头,这个设置用意上是好的,后台保存不上的时候就不写入,这会很快吃光你的内存,让你不得不查。

后台保存不上绝大多数是暂时的,缓过来的时候自动覆盖硬盘上 redis 数据库里的内容就好了。这个选项的过激之处在于,有一点问题就会让你的 redis 完全用不了。建议改为 no。

2. somaxconn = 511 和 vm.overcommit_memory = 1

这两个 redis 包的维护者已经帮我们优化好了,但是要重启生效

立即生效:

   sudo sysctl net.core.somaxconn=512
   sudo sysctl vm.overcommit_memory=1

3. 关闭 Transparent Huge Pages (THP)

这个可以在 yast - bootloader - kernel parameters,在 showopts 后面加上 transparent_hugepage=never 来解决。

但同样是要重启生效。

立即生效:

   sudo echo never > /sys/kernel/mm/transparent_hugepage/enabled

安装 discourse

添加软件源:

   sudo zypper ar -f http://download.opensuse.org/repositories/home:/darix:/apps/openSUSE_Tumbleweed/ discourse

修改优先级

   sudo zypper mr -p 60 discourse

刷新:

   sudo zypper ref

安装 discourse:

   sudo zypper in discourse

配置 discourse

   cd /srv/www/vhosts/discourse/config
   cp -r discourse_defaults.conf discourse.conf
   sudo chown discourse:discourse discourse.conf

编辑 discourse.conf:

   db_host = localhost
   db_name = discourse
   db_username = discourse
   db_password = 之前你设置的 postgresql 密码
   host_name = 'discourse.suse.org.cn'
   smtp_address = smtp.gmail.com
   smtp_port = 587
   smtp_domain = gmail.com
   smtp_user_name = 你的
   smtp_password = 你的
   developer_emails = 你的

这里你可以用 QQ 邮箱,但是 QQ 邮箱使用 smtp 需要申请一个随机密码。gmail 在国内 VPS 上面无法访问。所以建议注册一个 mailgun 服务,每月免费一万封邮件。

初始化 discourse

   cd /srv/www/vhosts/discourse
   RAILS_ENV=production /usr/bin/bundler.ruby2.4 exec /usr/bin/rake.ruby2.4 db:migrate
   RAILS_ENV=production /usr/bin/bundler.ruby2.4 exec /usr/bin/rake.ruby2.4 assets:precompile

在 db:migrate 的过程中,可能提示你比如 thor 0.19 找不到之类的错误,你可以用:

   sudo zypper se -v ruby2.4-rubygem-thor

来查找 thor 的可用版本,一般来说是由于 tumbleweed 源里的 thor 比 discourse 源里的新,所以装上了比如 0.20 版本,可以降级:

   sudo zypper in --oldpackage ruby2.4-rubygem-thor-0.19.4-1.6.x86_64

在上面两步做完之后,你需要修正一下权限(因为你可能是使用 root 登录的 VPS):

   sudo chown -R discourse:discourse /srv/www/vhosts/discourse/public 
   sudo chown -R discourse:discourse /srv/www/vhosts/discourse/tmp

启动 discourse

我们先要修正一下 discourse 的 systemd 服务,一共有三个:

   /usr/lib/systemd/system/discourse-update.service
   /usr/lib/systemd/system/discourse-sidekiq.service
   /usr/lib/systemd/system/discourse-puma.service

把所有的 Environment 变量改成:

   Environment="RUBY_GC_MALLOC_LIMIT=4000100"
   Environment="RUBY_GC_MALLOC_LIMIT_MAX=16000100"
   Environment="RUBY_GC_MALLOC_GROWTH_FACTOR=1.1"
   Environment="RAILS_ENV=production"
   Environment="LANG=en_US.UTF-8"
   Environment="LC_ALL=en_US.UTF-8"
   #Environment="RUBY_GC_MALLOC_LIMIT=90000000" "LANG=en_US.UTF-8" "LC_ALL=en_US.UTF-8"

接下来编辑 /usr/sbin/discourse-update, 把里面的 tombstone 删掉。

然后把 discourse-sidekiq.service 里面的 Type=simple 改成 Type=forking,再在 ExecStart 里面把 /usr/bin/sidekiq.ruby2.5 后面加 “-d” 以 daemonize 模式运行 sidekiq。

下面使用

   sudo systemctl enable discourse-sidekiq.service
   sudo systemctl start discourse-sidekiq.service

启动 sidekiq 服务。

然后修改 discourse-puma.service 把 Type=simple 改成 Type=forking。

然后:

   sudo systemctl enable discourse-puma.service
   sudo systemctl start discourse-puma.service

启动 puma 服务。

Nginx 相关设置

   sudo zypper in nginx

打开 /etc/nginx/nginx.conf 把里面的 server 部分注释掉。然后在 keepalive_timeout 65; 后面加上一行:

   server_names_hash_bucket_size 64;

保存。

建立 vhosts.d 文件夹

   sudo mkdir -p /etc/nginx/vhosts.d
   cd /etc/nginx/vhosts.d

把 /srv/www/vhosts/discourse/config/nginx.sample.conf 复制过来:

   cp -r /srv/www/vhosts/discourse/config/nginx.sample.conf /etc/nginx/vhosts.d/discourse.conf

编辑 discourse.conf,修改以下部分:

注释掉 upstream discourse thin 的部分,把 puma 的部分打开,因为我们用的是 puma。

server_name 改成你的,比如 discourse.suse.org.cn。

把 set $public 的部分改成正确的 /srv/www/vhosts/discourse/public。

保存。

启动 nginx:

   systemctl enable nginx.service
   systemctl start nginx.service

接着去你的 DNS parking 设置 discourse.suse.org.cn 指向这个 VPS 的外网 IP。

大功告成了!

安装插件

安装 git:

   sudo zypper in git

安装插件:

   systemctl stop discourse-puma
   systemctl stop discourse-sidekiq
   RAILS_ENV=production /usr/bin/bundler.ruby2.4 exec /usr/bin/rake.ruby2.4 plugin:install repo=https://github.com/openSUSE-zh/discourse-username-localization
   RAILS_ENV=production /usr/bin/bundler.ruby2.4 exec /usr/bin/rake.ruby2.4 db:migrate
   RAILS_ENV=production /usr/bin/bundler.ruby2.4 exec /usr/bin/rake.ruby2.4 assets:precompile
   systemctl stop discourse-sidekiq
   systemctl stop discourse-puma

升级插件

   systemctl stop discourse-puma
   systemctl stop discourse-sidekiq
   RAILS_ENV=production /usr/bin/bunlder.ruby2.4 exec /usr/bin/rake.ruby2.4 plugin:update plugin=[The name in /srv/www/vhosts/discourse/plugins]
   RAILS_ENV=production /usr/bin/bunlder.ruby2.4 exec /usr/bin/rake.ruby2.4 db:migrate
   RAILS_ENV=production /usr/bin/bunlder.ruby2.4 exec /usr/bin/rake.ruby2.4 assets:precompile
   systemctl start discourse-sidekiq
   systemctl start discourse-puma

升级 discourse

   systemctl stop discourse-puma
   systemctl stop discourse-sidekiq
   zypper up discourse
   RAILS_ENV=production /usr/bin/bundler.ruby2.4 exec /usr/bin/rake.ruby2.4 plugin:update_all
   RAILS_ENV=production /usr/bin/bundler.ruby2.4 exec /usr/bin/rake.ruby2.4 db:migrate
   RAILS_ENV=production /usr/bin/bundler.ruby2.4 exec /usr/bin/rake.ruby2.4 assets:precompile
   chown -R discourse:discourse public
   chown -R discourse:discourse tmp
   // 然后先去修正 discourse 的 systemd 服务
   systemctl start discourse-sidekiq
   systemctl start discourse-puma

其他问题

discourse 维护常看的 log

   /var/log/redis/discourse.log
   /srv/www/vhosts/discourse/log/production.log
   /srv/www/vhosts/discourse/log/sidekiq.log

提示找不到 optipng/jhead/jpegoptim/gifsicle/svgo/uglifyjs

optipng, jhead 和 gifsicle 都在官方源里面。

jpegoptim 在 OBS 上能找到 home 源。

svgo:

   cd /root
   npm install svgo
   ln -sf /root/node_modules/svgo/bin/svgo /usr/bin/svgo

uglifyjs:

   cd /root
   npm install uglify-js
   ln -sf /root/node_modules/uglify-js/bin/uglifyjs /usr/bin/uglifyjs 

提示找不到 GeoLite2-ASN.mmdb

https://dev.maxmind.com/geoip/geoip2/geolite2/ 下载,解压了放到 discourse 的 vendor/data 下面