存在的问题
目前,paopao-ce 存在这样几个问题:
- 不存在管理面板,得自己根据 API 写管理工具;
- 部署时,本人尚未解决搜索业务不能使用的问题(搜索的接口正常但是返回的数据是空的)。
此文档还在完善
截至目前,使用 ZincSearch 尚无法进行搜索和日志两服务,还在研究中。
准备开始
本文适用于小规模生产部署(比如,自己只有一个乞丐小煮鸡,做出来服务只给你自己或者你认识的朋友),MinIO 之类的对象存储统统不用(太高射炮打蚊子了也)……
首先,出于安全起见,先新建一个专门的用户,这个用户是不给管理员权限的,不能把它添加到 sudo 组中:
sudo adduser paopao
安全起见,所有 Paopao-ce 的进程都使用普通权限运行,占用高位端口,然后再通过 Nginx 反代,将其反代到域名下的路由或者子域名中。
为了能后面和 Web 目录互通文件方便,先新建一个 public 目录,并授予 777 权限:
sudo mkdir /home/public/ sudo chmod a+rw /home/public/
然后先安装基本的 lemp。我在这里使用的是 Oneinstack。当然,使用一般的包管理器安装应该也可以。
安装完成后,使用 Oneinstack 提供的 vhost.sh 先新建一个 virtual host,然后配置好 ssl 访问。如果你使用的是 CloudFlare,需要在 CloudFlare 里新建源站证书(在 SSL/TLS -> Origin Server 中),下载下来私钥和证书以后,放在服务器当中你喜欢的目录里面,配置 Nginx 使用该证书和私钥文件:
server { listen 80; listen 443 ssl http2; ssl_certificate /usr/local/etc/cf-ssl/site-prod/site-prod.cer; //证书 ssl_certificate_key /usr/local/etc/cf-ssl/site-prod/site-prod.pri; //私钥 ssl_protocols TLSv1.2 TLSv1.3; ssl_ecdh_curve X25519:prime256v1:secp384r1:secp521r1; ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-E> ssl_conf_command Ciphersuites TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SH> ssl_conf_command Options PrioritizeChaCha; ssl_prefer_server_ciphers on; ssl_session_timeout 10m; ssl_session_cache shared:SSL:10m; ssl_buffer_size 2k; add_header Strict-Transport-Security max-age=15768000; ...
注意:
- 如果这里存在 ssl_pinning 相关选项,应该将其移除;
- 如果你在子域名下运行 Paopao-ce,且一级域名签发的证书或子域名 wildcard 证书和子域名签发的证书不一致或不能通用,需要将 CloudFlare 的 ssl 安全级别由 Full(strict) 降级为 Full。这将对你这个域名下的所有网站的安全性造成影响,请小心
验证
在生产前,请确保 Nginx 关闭了 directory listing 或类似功能。在网站静态文件目录(我这里是 /data/wwwroot/<sitename>)为空的情况下,直接访问该域名的目录,此时应该报一个 403 错误。如果是此情况,则继续按照此文档进行操作。
安装依赖系统
如下,先使用包管理器安装。如果你运行有 Oneinstack,务必不要让它自己装数据库:
sudo apt install golang nodejs npm mariadb-server
然后需要安装 zincsearch。如下:
wget https://github.com/zincsearch/zincsearch/releases/download/v0.4.7/zincsearch_0.4.7_Linux_x86_64.tar.gz tar -zxf zincsearch_0.4.7_Linux_x86_64.tar.gz sudo mkdir -p /usr/local/zinc/ sudo mkdir -p /data/zinc/ sudo cp zincsearch /usr/local/zinc/ sudo chown -R paopao /data/zinc/ sudo chmod a+x /usr/local/zinc/zincsearch
写一个 systemd 文件,管理 zincsearch 启动:
[Unit] Description=Zinc data search service After=network.target StartLimitIntervalSec=0 [Service] Type=simple Restart=always RestartSec=1 User=paopao ExecStart=/usr/local/zinc/zincsearch Environment="ZINC_DATA_PATH=/data/zinc/" [Install] WantedBy=multi-user.target
现在需要首次启动 zincsearch 并创建用户,如下:
ZINC_FIRST_ADMIN_USER=admin ZINC_FIRST_ADMIN_PASSWORD=Complexpass#123 ZINC_DATA_PATH=/data/zinc/ /usr/local/zinc/zincsearch
为安全起见,创建一个单独的用户,配置一个单独的权限组,把用户放在权限组里面,给它单独给 index。
设置完后开始处理 MariaDB。
之所以这里不建议使用 MySQL 的原因在于。MariaDB 在 secure_installation 时,可以方便地配置使用 unix socket 来鉴权,我一般的习惯是先使用 sudo 进去创建常规权限的用户,再给他们配置权限。这样在维护时直接使用 sudo mariadb 进数据库,方便又安全。
先使用 sudo mariadb_secure_installation 走完 secure_installation 流程之后,使用 sudo 直接登录进去,开始处理用户和数据库:
create database paopao; create user 'paopao'@'localhost'; alter user 'paopao'@'localhost' identified by aohw3yfuawhgfou3h4fgou34f; grant all privileges on paopao.* to 'paopao'@'localhost';
安全起见,只能给这个创建的普通用户这一个数据库的权限。
值得注意的是,如果创建数据库用户时不指定 @localhost,则应该在 config.yaml 配置中写出数据库的地址和端口(比如127.0.0.1:3306),而不是使用 0.0.0.0 来进行连接。从安全层面上而言,0.0.0.0 的设定会使得任意的 IPv4 地址都能与数据库连接,将会导致安全问题。
验证
检查所有新增的系统服务:
ls /etc/systemd/system
dbus-org.freedesktop.timesync1.service php-fpm.service
getty.target.wants sockets.target.wants
multi-user.target.wants sshd.service
mysql.service sysinit.target.wants
network-online.target.wants timers.target.wants
nginx.service zinc.service
目前应该至少有 mysql、nginx、zinc 这几个服务。把它们全部设置为开机自启,并启动:
sudo systemctl enable mysql nginx zinc sudo systemctl start mysql nginx zinc
安装 Paopao-ce
首先切换进 paopao 用户。在创建该用户时建议也不要给它赋予用户密码,需要使用时,使用 su 命令切换过去:
sudo su - paopao
在家目录中,直接使用 git 下载软件代码:
git clone https://github.com/rocboss/paopao-ce
然后将 scripts 中提供的 paopao-mysql.sql 文件导入 MariaDB 中。
由于等会儿要使用 web 目录下的东西,所以也不要直接下载提供的二进制。升级时,使用二进制文件替换即可。
后端服务配置文件
在配置文件中,要着重关注以下几个方面:
- 根节点 App 中是由此 web 应用制作的转制桌面客户端的相关配置。
- 根节点 Server 中是后端服务 API 的配置。
- 根节点 Features 中是功能集,使用其中的不同功能集,就启动整个服务的不同部分,也可以自己新建功能集或者调整其中内容。
- 根节点 WebServer 中是后端服务 API 运行的 IP 地址和端口信息。
新建和配置功能集
在小规模部署中,我们需要开以下几个服务。模仿之前功能集的格式,新建一个功能集填入服务名字就行:
- Admin – 后台管理 API 接口(尚在制作中);
- Web – 网页 API 服务接口(注意这里不是网页前端,这个服务的前后端是分离的);
- Zinc – 使用 Zinc 进行搜索的接口(目前,网站和它的对接似乎有点问题);
- LocalOSS – 本地静态文件存储;
- MySQL – 数据库服务;
- Base – 基础服务;
- LoggerZinc – 使用 Zinc 写入操作日志的接口(目前,网站和它的对接似乎有点问题);
- LoggerFile – 使用本地文件写操作日志(如果 LoggerZinc 不能使用,可以先使用这个);
- Migration – 数据迁移服务(从日志情况看,目前似乎暂时无法使用);
- Redis – 内存缓存数据库,如果启用此项,需要在开始的位置安装 redis,并。
- Friendship – “好友”相关 API 接口。没有的话,首页上的“好友”功能无法使用。
- 如果要打开手机验证码功能,需要打开 SmsJuhe 并配置其配置文件节点;如果要打开支付功能,需要打开 AliPay 并配置其配置文件节点。
然后需要改配置里面的几个位置:
- 根节点 LoggerZinc
- 需要修改 Host 为你部署的 Zinc 地址和端口;
- 需要修改 Index 为你分配的 index 名称;
- 需要修改 User 为你指定的 Zinc 用户;
- 需要修改 Password 为你指定 Zinc 用户的密码;
- 假如你用 IP 地址运行 Zinc,需要修改 Secure 为 False;假如你用域名运行 Zinc 服务并且开启了 SSL,需要修改为 True。
- 根节点 Zinc
- 和上面类似,但是把你的 Index 指定为数据用的 index 名称
- 根节点 Database
- TablePrefix 需要你记住,假如你使用同一个数据库存放好多个 Paopao-ce 实例的数据的话,应该修改这个表前缀,使数据不会冲突。
- 根节点 MySQL
- 更改用户名、密码、主机名、数据库名。注意,如果配置文件中的 MySQL 地址是 0.0.0.0:3306,则服务需要使用用户 ‘paopao’@’localhost’ 进行连接。如果这里指定了地址,比如 127.0.0.1:3306,则应该使用 ‘paopao’ 进行连接。
关于 LocalOSS、主站 API 服务和 Nginx 的特别说明
LocalOSS 的路由是写死了一部分在 paopao-ce 的核心代码里的。无论如何,假如你不做反向代理的话,路由里都会存在一个 /oss/。它的代码大概是这样:
package localoss import ( "path/filepath" "github.com/gin-gonic/gin" api "github.com/rocboss/paopao-ce/auto/api/s/v1" "github.com/rocboss/paopao-ce/internal/conf" "github.com/sirupsen/logrus" ) // RouteLocalOSS register LocalOSS route if needed func RouteLocalOSS(e *gin.Engine) { savePath, err := filepath.Abs(conf.LocalOSSSetting.SavePath) if err != nil { logrus.Fatalf("get localOSS save path err: %v", err) } e.Static("/oss", savePath) logrus.Infof("register LocalOSS route in /oss on save path: %s", savePath) } // RouteLocaloss register LocalOSS route if needed func RouteLocaloss(e *gin.Engine) { api.RegisterUserServant(e, newUserSrv(), newUserBinding(), newUserRender()) }
还有这样:
... else if cfg.If("LocalOSS") { if !LocalOSSSetting.Secure { uri = "http://" } return uri + LocalOSSSetting.Domain + "/oss/" + LocalOSSSetting.Bucket + "/" } return uri + AliOSSSetting.Domain + "/" }
看到了吗?
也就是说,当 API 接口生成路由的时候,他会按照上面的那个代码生成路由;在 API 的返回里返回图片的网址的时候,他则会按照下面的这个代码,使用字符串拼接的方式生成网址。不管怎么样,网址里面是有一个 oss 在里面的。这个 oss 是分别写死在路由生成和 API 返回的代码里面的。
你需要修改 LocalOSS 配置文件节点,不然容易出现最后在调试器看到文件变成从 127.0.0.1:8080 出来,加载失败的情况。注意,你要修改的配置节点是 LocalOSS,而不是 LocalossServer:
- 如果 SavePath 所指的路径在目录中不存在,使用普通用户权限创建之。注意,这个路径是相对于 paopao-ce 可执行文件的路径;
- 如果你主站使用 SSL,将 Secure 改为 True;
- Bucket 的名字可以随便起。假如你有多个 paopao 实例,修改此值应可避免媒体文件冲突;
- 现在假设你的主站域名是 t.example.net,如果你使用反向代理把 API 服务反代到了 https://t.example.net/api/,那么 API 服务的端点是 /api/v1/ 。这时候就分三种情况:
- 如果你想把 LocalOSS 下挂在 /api/oss/ 下,将这里改成 t.example.net/api;
- 如果你想把 LocalOSS 下挂在 /static/ ,或者什么别的名字,比如 img、cdn、……下,随你喜欢,将这里改成
t.example.net/<你的名字>
; - 如果你想把 LocalOSS 下挂在别的域名,比如 cdn.example.net 下,就将这里改成
cdn.example.net
。
另外,假如你需要把 LocalOSS 下挂在别的域名,则应该在 Nginx 中新起一个 vhost,然后按照 LocalossServer(注意不是 LocalOSS)的端口号,在 Nginx 中进行反代。
接下来,我们来考虑 Nginx。
这里配置反代大概应该这样写,我问了下 ChatGPT,大概是这样的
location /api/ { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_pass http://127.0.0.1:8008/; location ~ ^\/api\/oss\/(.*)$ { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_pass http://127.0.0.1:8008/oss/$1; } }
127.0.0.1:8008 是主站 API 的地址。这个规则用来把 API 服务挂载在 /api/
这个子目录下。
如果 location /api/ 这里末尾是带有斜杠的,那么在里面这个 proxy_pass 的网址末尾也应该有斜杠,否则会报 404 错误。
在这个 /api/ 的 location block 中,又套了一个 location block。location 后面的波浪线,表示这条规则进入正则表达式模式。这里分三种情况:
- 如果你想把 LocalOSS 下挂在 /api/oss/ 下,规则就是
^\/api\/oss\/(.*)$
; - 如果你想把 LocalOSS 下挂在 /static/ ,或者什么别的名字,比如 img、cdn、……下,随你喜欢,将这里改成
^\/<你的名字>\/<你的名字>\/(.*)$
,比如就改成^\/static\/(.*)$
; - 如果你想把 LocalOSS 下挂在别的域名,比如 cdn.example.net 下,则直接新起一个 vhost,在配置文件里面这样写:
location / { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_pass http://127.0.0.1:8008/oss/; }
即可。
生成前端文件
在项目目录中切进 web 目录,然后编辑 .env
文件:
- 如果你的 API 被反代到主站中的目录,比如
/api/
,请将VITE_HOST
填写成对应的目录名字,比如就填成api
。 - 要开启全站通知,将
VITE_ENABLE_ANOUNCEMENT
设为 true。 - 要开启支付功能,将
VITE_ENABLE_WALLET
设为 true。 - 修改
VITE_DEFAULT_TWEET_IMAGE_404
,变成你自己 LocalOSS 里面的。 - 剩下的配置基本都带有注释,自己改一下就行。
然后修改 package.json
,修改里面的 build 命令,改成 node --max_old_space_size=4096 node_modules/vite/bin/vite.js build
,总之就是允许 Node 打包时占用更多的内存,不然会 OOM。(emmm……)
然后在 web 目录运行 yarn build
。
最后,通过 rsync 把 web/dist 下的文件同步给 nginx 的网站目录就行。
可以修改一下最后生成的那个 manifest.json,在那里可以改改网站名字之类的。
服务配置
写一个 systemd 文件,这样就可以通过 systemctl 控制 paopao-ce 的行为(日志的话,要么在 Zinc 里看,要么在日志文件里看)。
从终端直接启动的时候,我是用这个命令:
GIN_MODE=release GOMAXPROCS=4 ./paopao-ce-build --no-default-features --features prod
写成配置文件就这样:
[Unit] Description=Paopao-ce After=network.target StartLimitIntervalSec=0 [Service] Type=simple Restart=always RestartSec=1 User=paopao WorkingDirectory=/home/paopao/paopao-ce Environment="GIN_MODE=release" "GOMAXPROCS=4" ExecStart=/home/paopao/paopao-ce/paopao-ce --no-default-features --features prod [Install] WantedBy=multi-user.target
最后一句话
值得一提的是,这个泡泡服务存在一种离谱的机控,如果用户没有填手机号,就强制不允许你发表图片和帖子。这时候只需要改下数据库,输入一个空的电话号在里面,你就能愉快地发帖了。