《树莓派4B家庭服务器搭建指南》第十二期:降低BBS运营成本,将面向未来的BBS论坛程序Discourse部署到树莓派(私人BBS论坛一年运营成本300块!)


title: 《树莓派4B家庭服务器搭建指南》第十二期:降低BBS运营成本,将面向未来的BBS论坛程序Discourse部署到树莓派(私人BBS论坛一年运营成本300块!)

Discourse是一款面向未来的BBS论坛程序,官方提供收费的托管服务,程序本身开源,可免费部署到自己的服务器。

Discourse 完美支持PC和移动版,且支持第三方插件,为定制论坛提供了极大的便利。

Discourse提供了完整的BBS论坛维护方案,支持定时数据备份,用户上传图片自动生成预览图。

前段时间我出了两篇关于部署Discourse论坛的教程:

给热心老哥搭个窝,2021年30分钟用Discourse搭建新一代BBS论坛站全攻略 https://v2fy.com/p/2021-06-12-discourse-2021-1623477573000/

给热心老哥挪个窝,将BBS网站Discourse从海外主机完美迁移到国内云服务器, 实现国内主机同时运行WordPress和Discourse https://v2fy.com/p/2021-06-21-discourse-1624274883000/

以上教程为想要建立个人论坛的人提供了帮助。

但是,Discourse这种附带Redis内存数据库的论坛程序,虽然体验极佳,但对服务器内存的压力很大,虽然2GB就能运行,但内存肯定是越大越流畅,但云服务的内存都太贵了,作为一个树莓派爱好者,我一直尝试重新编译Discourse的 Docker到树莓派的ArmV8处理器处理器,但总是各种不完美。

然鹅,Discourse官方于2021年12月7日支持了以Docker形式部署到树莓派 https://blog.discourse.org/2021/12/2021-12-07-discourse-on-a-raspberry-pi/ ,真是喜大普奔,为了让Discourse论坛程序更流畅,也为了缓解云服务器的压力,我决定把Discourse论坛程序迁移到树莓派~

如果你已经在线上有Discourse网站,可以先按照 给热心老哥挪个窝,将BBS网站Discourse从海外主机完美迁移到国内云服务器, 实现国内主机同时运行WordPress和Discourse https://v2fy.com/p/2021-06-21-discourse-1624274883000/ 提供的方法,为Discourse 所有数据打个包,方便最后迁移到树莓派的Discourse服务,如果你是从零开始在树莓派搭建Discourse 站,那你可以跳过备份数据,恢复数据的步骤。

在树莓派运行Discourse的思路

我在云服务器搭建过Discouse服务,所以用我的配置举个例子,下面提到的端口,理论上都可以被任意替换。

Discourse 在云服务端运行占用了20080端口(用于Http服务)和587端口(用于邮件服务),我们在树莓派依然为Discourse 预留出20080端口和587端口,但20080端口要通过树莓派Nginx 的80端口进行请求转发。

云服务器端将Discourse论坛数据全部导出后,关停Discourse服务,空出587端口和20080端口。

我们需要在树莓派的frpc.ini中配置两个端口穿透,一个是将树莓派的587端口直接穿透到云服务器端的587端口,另一个是将树莓派运行Nginx的80端口穿透到云服务端的 8666端口。

我们需要设置云服务器端的Nginx关于bbs.v2fy.com域名的配置文件,将原本转发到20080端口的服务,修改为转发到8666端口,效果是将用户对云服务器的请求,转发给树莓派在80端口运行的Nginx服务,Nginx识别bbs.v2fy.com,然后将对应请求转发给树莓派20080端口运行的Discourse服务.

最后,依次重启树莓派的frpc服务,树莓派的Nginx服务,云服务器端的Nginx服务,配置完成。

配置完成的效果,可通过 https://bbs.v2fy.com 查看。


一些具体的配置文件

  • 树莓派Nginx配置

我们将树莓派运行 Discoure 在Nginx 的配置文件放置在 /etc/nginx/conf.d/bbs.v2fy.com.conf

upstream bbs_v2fy_com { server 127.0.0.1:20080; }

server {
    server_name      bbs.v2fy.com;
    listen           80;

    location / {
        proxy_pass http://bbs_v2fy_com;
        proxy_set_header Host $host:80;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    error_page 404 /404.html;
        location = /40x.html {
    }

    error_page 500 502 503 504 /50x.html;
        location = /50x.html {
    }


}

这个/etc/nginx/conf.d/bbs.v2fy.com.conf配置文件的作用是,将bbs.v2fy.com的请求全部指向20080端口运行的Discourse服务。

  • 服务器端Nginx配置

服务端配置Nginx相关文件的位置为/etc/nginx/conf.d/bbs.v2fy.com.conf

upstream bbs_v2fy_com { server 127.0.0.1:8666; }

server {
    server_name      bbs.v2fy.com;
    listen           80;


    rewrite ^(.*)$ https://$host$1 permanent;

    #location / {
    #    proxy_pass http://bbs_v2fy_com;
    #    proxy_set_header Host $host:80;
    #    proxy_set_header X-Real-IP $remote_addr;
    #    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    #}
}


server {
    listen       443 ssl http2;
    listen       [::]:443 ssl http2;
    server_name  bbs.v2fy.com;

    ssl_certificate "/etc/nginx/ssl/bbs.v2fy.com/fullchain.cer";
    ssl_certificate_key "/etc/nginx/ssl/bbs.v2fy.com/bbs.v2fy.com.key";
    ssl_session_cache shared:SSL:1m;
    ssl_session_timeout  10m;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

    location / {
        proxy_pass http://bbs_v2fy_com;
        proxy_set_header Host $host:443;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    error_page 404 /404.html;
        location = /40x.html {
    }

    error_page 500 502 503 504 /50x.html;
        location = /50x.html {
    }
}

这个/etc/nginx/conf.d/bbs.v2fy.com.conf配置文件的作用是将与bbs.v2fy.com有关的http服务全部转发到 8666端口,而8666端口恰好可以通过frp转发到树莓派运行Nginx的80端口。

服务端的Nginx还通过acme.sh为bbs.v2fy.com域名添加了https证书,并实现了自动续期,详情参考 零依赖!使用acme.sh设置nginx多个https证书自动更新,无限续期https证书 https://www.v2fy.com/p/2021-06-27-nginx-https-1624774964000/

树莓派端frp内网穿透配置

配置文件的位置为 /opt/frp_0.37.0_linux_arm64/frpc.ini

[common]
server_addr = 自己的服务器ip
server_port = 7000
token = '自己的token'
log_file = './frpc.log'

[nginx-v2fy-com-8666]
type = tcp
local_ip = 127.0.0.1
local_port = 80
remote_port = 8666

[bbs-v2fy-com-smtp-587]
type = tcp
local_ip = 127.0.0.1
local_port = 587
remote_port = 587

这个frpc.ini配置文件作用是: 完成了树莓派Nginx 80 端口 与云服务器端8666端口的穿透;完成了树莓派端587端口与云服务器端 587端口的穿透。

树莓派获取Discourse程序

  • 通过ssh登录树莓派,获取discourse 主程序
sudo -s
git clone https://github.com/discourse/discourse_docker.git /opt/bbs.v2fy.com
cd /opt/bbs.v2fy.com

Discourse配置文件迁移

将原Discourse 目录下的 containers/app.yml 放置到树莓派 /opt/bbs.v2fy.com/containers/app.yml

app.yml示例内容为:

## this is the all-in-one, standalone Discourse Docker container template
##
## After making changes to this file, you MUST rebuild
## /var/discourse/launcher rebuild app
##
## BE *VERY* CAREFUL WHEN EDITING!
## YAML FILES ARE SUPER SUPER SENSITIVE TO MISTAKES IN WHITESPACE OR ALIGNMENT!
## visit http://www.yamllint.com/ to validate this file as needed



templates:
  - "templates/postgres.template.yml"
  - "templates/redis.template.yml"
  - "templates/web.template.yml"
  - "templates/web.ratelimited.template.yml"
## Uncomment these two lines if you wish to add Lets Encrypt (https)
  #- "templates/web.ssl.template.yml"
  #- "templates/web.letsencrypt.ssl.template.yml"

## which TCP/IP ports should this container expose?
## If you want Discourse to share a port with another webserver like Apache or nginx,
## see https://meta.discourse.org/t/17247 for details
expose:
  - "20080:80"   # http
  - "587:587" # SMTP TSL


params:
  db_default_text_search_config: "pg_catalog.english"

  ## Set db_shared_buffers to a max of 25% of the total memory.
  ## will be set automatically by bootstrap based on detected RAM, or you can override
  db_shared_buffers: "128MB"

  ## can improve sorting performance, but adds memory usage per-connection
  #db_work_mem: "40MB"

  ## Which Git revision should this container use? (default: tests-passed)
  #version: tests-passed

env:
  LC_ALL: en_US.UTF-8
  LANG: en_US.UTF-8
  LANGUAGE: en_US.UTF-8
  # DISCOURSE_DEFAULT_LOCALE: en

  ## How many concurrent web requests are supported? Depends on memory and CPU cores.
  ## will be set automatically by bootstrap based on detected CPUs, or you can override
  UNICORN_WORKERS: 2

  ## TODO: The domain name this Discourse instance will respond to
  ## Required. Discourse will not work with a bare IP number.
  DISCOURSE_HOSTNAME: bbs.v2fy.com

  ## Uncomment if you want the container to be started with the same
  ## hostname (-h option) as specified above (default "$hostname-$config")
  #DOCKER_USE_HOSTNAME: true

  ## TODO: List of comma delimited emails that will be made admin and developer
  ## on initial signup example 'user1@example.com,user2@example.com'
  DISCOURSE_DEVELOPER_EMAILS: 'zhaoolee@gmail.com'

  ## TODO: The SMTP mail server used to validate new accounts and send notifications
  # SMTP ADDRESS, username, and password are required
  # WARNING the char '#' in SMTP password can cause problems!
  DISCOURSE_SMTP_ADDRESS: smtp.exmail.qq.com
  DISCOURSE_SMTP_PORT: 587
  DISCOURSE_SMTP_USER_NAME: zhaoolee@v2fy.com
  DISCOURSE_SMTP_PASSWORD: "自己的邮箱密码"
  #DISCOURSE_SMTP_ENABLE_START_TLS: true           # (optional, default true)
  DISCOURSE_SMTP_DOMAIN: v2fy.com
  DISCOURSE_NOTIFICATION_EMAIL: zhaoolee@v2fy.com

  ## If you added the Lets Encrypt template, uncomment below to get a free SSL certificate
  LETSENCRYPT_ACCOUNT_EMAIL: zhaoolee@v2fy.com

  ## The http or https CDN address for this Discourse instance (configured to pull)
  ## see https://meta.discourse.org/t/14857 for details
  #DISCOURSE_CDN_URL: https://discourse-cdn.example.com

  ## The maxmind geolocation IP address key for IP address lookup
  ## see https://meta.discourse.org/t/-/137387/23 for details
  #DISCOURSE_MAXMIND_LICENSE_KEY: 1234567890123456
  DISCOURSE_SMTP_AUTHENTICATION: login

## The Docker container is stateless; all data is stored in /shared
volumes:
  - volume:
      host: /var/discourse/shared/standalone
      guest: /shared
  - volume:
      host: /var/discourse/shared/standalone/log/var-log
      guest: /var/log

## Plugins go here
## see https://meta.discourse.org/t/19157 for details
hooks:
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - git clone https://github.com/discourse/docker_manager.git
          - git clone https://github.com/discourse/discourse-voting.git
          - git clone https://github.com/discourse/discourse-sitemap.git
          - git clone https://github.com/discourse/discourse-custom-header-links.git
          - git clone https://github.com/discourse/discourse-adplugin.git

## Any custom commands to run after building
run:
  - exec: echo "Beginning of custom commands"
  ## If you want to set the 'From' email address for your first registration, uncomment and change:
  ## After getting the first signup email, re-comment the line. It only needs to run once.
  - exec: rails r "SiteSetting.notification_email='zhaoolee@v2fy.com'"
  - exec: echo "End of custom commands"

Discourse在树莓派端重新构建

cd /opt/bbs.v2fy.com
sudo ./launcher rebuild app

构建完成后,我们就可以通过bbs.v2fy.com 访问到我们运行在树莓派的Discourse程序了,
但BBS网站是初始化的状态,我们可以按照 给热心老哥挪个窝,将BBS网站Discourse从海外主机完美迁移到国内云服务器, 实现国内主机同时运行WordPress和Discourse https://www.v2fy.com/p/2021-06-21-discourse-1624274883000/ 提供的方法,使用scp命令将数据恢复到树莓派运行的Discourse服务,至此完成数据迁移。

  • 树莓派运行Discourse

树莓派运行Discourse

  • 树莓派运行的Discourse可以全功能公网访问,并支持Https证书自动续期

树莓派运行的Discourse可以公网访问

小结

近期,国内的留言管制越来越严了,连B乎评论区都因技术调整关闭了,后续开放时间遥遥无期,言论管制会成为一个常态,很多类似简书之类的社区直接进行关键词无差别封禁,在网上好好写一段文字,讨论一个话题变得越来越难。

人怕出名猪怕壮,反过来讲,也是通用的,只要自建的BBS访问量不太大,对于特定垂直话题的讨论,就会有天然的屏障。

一个BBS的建站成本有多高呢?使用本文提供的方案,一块树莓派,一台固定ip每月20块的主机,再买个一年几十块的域名,一年的维护成本也就300人民币左右。如果你要加Google Adsence (谷歌广告),甚至还能赚点小钱。

阅读树莓派玩法文章合集《树莓派不吃灰》,请前往 https://github.com/zhaoolee/pi

本文永久更新地址(欢迎来读留言,写评论):

https://www.v2fy.com/p/2021-12-23-discourse-pi-1640269071000