XiaBee's Studio.

Docker搭建NextCloud个人网盘

字数统计: 3.2k阅读时长: 15 min
2021/11/09

开端

  • 百度云非会员太慢了!!!
  • One Drive有时候连不上服务器!!!
  • 正好手头有个4G内存8M带宽的服务器,可以整个活
  • 手头也有个域名,已经搞了SSL证书,可以满足网盘加密传输的需求
  • 太长不看版:代码在这里,设置密码、添加证书、修改域名,docker-compose up -d就行

NextCloud简介

  • 官网

  • nextcloud是一款开源的、支持多平台的云盘,有服务器的小朋友可以整一个玩玩,可以搭一个自己的One Drive

搭建方式

官网的搭建过程比较麻烦,需要手动配置服务器再执行相关代码等等。这里懒癌晚期患者直接去dockerhub找了个官方镜像,直接通过容器进行安装。

首先要确保你的VPS中安装了dockerdocker-compose

1
2
3
4
5
sudo apt install docker.io
sudo apt install docker
sudo apt install docker-compose
sudo service docker start
# 以 Ubuntu 为例

单容器搭建

nextcloud独立容器版本使用的是Apache服务器,自带SQLite作数据库,基本满足个人需求。如果对性能要求不高的话直接单容器搭建也可以:

1
2
3
4
5
6
docker run -d \
--restart=always \
--name nextcloud \
-p 5000:80 \
-v ~/nextcloud:/var/www/html \
docker.io/nextcloud

参数解释:

1
2
3
4
5
6
7
run					# 运行容器实例
-d # 守护模式运行
-restart=always # 遇到问题就重启
--name nextcloud # 命名为nextcloud
-p 5000:80 # 将容器的80端口映射到宿主机的5000端口
-v ~/nextcloud:/var/www/html # 将容器的/var/www/html目录映射到主机的~/nextcloud目录
docker.io/nextcloud # 创建容器用到的镜像

构建完毕后,通过http://ip:5000就能访问nextcloud了,然后进行相关设置即可。

满血搭建

  • 项目在GitHub仓库
  • 相较于单容器的nextcloud,这次满血搭建添加了fpmnginxmariadbredis以提高安全性和性能
  • docker-compose部分借鉴了一位素不相识的名为chensmallx大佬的博客,稍微修改了一部分,解决了数据库的相关BUG
  • 要实现https访问的话需要提前准备域名和证书

项目的目录结构如下:

1
2
3
4
5
6
7
8
├── docker-compose.yml
└── proxy
├── conf.d
│   └── nextcloud.conf
└── ssl_certs
├── cert.cer
├── cert.key
└── fullchain.cer

没有域名和证书的朋友可以翻到这里

搭建方法

  • 将项目克隆到本地,把自己的SSL证书放入proxy/ssl_certs目录下
  • 修改proxy/conf.d/nextcloud.conf文件,将域名换成自己的
  • docker-compose up -d等待容器启动

各模块功能

  • FPMfastCgi做为呈现层,提高处理速度
  • nginx:前置反向代理,提高并发处理能力,同时提供https服务
  • mariadb:中大型关系数据库,替换轻型的SQLite,提高数据读写性能和可靠性
  • redis:缓存数据库,提供数据缓存能力和文件锁管理器

依赖关系

  • nextcloud是主业务,读写数据时会用到数据库mariadb和缓存redis,因此nextcloud依赖于mariadbredis
  • mariadbredis各司其职,挂了一个不会影响到另一个,故没有依赖关系
  • nginx作为反向代理,需要主体业务nextcloud正常运行才能提供代理服务,故nginx依赖于nextcloud

整体依赖关系如下:

1
2
3
4
5
6
7
8
# 依赖关系如下
/-> mariadb
nginx -> nextcloud -|
\-> redis


redis & mariadb -> nextcloud -> nginx
# 启动顺序则需要反过来

代码说明

环境变量

在老版本的docker-compose文件中,常见的环境变量可以直接用environment的变量表示,类似于chensmallx这种写法:

1
2
3
4
5
6
environment:
# environment可以对容器创建指定多个环境变量
- MYSQL_ROOT_PASSWORD=root_password # 这里配置root密码
- MYSQL_DATABASE=nextcloud
- MYSQL_USER=user_name # 这里配置一个非root账户给nextcloud使用
- MYSQL_PASSWORD=user_password # 这里配置上面那个账号的密码

然而,新版本的docker-compose部分特定镜像可能会读不到此时的环境变量,就会导致数据库容器在创建时没有设置密码,同时也无法知道root密码是什么,最终可能导致服务启动失败。

在查阅了多方issue之后,我把environment改成了键值对的形式:

1
2
3
4
5
environment:
MYSQL_ROOT_PASSWORD: set_your_password
MYSQL_DATABASE: nextcloud
MYSQL_USER: set_your_username
MYSQL_PASSWORD: set_your_pass

数据库启动

在搭建过程中遇到了innodb-read-only相关的BUG导致服务启动了但是无法安装,因此在启动服务时,我们直接利用commandinnodb-read-only干掉,并解除内存限制:

1
2
command: [--transaction-isolation=READ-COMMITTED,--binlog-format=ROW,--innodb-file-per-table=1,--skip-innodb-read-only-compressed]
# to avoid innodb bugs

完整的docker-compose

docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
version: '3.4'
services:

db:
image: mariadb
restart: unless-stopped
expose:
- "3306"
volumes:
- ./db:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: set_your_password
MYSQL_DATABASE: nextcloud
MYSQL_USER: set_your_username
MYSQL_PASSWORD: set_your_pass
command: [--transaction-isolation=READ-COMMITTED,--binlog-format=ROW,--innodb-file-per-table=1,--skip-innodb-read-only-compressed]
# to avoid innodb bugs

cache:
image: redis
restart: unless-stopped
expose:
- "6379"
volumes:
- ./cache:/data
command: redis-server --requirepass 'redis_password'

app:
image: nextcloud:fpm
restart: unless-stopped
expose:
- "9000"
volumes:
- ./app/html:/var/www/html
- ./app/data:/var/www/html/data
- ./app/config:/var/www/html/config
- ./app/custom_apps:/var/www/html/custom_apps
links:
- db:db
- cache:cache
depends_on:
- db
- cache

proxy:
image: nginx
restart: unless-stopped
expose:
- "80"
ports:
- 5000:443
volumes:
- ./app/html:/var/www/html
- ./proxy/conf.d:/etc/nginx/conf.d:ro
- ./proxy/ssl_certs:/etc/nginx/ssl_certs:ro
links:
- app:app
depends_on:
- app

完整的nextcloud.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
upstream php-handler {
server app:9000;
}

server {
listen 80;
listen [::]:80;
server_name your.domain.com;
# input your domain here
# enforce https
return 301 https://$server_name:443$request_uri;
}

server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name your.domain.com;

# Use Mozilla's guidelines for SSL/TLS settings
# https://mozilla.github.io/server-side-tls/ssl-config-generator/
# NOTE: some settings below might be redundant
ssl_certificate /etc/nginx/ssl_certs/cert.cer;
ssl_certificate_key /etc/nginx/ssl_certs/cert.key;

# Add headers to serve security related headers
# Before enabling Strict-Transport-Security headers please read into this
# topic first.
#add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;";
#
# WARNING: Only add the preload option once you read about
# the consequences in https://hstspreload.org/. This option
# will add the domain to a hardcoded list that is shipped
# in all major browsers and getting removed from this list
# could take several months.
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
add_header Referrer-Policy no-referrer;
add_header Strict-Transport-Security 15552000;
#add_header X-Frame-Options SAMEORIGIN;


# Remove X-Powered-By, which is an information leak
fastcgi_hide_header X-Powered-By;

# Path to the root of your installation
root /var/www/html;



# The following 2 rules are only needed for the user_webfinger app.
# Uncomment it if you're planning to use this app.
#rewrite ^/.well-known/host-meta /public.php?service=host-meta last;
#rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json last;

# The following rule is only needed for the Social app.
# Uncomment it if you're planning to use this app.
#rewrite ^/.well-known/webfinger /public.php?service=webfinger last;

location = /.well-known/carddav {
return 301 $scheme://$host:$server_port/remote.php/dav;
}
location = /.well-known/caldav {
return 301 $scheme://$host:$server_port/remote.php/dav;
}

# set max upload size
client_max_body_size 512M;
fastcgi_buffers 64 4K;

# Enable gzip but do not remove ETag headers
gzip on;
gzip_vary on;
gzip_comp_level 4;
gzip_min_length 256;
gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;

# Uncomment if your server is build with the ngx_pagespeed module
# This module is currently not supported.
#pagespeed off;

location / {
rewrite ^ /index.php$request_uri;
}

location ~ ^\/(?:build|tests|config|lib|3rdparty|templates|data)\/ {
deny all;
}
location ~ ^\/(?:\.|autotest|occ|issue|indie|db_|console) {
deny all;
}

location ~ ^\/(?:index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|oc[ms]-provider\/.+)\.php(?:$|\/) {
fastcgi_split_path_info ^(.+?\.php)(\/.*|)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param HTTPS on;
# Avoid sending the security headers twice
fastcgi_param modHeadersAvailable true;
# Enable pretty urls
fastcgi_param front_controller_active true;
fastcgi_pass php-handler;
fastcgi_intercept_errors on;
fastcgi_request_buffering off;
}

location ~ ^\/(?:updater|oc[ms]-provider)(?:$|\/) {
try_files $uri/ =404;
index index.php;
}

# Adding the cache control header for js, css and map files
# Make sure it is BELOW the PHP block
location ~ \.(?:css|js|woff2?|svg|gif|map)$ {
try_files $uri /index.php$request_uri;
add_header Cache-Control "public, max-age=15778463";
# Add headers to serve security related headers (It is intended to
# have those duplicated to the ones above)
# Before enabling Strict-Transport-Security headers please read into
# this topic first.
#add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;";
#
# WARNING: Only add the preload option once you read about
# the consequences in https://hstspreload.org/. This option
# will add the domain to a hardcoded list that is shipped
# in all major browsers and getting removed from this list
# could take several months.
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
add_header Referrer-Policy no-referrer;

# Optional: Don't log access to assets
access_log off;
}

location ~ \.(?:png|html|ttf|ico|jpg|jpeg|bcmap)$ {
try_files $uri /index.php$request_uri;
# Optional: Don't log access to other assets
access_log off;
}
}

故障排除

先确保容器正常运行:docker-compose ps查看容器状态:都是Up说明运行成功

image.png

Nginx一直重启

证书设置

如果出现proxy一直在重启的情况,可以查看一下日志docker-compose logs:大部分时候应该是没放证书或者证书设置错误……

image.png

比如这个就是典型的忘记设置证书了:重新配置证书即可

image.png

关闭https

如果没有证书的话,把nextcloud.conf设置成http的即可:

443那一段直接复制粘贴到80上;同时修改docker-compose.yml的端口映射:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
## nextcloud.conf
upstream php-handler {
server app:9000;
}

server {
listen 80;
listen [::]:80;

add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
add_header Referrer-Policy no-referrer;
add_header Strict-Transport-Security 15552000;
#add_header X-Frame-Options SAMEORIGIN;


# Remove X-Powered-By, which is an information leak
fastcgi_hide_header X-Powered-By;

# Path to the root of your installation
root /var/www/html;



# The following 2 rules are only needed for the user_webfinger app.
# Uncomment it if you're planning to use this app.
#rewrite ^/.well-known/host-meta /public.php?service=host-meta last;
#rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json last;

# The following rule is only needed for the Social app.
# Uncomment it if you're planning to use this app.
#rewrite ^/.well-known/webfinger /public.php?service=webfinger last;

location = /.well-known/carddav {
return 301 $scheme://$host:$server_port/remote.php/dav;
}
location = /.well-known/caldav {
return 301 $scheme://$host:$server_port/remote.php/dav;
}

# set max upload size
client_max_body_size 512M;
fastcgi_buffers 64 4K;

# Enable gzip but do not remove ETag headers
gzip on;
gzip_vary on;
gzip_comp_level 4;
gzip_min_length 256;
gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;

# Uncomment if your server is build with the ngx_pagespeed module
# This module is currently not supported.
#pagespeed off;

location / {
rewrite ^ /index.php$request_uri;
}

location ~ ^\/(?:build|tests|config|lib|3rdparty|templates|data)\/ {
deny all;
}
location ~ ^\/(?:\.|autotest|occ|issue|indie|db_|console) {
deny all;
}

location ~ ^\/(?:index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|oc[ms]-provider\/.+)\.php(?:$|\/) {
fastcgi_split_path_info ^(.+?\.php)(\/.*|)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param HTTPS on;
# Avoid sending the security headers twice
fastcgi_param modHeadersAvailable true;
# Enable pretty urls
fastcgi_param front_controller_active true;
fastcgi_pass php-handler;
fastcgi_intercept_errors on;
fastcgi_request_buffering off;
}

location ~ ^\/(?:updater|oc[ms]-provider)(?:$|\/) {
try_files $uri/ =404;
index index.php;
}

# Adding the cache control header for js, css and map files
# Make sure it is BELOW the PHP block
location ~ \.(?:css|js|woff2?|svg|gif|map)$ {
try_files $uri /index.php$request_uri;
add_header Cache-Control "public, max-age=15778463";
# Add headers to serve security related headers (It is intended to
# have those duplicated to the ones above)
# Before enabling Strict-Transport-Security headers please read into
# this topic first.
#add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;";
#
# WARNING: Only add the preload option once you read about
# the consequences in https://hstspreload.org/. This option
# will add the domain to a hardcoded list that is shipped
# in all major browsers and getting removed from this list
# could take several months.
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
add_header Referrer-Policy no-referrer;

# Optional: Don't log access to assets
access_log off;
}

location ~ \.(?:png|html|ttf|ico|jpg|jpeg|bcmap)$ {
try_files $uri /index.php$request_uri;
# Optional: Don't log access to other assets
access_log off;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
## docker-compose的proxy模块:把443改成80
proxy:
image: nginx
restart: unless-stopped
expose:
- "80"
ports:
- 5000:80
volumes:
- ./app/html:/var/www/html
- ./proxy/conf.d:/etc/nginx/conf.d:ro
- ./proxy/ssl_certs:/etc/nginx/ssl_certs:ro
links:
- app:app
depends_on:
- app

重新构建容器:

1
2
3
4
5
docker-compose down
# 关闭并删除原有容器

docker-compose up -d
# 构建新容器

此时我就部署了一个http服务的nextcloud

image.png

SQLSTATE[HY000] [2002] No such file or directory

注册时出现数据库找不到localhost的情况:

image.png

问题原因:

因为我们用的数据库的是容器,所以不能直接用主机的localhost或者localhost:3306去寻找主机。

解决方案:

因该通过容器的DNS服务寻找,比如在我们项目中,就应该输入db:3306

image-20211110102356732.png

您的数据目录可被其他用户读取

image.png

问题原因:这里用的是WSL做演示。WSL用的是WindowsNTFS文件系统,权限是由Windows控制的,故所有目录都是0770……

解决方案:别用WSL……整一个纯正的Linux系统就行。

其他数据库问题

  • innodb相关的问题前面提到了,参考项目中docker-compose.yml重新设置即可。
  • 环境变量的问题前面也提到了,改成键值对的形式即可。
  • 如果是直接克隆下来的项目,应该不会有这俩问题

最终效果

最后安装完毕大概长这样啦:这个是没怎么设置的原始UI

image.png

小结

容器操作不难,编排也不难,难的是写出了配置文件然后疯狂debug……

Refference

CATALOG
  1. 1. 开端
  2. 2. NextCloud简介
  3. 3. 搭建方式
    1. 3.1. 单容器搭建
    2. 3.2. 满血搭建
      1. 3.2.1. 搭建方法
      2. 3.2.2. 各模块功能
      3. 3.2.3. 依赖关系
    3. 3.3. 代码说明
      1. 3.3.1. 环境变量
      2. 3.3.2. 数据库启动
      3. 3.3.3. 完整的docker-compose
      4. 3.3.4. 完整的nextcloud.conf
  4. 4. 故障排除
    1. 4.0.1. Nginx一直重启
      1. 4.0.1.1. 证书设置
      2. 4.0.1.2. 关闭https
    2. 4.0.2. SQLSTATE[HY000] [2002] No such file or directory
    3. 4.0.3. 您的数据目录可被其他用户读取
    4. 4.0.4. 其他数据库问题
  • 5. 最终效果
  • 6. 小结
  • 7. Refference