将BBS网站Discourse从海外主机完美迁移到国内云服务器, 国内主机同时运行WordPress和Discourse服务

我前两天把 Discourse这个论坛服务部署到了一个轻量云服务器上, 详情 给热心老哥搭个窝,2021年30分钟用Discourse搭建新一代BBS论坛站全攻略

海外的云服务在国内访问很慢, 于是我开始了将Discourse往国内云迁移的探索.

遇到的问题

  • Discourse依赖包极多, 官方推荐Docker部署, 但启动Docker的容器默认绑定了80 和 443 端口
  • Discourse 强依赖Github, 无论是安装还是构建都需要Github, 而国内云访问Github极其不稳定, 经常失败
  • Discourse官方没有给出数据迁移的详细教程, 2021年的Discourse中文网完全打不开, 要完成完美的迁移过程, 全靠自己猜

解决Docker部署默认绑定80 和 443 端口的问题

containers/app.yml 中添加以下几行参数可以解决端口映射的问题

expose:
  - "20080:80"   # http
  - "20443:443" # https

解决Discourse安装和构建期间, 访问Github失败的问题

首先按照 为国内WordPress主机配置代理,解决从插件商店下载插件失败,无法验证Google官方插件Site Kit的问题 中提供的步骤, 在国内云服务器端开启魔法上网服务

containers/app.yml 中添加以下几行参数可以解决Discourse安装和构建期间, 访问Github失败的问题

image.png
env:
    http_proxy: http://127.0.0.1:7890
    https_proxy: http://127.0.0.1:7890

另外docker 拉取基础镜像也需要走海外代理, 需要在 ~/.docker/config.json 中添加走代理服务的设置

.docker/config.json
{
 "proxies":
 {
   "default":
   {
     "httpProxy": "http://172.17.0.1:7890",
     "httpsProxy": "http://172.17.0.1:7890",
     "noProxy": "localhost,127.0.0.1"
   }
 }
}

另外, 在国内执行 ./launcher rebuild app 前, 最好在当前终端先执行以下语句

export https_proxy=http://127.0.0.1:7890 http_proxy=http://127.0.0.1:7890

(以上均为国内云服务器, 无法魔法上网, 导致我被坑的血泪史...)

解决Discourse从海外迁移到国内的问题

首先进入已经可以提供服务的服务器, 进入默认项目目录

/var/discourse

运行 ./launcher enter app 进入容器

成功进入容器

运行discourse 可以看的命令提示

查看命令提示

输入 discourse backup, 回车获取备份包

获取备份包

备份包的位置为

/var/www/discourse/public/backups/default/discourse-2021-06-21-100849-v20210617202227.tar.gz

通过scp 将 /var/www/discourse/public/backups/default/discourse-2021-06-21-100849-v20210617202227.tar.gz 传送到国内新云服务器的/opt/ 目录

scp /var/www/discourse/public/backups/default/discourse-2021-06-21-100849-v20210617202227.tar.gz root@国内云服务器IP:/opt/

(scp这个命令真的超实用, 在容器内部也能用!建议仔细记一下scp的使用方法)

传输成功

按 Control+D 退出容器, 回到海外宿主机


退出容器

将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
  - "20443:443" # https
  - "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

## 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"

将海外主机内的app.yml也传送到国内新云服务器的/opt/ 目录

scp /var/discourse/containers/app.yml  root@120.76.136.220:/opt/
发送成功

至此!在海外主机的操作完成!

登陆国内云服务器

ssh 用户名@国内云服务器ip

国内云服务器设置好魔法上网, 仔细阅读本文前方解决Discourse安装和构建期间, 访问Github失败的问题相关内容。

如果国内云主机没有安装最新版docker, 请通过以下命令安装(以CentOS7为例)

yum install -y yum-utils
yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo

yum install docker-ce docker-ce-cli containerd.io -y
# 启动docker
systemctl start docker

为了便于区分,我把国内云服务器的discourse目录放到 /usr/share/nginx/bbs.v2fy.com 目录下

cd  /usr/share/nginx/bbs.v2fy.com
git clone https://github.com/discourse/discourse_docker.git  /usr/share/nginx/bbs.v2fy.com
下载成功

将/opt/app.yml放入 /usr/share/nginx/bbs.v2fy.com/containers

cp /opt/app.yml    /usr/share/nginx/bbs.v2fy.com/containers/

运行discourse服务

cd /usr/share/nginx/bbs.v2fy.com/
./launcher rebuild app

查看新容器的id

docker ps
查看容器id

将备份包拷贝到新容器中

docker cp /opt/discourse-2021-06-21-100849-v20210617202227.tar.gz   983dca831620:/var/www/discourse/public/backups/default/discourse-2021-06-21-100849-v20210617202227.tar.gz

进入新容器,恢复数据

cd /usr/share/nginx/bbs.v2fy.com/
./launcher enter app
discourse restore discourse-2021-06-21-100849-v20210617202227.tar.gz
恢复数据成功

退出容器, rebuild容器

按 Control+D 退出容器

cd /usr/share/nginx/bbs.v2fy.com/
./launcher rebuild app

现在, 我们已经将discourse的80端口映射到 20080端口, 443端口映射到20443端口

我们需要对国内云服务器的Nginx进行配置, 将请求域名bbs.v2fy.com 80端口的服务, 指向20080端口,请求域名bbs.v2fy.com 的443端口的服务, 指向20443端口

有趣的是,

安装模块

yum update -y
yum install nginx-mod-stream -y

以CentOS7 为例,安装 nginx-mod-stream 完成后, 可以在

/usr/lib64/nginx/modules/ngx_stream_module.so

找到

最终的 /etc/nginx/nginx.conf 配置为

#user  nginx;
worker_processes  1;
load_module /usr/lib64/nginx/modules/ngx_stream_module.so;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;



stream {

    map $ssl_preread_server_name $backend_name {
        bbs.v2fy.com  bbs;
    v2fy.com web;
    fangyuanxiaozhan web;
        default web;
    }

    upstream bbs {
        server 127.0.0.1:20443;
    }

    upstream web {
    server 127.0.0.1:30443;
   }





    server {
        listen       443 reuseport;
        listen  [::]:443 reuseport;
        proxy_pass   $backend_name;
        ssl_preread  on;
    }
}


events {
    worker_connections  1024;
}



http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;
    charset utf-8,gbk;
    client_max_body_size 20m;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    gzip  on;

    server {
      listen 80;
      server_name bbs.v2fy.com;
      location / {
        proxy_pass http://127.0.0.1:20080;
        proxy_set_header Host $proxy_host; # 修改转发请求头,让8080端口的应用可以受到真实的请求
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      }
}

    include /etc/nginx/conf.d/*.conf;
}

这个配置文件很奇妙, 有一些冗余信息, 比如其中的

    upstream web {
    server 127.0.0.1:30443;
   }

是留给WordPress关联的php服务用的, 处理v2fy.com和fangyuanxiaozhan.com这两个WordPress站,原理是在30443端口开启了监听, 用于处理v2fy.com和fangyuanxiaozhan.com的请求, 这里放一个v2fy.com的配置 /etc/nginx/conf.d/v2fy.com.conf

server {
  listen 30080;
  server_name v2fy.com  www.v2fy.com;
  charset  utf-8;
  root /usr/share/nginx/v2fy.com;
  index index.php index.html index.htm;
  rewrite ^(.*)$ https://$host$1 permanent;

  location / {
    try_files $uri $uri/ /index.php$query_string =404;
  }

  error_page 404 /404.html;
  error_page 500 502 503 504 /50x.html;
  location = /50x.htm {
    root /usr/share/nginx/v2fy.com;
  }



  location ~ \.php$ {
    try_files $uri =404;
    fastcgi_pass unix:/var/run/php73-fpm/php73-fpm.sock;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
  }



}


server {
  listen 30443 ssl;   #SSL协议访问端口号为443。此处如未添加ssl,可能会造成Nginx无法启动。
  server_name v2fy.com  www.v2fy.com;  #将localhost修改为您证书绑定的域名,例如:www.example.com。
  charset  utf-8;
  root /usr/share/nginx/v2fy.com;
  index index.php index.html index.htm;
  ssl_certificate /etc/nginx/cert/v2fy.com.pem;   #将domain name.pem替换成您证书的文件名。
  ssl_certificate_key /etc/nginx/cert/v2fy.com.key;   #将domain name.key替换成您证书的密钥文件名。
  ssl_session_timeout 5m;
  ssl_ciphers  *****;  #使用此加密套件。
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;   #使用该协议进行配置。
  ssl_prefer_server_ciphers on;

    gzip on;
    gzip_min_length 1k;
    gzip_buffers 4 16k;
    #gzip_http_version 1.0;
    gzip_comp_level 8;
    gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
    gzip_vary off;
    gzip_disable "MSIE [1-6]\.";

  location = /favicon.ico {
                log_not_found off;
                access_log off;
        }

        location = /robots.txt {
                allow all;
                log_not_found off;
                access_log off;
        }

        location / {
                # This is cool because no php is touched for static content.
                # include the "?$args" part so non-default permalinks doesn't break when using query string
                try_files $uri $uri/ /index.php?$args;
        }


  location ~ \.php$ {
    try_files $uri =404;
    fastcgi_pass unix:/var/run/php73-fpm/php73-fpm.sock;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
  }

 location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
                expires max;
                log_not_found off;
        }



    location ~* .(json)$ {
          add_header  Content-Type 'application/json;charset=utf-8';
    }
}

最终进入域名服务商后台, 将bbs.v2fy.com的解析换到国内云服务器ip, 齐活!

完美迁移完成

小结

这篇文章前后耗费我一周时间, 查了大量的资料, 国内的网络条件也真是不友好, 没有魔法上网工具, 请勿尝试本文的操作, 你会秃头的... 如果你的云服务器内存不足2GB, 请做好主机被卡死的心理准备(我4GB主机, 都被卡掉重启一次)

希望这篇文章能帮到, 同样对Discourse感兴趣的你~

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

https://www.v2fy.com/p/2021-06-21-discourse-1624274883000

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容