从零搭建 NextCloud 记录

2020-11-05 41点热度 1人点赞 0条评论

NextCloud 作为著名的开源私有云,一直饱受好评,而许多搭建过程也一直饱受"好评"进而都开始使用 docker。本文记录本站搭建的过程,期间埋坑一堆


1、选材

从头开始,那么肯定要选最新的系统了,CentOS 8 安排上! Ubuntu 20.04 安排上!

先到官网看看,哦,LAMPR,不行啊,Apache 动态去管理云盘静态资源?怎么想都亏爆啊

继续看看,脚本安装,啊这估计是给白板机准备的,像我们这些老油条肯定得是【自定义】

先准备下环境吧,CentOS 8 Ubuntu 20.04 + Nginx v1.18 + PHP-FPM v7.4 + Mysql 8.0 + Redis 5 + NextCloud


2、搭建

2.1、初逢

最开始我是直接把 Wordpres 的 LNMP 组件直接放上用,结果……惨遭毒打

刚开始看来还是很良心的,CentOS 还有案例支持,多好,赶紧安排上 [ 文档链接 ](本分支结局爆炸已删)

NextCloud 调用了大量的 PHP 相关组件,这些远远不是 Wordpres 所需要的那一丢丢的 PHP 组件所能比拟的。

Docker 环境的官方 PHP 包也缺少大量组件,必须额外增加。目前没有什么办法能让我在短时间安装好 NextCloud 巨量的组件支持 并且还不会报错,所以放弃 最终发现其实都是参数配置出错

无奈之下,只能先放弃了 Docker 环境 与 生产环境 直接搭建的想法


2.2、开始

老司机一般为了保证开车平稳,都是用的最熟悉的东西

那在 Linux 中,大家最常见的东西,肯定是 包管理器 apt-get

apt install nginx-full mysql-server mysql-client redis redis-server

PHP 中间摸爬滚打太多,干脆最后安装上的包都整理在这里好了。注意 PHP 版本是 7.4 的

apt install php-bcmath php-common php-curl php-fpm php-gd php-gmp php-igbinary php-imagick php-imap php-json php-mbstring php-redis php-zip
[关联] apt install php7.4 php7.4-bcmath php7.4-cli php7.4-common php7.4-curl php7.4-fpm php7.4-gd php7.4-gmp php7.4-imap php7.4-intl php7.4-json php7.4-ldap php7.4-mbstring php7.4-mysql php7.4-opcache php7.4-readline php7.4-xml php7.4-zip

那么按照该环境开始改配置。本文所使用的配置文件位置如下

Nginx 部分
用户 nginx:nginx
配置文件 /etc/nginx/nginx.conf
站点文件 /etc/nginx/site-enabled/nextcloud.conf
站点路径 /opt/nextcloud/
存储路径 /opt/nextcloud_data/

PHP-FPM 部分
用户 nginx:nginx
配置文件 /etc/php/7.4/fpm/php.ini;/etc/php/7.4/fpm/pool.d/www.conf
链接文件 /etc/php/7.4/fpm/conf.d/*.ini
会话文件 /var/lib/php/sessions
传输文件 /var/run/php-fpm.sock

Mysql 部分
用户 mysql:mysql
配置文件 /etc/mysql/mysql.conf.d/mysqld.cnf
数据文件 /var/lib/mysql/
传输文件 /var/run/mysqld/mysqld.sock

Redis 部分
用户 redis:redis
配置文件 /etc/redis/redis.conf
数据文件 /var/lib/redis/dump.rdb
传输文件 /var/run/redis/redis.sock

2.3、Nginx 配置

Nextcloud 官方给了 Nginx 配置文件方案,直接照抄即可 [ 链接 ]

……直接抄……

注意需要修改 root 参数,指向有效的本地文件

root /opt/nextcloud;

额外建议分离 站点日志 ,需要增加在 server{} 中

access_log  /var/log/nginx/nextcloud.log  main;
error_log  /var/log/nginx/nextcloud-error.log;

2.4、Mysql 配置

首先优先在 Mysql 配置文件中增加如下字段,并重启 Mysql 服务器
前三条字段是限制储存数据格式,同时允许 4bit emoji 字符写入数据库。
第四个是关闭 binlog 的产生(集群则不需要关闭)

[mysqld]
character_set_server = utf8mb4
collation_server = utf8mb4_general_ci
innodb_file_per_table=1
skip-log-bin

然后登陆数据库,并初始化 'root'@'localhost' 密码

mysql -uroot -p
ALTER USER 'root'@'localhost' IDENTIFIED BY 'MyNewPass4!';

增加数据库用户 cloudmanager 并配置密码为 MyNewPass2!
增加数据库 nextclouddb 并为 cloudmanager 附加权限

CREATE USER 'cloudmanager'@'localhost' IDENTIFIED BY 'MyNewPass2!';
CREATE DATABASE IF NOT EXISTS nextclouddb CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
GRANT ALL PRIVILEGES ON nextclouddb.* TO 'cloudmanager'@'localhost';
FLUSH PRIVILEGES;

退出并使用新用户登录并测试数据库访问情况,测试好后退出

mysql -uroot -p
show databases;

2.5、PHP-FPM 配置

首先我们需要配置 php.ini 这个主体文件。

在这里其实有较多配置,但是我使用的大部分都不是主要的,关注主要的内容即可

memory_limit = 512M
error_log = /var/log/php7.4_error.log
post_max_size = 100M
upload_max_filesize = 100M
date.timezone = PRC
pdo_mysql.default_socket="/var/run/mysqld/mysqld.sock"
mysqli.default_port = 3306
mysqli.default_socket = "/var/run/mysqld/mysqld.sock"
session.save_handler = redis
session.save_path = "unix:/var/run/redis/[email protected]"
opcache.enable=1
opcache.enable_cli=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=10000
opcache.revalidate_freq=1
opcache.save_comments=1
opcache.huge_code_pages=1

接着我们需要配置 www.conf 的 php-fpm 线程文件,同样也是关注主要内容即可

注意其中下面五条其实和上面的 php.ini 重复,主要是在使用集群时需要自定义配置
中间 slowlog 和 request_slowlog_timeout 是慢查询日志,如果 php 出现 3s 以上的操作会记录

user = nginx
group = nginx
listen = /var/run/php-fpm.sock
listen.backlog = 2048
pm.max_children = 120
pm.start_servers = 12
pm.min_spare_servers = 6
pm.max_spare_servers = 18
slowlog = /var/log/php7.4-$pool-slow.log
request_slowlog_timeout = 3
php_admin_value[error_log] = /var/log/php74-$pool-error.log
php_admin_flag[log_errors] = on
php_value[session.save_handler] = redis
php_value[session.save_path]    = "unix:/var/run/redis/[email protected]"
php_value[soap.wsdl_cache_dir]  = "/tmp"

2.6、Redis 配置

在 Redis 中也需要同样配置,一共五条。
关闭 TCP 端口
开放 Socket 传输文件,以及赋予权限为 rw-rw----
配置 Redis 密码 本例为 [email protected] 上方曾经用到
增加 Redis 最大分配内存

port 0
unixsocket /var/run/redis/redis.sock
unixsocketperm 660
requirepass [email protected]
maxmemory 512mb

配置完后,我们还需要额外给 php-fpm 访问 redis.sock 的权限,方式是为 nginx 增加权限组

usermod -G redis nginx

如果 Redis 运行时提示一些内容,可以检查一下相关提示并根据提示进行优化操作。

Redis 测试命令

redis-cli -s /var/run/redis/redis.sock
auth [email protected]

2.7、NextCloud 权限配置

解压 NextCloud 文件至 /opt/nextcloud/ 可以检查到 /opt/nextcloud/version.php 存在

unzip nextcloud.zip
mv ./nextcloud /opt/
chown -R nginx:nginx /opt/nextcloud/

创建存储路径 /opt/nextcloud_data/ 并附加权限

mkdir /opt/nextcloud_data
chown -R nginx:nginx /opt/nextcloud_data/

2.8、NextCloud 配置

上方的内容汇总,直接在初始化界面填入即可

用户 : 
密码 : 

存储路径 : /opt/nextcloud_data

数据库用户 cloudmanager
数据库密码 MyNewPass2!
数据库库名 nextclouddb
数据库主机 localhost

生成的配置文件类似如下

   'instanceid' => 'qwertyuiop',
   'passwordsalt' => 'asdfghjkl',
   'secret' => 'zxcvbnm',
   'trusted_domains' =>
   array (
     0 => 'cloud.domain.com',
   ),
   'datadirectory' => '/opt/nextcloud_data',
   'dbtype' => 'mysql',
   'version' => '21.0.1.1',
   'overwrite.cli.url' => 'https://cloud.domain.com',
   'dbname' => 'nextclouddb',
   'dbhost' => 'localhost',
   'dbport' => '',
   'dbtableprefix' => 'oc_',
   'mysql.utf8mb4' => true,
   'dbuser' => 'cloudmanager',
   'dbpassword' => 'MyNewPass2!',
   'installed' => true,
   'debug' => false,

3、奇葩 BUG 汇总

3.0、排查方案

首先优先开启 log 模式

php.ini     ->  display_errors on(默认 应该 off)
redis.conf  ->  loglevel debug(默认 notice)
config.php  ->  'debug' => true,  (默认 false)
nextcloud   ->  /opt/nextcloud_data/nextcloud.log  (也可能在站点目录里)

3.1、无限登录循环

现象:是登录按钮点击后,页面刷新,又回来没变
原理:本质是 Redis 写入 session 失败,所以登录失效
处置:检查 Redis 运行情况即可。

本人 OS:chmod 644 /etc/redis/redis.conf 坑一年


3.2、消息传递被阻拦

现象:消息通知清理失败,新建出错,删除出错,编辑资料自动失效,却有一些小东西可以用
原理:NextCloud 使用了 method 除常规 (GET|HEAD|POST) 外的 (PUT|DELETE) 操作
处置:取消限制 method 的规则

本人 OS:撞 Nginx 规则还是真头一回。


4、其他配置

4.1、NextCloud 集群配置

在 站点文件/config/config.php 中增加如下字段,支持 redis 集群。

  'memcache.distributed' => '\OC\Memcache\Redis',
  'redis' => [
    'host' => '/var/run/redis/redis.sock',
    'port' => 0,
    'dbindex' => 0,
    'password' => '4e1fa509f485e548e789f9ddba6eba62d68037467f23dbe362077eba6a592f6c',
    'timeout' => 1.5,
  ],
  'memcache.locking' => '\OC\Memcache\Redis',

注意,config.php 的上下格式是有优先级的。少的时候可能会直接报错

在 php.ini 中增加 redis session 慢写入和锁定的配置

redis.session.locking_enabled=1
redis.session.lock_retries=-1
redis.session.lock_wait_time=10000

在 Mysql 配置文件中也需要增加一部分,比如去掉之前的

[mysqld]
#skip-log-bin
transaction_isolation = READ-COMMITTED
binlog_format = ROW
#innodb_large_prefix=on                #mysql8 失效
#innodb_file_format=barracuda          #mysql8 失效
innodb_buffer_pool_size=256M
innodb_io_capacity=4000

4.2、Docker 下去除 index.php 的链接字样

当你看到 domain.com/index.php/hello.txt 这样的 URL 感到十分苦恼,可以通过修改配置文件撤掉该字样。

第一种方案是修改 URL 重写规则,建议采用此方案 [ 链接 ]

<IfModule mod_rewrite.c>
  Options -MultiViews
  RewriteRule ^core/js/oc.js$ index.php [PT,E=PATH_INFO:$1]
  RewriteRule ^core/preview.png$ index.php [PT,E=PATH_INFO:$1]
  RewriteCond %{REQUEST_FILENAME} !\.(css|js|svg|gif|png|html|ttf|woff|ico|jpg|jpeg)$
  RewriteCond %{REQUEST_FILENAME} !core/img/favicon.ico$
  RewriteCond %{REQUEST_FILENAME} !/remote.php
  RewriteCond %{REQUEST_FILENAME} !/public.php
  RewriteCond %{REQUEST_FILENAME} !/cron.php
  RewriteCond %{REQUEST_FILENAME} !/core/ajax/update.php
  RewriteCond %{REQUEST_FILENAME} !/status.php
  RewriteCond %{REQUEST_FILENAME} !/ocs/v1.php
  RewriteCond %{REQUEST_FILENAME} !/ocs/v2.php
  RewriteCond %{REQUEST_FILENAME} !/updater/
  RewriteCond %{REQUEST_FILENAME} !/ocs-provider/
  RewriteCond %{REQUEST_URI} !^/.well-known/acme-challenge/.*
  RewriteRule . index.php [PT,E=PATH_INFO:$1]
  RewriteBase /
  <IfModule mod_env.c>
    SetEnv front_controller_active true
    <IfModule mod_dir.c>
      DirectorySlash off
    </IfModule>
  </IfModule>
</IfModule>

第二种方案是过去使用的,由于上方有好的方式所以不建议使用。同时仅能修改一部分的 URL,不是所有的都可以用这个方式修改。

./lib/private/URLGenerator.php 第 246 行附近
  public function getAbsoluteURL(string $url): string {
    $separator = strpos($url, '/') === 0 ? '' : '/';
    /** index_edit **/
    $url=str_replace("/index.php/","/",$url);

./config/config.php 新增一行
  'htaccess.RewriteBase' => '/',

4.3、安装 STUN/TURN 服务器

文章参考链接 [ 链接 ] 配置文件参数说明 [ 链接 ]

配置文件参考链接 [ 链接 ] 服务端测试方式 [ 链接 ]

apt install coturn

然后在 Ubuntu 中开启服务器

sed -i '/TURNSERVER_ENABLED/c\TURNSERVER_ENABLED=1' /etc/default/coturn
systemctl enable coturn.service
systemctl start coturn.service

接着修改配置文件 /etc/turnserver.conf

#syslog    默认自带的配置文件仅开启了 syslog 一个参数

# 配置 turn 监听接口(可选),turn 监听端口,备用 turn 监听端口(可选),turns 监听端口(可选),备用 (ALT)turns 监听端口(可选),以及内外网 NAT 地址(可选)如果备用端口未配置,默认为主端口号+1 的端口
# listening-device=eth0
# external-ip=101.202.102.201/192.168.1.100
listening-port=3478
alt-listening-port=3479
tls-listening-port=5349
alt-tls-listening-port=5350

fingerprint
lt-cred-mech

# 开启 NextCloud 所使用的 WebAuth 认证
use-auth-secret
# 配置 NextCloud 所使用的 WebAuth 认证密钥(时间密钥)(自行修改)
static-auth-secret=yoursecretpasswordqwertytuiop
# 配置本服务器所属域名(自行修改)
realm=your.domain.name

total-quota=100
bps-capacity=0
stale-nonce

# 配置 TLS 使用证书(自行修改)
cert=/etc/cert/fullchain.pem
pkey=/etc/cert/privkey.pem
# 配置自定义加密选择方式
# cipher-list="ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AES:RSA+3DES:!ADH:!AECDH:!MD5"

# 安全限制,禁用本地回复,禁用广播回复,禁止 DTLS(UDP 方式的 TLS 加密),禁止 TLSV1.0/1.1
no-loopback-peers
no-multicast-peers
no-dtls
no-tlsv1
no-tlsv1_1
no-cli
# 输出日志
no-stdout-log
syslog
simple-log
log-file=/var/log/coturn.log

配置完重启服务器,开放防火墙对应端口(以下仅开启了 turn 监听端口)(UDP 无认证可以选择不开)

firewall-cmd --zone=public --per --add-port=3478/tcp
firewall-cmd --zone=public --per --add-port=3478/udp
firewall-cmd --reload

在服务端配置页面中,进入 后台管理页面,通话(talk),在 STUN 服务器 和 TURN 服务器 中填写对应的信息,并等待测试通过后保存即可。(使用非加密的 turn 是因为 nextcloud 的 webrtc 已经加密,并且不能很好支持 turns [ 链接 ])

stun:your.domain.name:3478
turn:your.domain.name:3478 yoursecretpasswordqwertytuiop tcp/udp

在检测网站中,清空默认的 Google stun server,然后手动添加本次搭建的 STUN 服务器,URI 需要携带前缀 stun:yourdomainname:port
检测网站 [ 链接 ] WebRTC 测试网站 [ 链接 ]

点击 Gather candidates 按钮开始测试,等待下方出现 host 和 srflx 发送接收两条消息,即为正常使用。


4.4、新用户云盘默认文件

Nextcloud 创建用户时,会自动复制 ./core/skeleton 中的文件到新用户目录下。

所以如果需要修改默认用户云盘的文件内容,可以直接清空这个数据。


4.5、Redis 配置

透明大页面(THP)是一种 Linux 内存管理系统,它通过使用较大的内存页面来减少具有大量内存的计算机上的转换后备缓冲区(TLB)查找的开销。

但是,启用 THP 时,数据库工作负载通常表现不佳,因为它们往往具有稀疏而不是连续的内存访问模式。 在 Linux 上运行 MongoDB 时,应禁用 THP 以获得最佳性能。

默认 Redis 在启动时会检查 THP 功能是否启用,并在发现该功能启用后提示如下警告内容

WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.

针对该问题我们需要禁用该功能,但这个功能不能在 sysctl.conf 中禁用,所以我们需要手动创建一个文件,参考 [ 链接 ]

vim /etc/systemd/system/sysctl-thp-disable.service
[Unit]
Description=Disable Transparent Huge Pages (THP)
DefaultDependencies=no
After=sysinit.target local-fs.target
Before=redis.service

[Service]
Type=oneshot
ExecStart=/bin/sh -c 'echo never | tee /sys/kernel/mm/transparent_hugepage/enabled > /dev/null'


[Install]
WantedBy=basic.target
systemctl enable sysctl-thp-disable.service
systemctl start sysctl-thp-disable.service

检查 THP 是否已成功设置为 [never] 通过运行以下命令:

cat /sys/kernel/mm/transparent_hugepage/enabled

StarryVoid

这个人很懒,什么都没留下