0.写在前面
很久之前,我就在博客首页放了个视频,因为怕把视频这种大文件扔到对象存储或CDN上会导致昂贵的费用,所以把这些大文件扔到了一台美国的大硬盘服务器上。

最初的方案只是简易的搭建一个LNMP环境直接把这些大文件存储起来。于是在以后每次更换视频的时候,都要登录xftp去手动上传视频。最近感觉这样做太蛋疼了,而且又想放一些东西。一开始打算使用H5ai凑合就算了,但是再想想H5ai并不带管理功能,上传或修改文件仍要使用xftp工具,痛点仍未解决,于是萌生了这个使用自建云盘想法。


1.云盘选型
自建云盘首先想到的就是OwnCloud,NextCloud,Seafile这几个方案。网上都说NextCloud是OwnCloud的继任者(OwnCloud元老离开并创立NextCloud项目),我也没深入研究,就不多说了。但是前两年使用OwnCloud的蛋疼经历至今我仍感觉历历在目,所以就OwnCloud好感度-1。
方案 \ 项目 | OwnCloud | NextCloud | Seafile |
环境依赖 | LNMP* | LNMP | 要求环境未安装其他环境应用 |
安装方便性 | 一般,需要下载整个项目然后安装,也可以使用Docker或包管理器进行安装 | 简易,只需要上传一个PHP文件并配置 | 困难,需要一个干净的环境使用包管理器进行安装 |
存储方式 | 文件存储,加密存储 | 文件存储 | 切片存储 |
存储可靠性* | 低 | 中 | 高 |
*以上表格内的 “存储可靠性” 一项无数据支撑,仅凭使用印象打分。
尽管Seafile的存储可靠性较高,但是由于其对环境的严格要求及存储方式的特别,注定了Seafile更适合于严谨的存储场景,例如企业自建云盘(本人以前就帮当时所在的高中部署了Seafile,用于存放视频、图片等资源,至今稳定运行2年有余)。
加上上文说到,两年前的几乎同一个时间,我又部署过OwnCloud,当时使用的是php5.6,慢的一批,而且LNMP服务经常宕机,加上OwnCloud当时的存储方式貌似是加密的,导致web服务损坏,丢失秘钥后,文件几乎无法恢复,所以当时觉得蛋疼至极,所以好感几乎为0
对比了这三个存储方案后,我选择了NextCloud。
问题又来了,我在使用NextCloud的过程中发现NextCloud更注重于云盘,很多设置是从文件安全性的角度出发。所以即使有文件分享,文件分享后,可以直接使用 “文件分享链接/download” 的形式作为直链,但这个直链如果直接嵌套在网页内容上,例如在video标签直接嵌套这个直链进行视频播放,会导致无限的302跳转。详情请看以下的Issue – Too many redirects for shared image links (direct link).
之后我又发现了NextCloud的一个插件(nextcloud-sharing-path),说是可以把NextCloud当成CDN源站使用,但是也是没解决上述的无限的302跳转的问题。所以就想到了在data的某个目录下安装H5ai的想法。
让普通用户直接访问域名根目录,显示的是H5ai界面,同时管理员访问某个子目录(例如 a.com/_pan )可以进入NextCloud对文件进行管理。
综上所述,我们就需要配置Nginx伪静态规则实现这些想法。
1. 安装NextCloud
NextCloud的安装非常简单,此文不作详细叙述,下面放两个链接以供参考
但值得一提的是,我使用的Web服务器是Nginx,并且请在网站根目录创建_pan文件夹并把NextCloud安装进其中,以方便后续的Nginx配置
安装完成后,请记住您的用户名,并开始配置Nginx伪静态规则
Nginx伪静态设置
由于我们服务端不是安装在网站根目录,所以需要手动修改Nginx伪静态规则
# 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; # 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; location = /robots.txt { allow all; log_not_found off; access_log off; } # 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 /nextcloud/public.php?service=host-meta last; #rewrite ^/.well-known/host-meta.json /nextcloud/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 /nextcloud/public.php?service=webfinger last; location = /.well-known/carddav { return 301 $scheme://$host:$server_port/nextcloud/remote.php/dav; } location = /.well-known/caldav { return 301 $scheme://$host:$server_port/nextcloud/remote.php/dav; } location /.well-known/acme-challenge { } location ^~ /nextcloud { # 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 /nextcloud { rewrite ^ /nextcloud/index.php$request_uri; } location ~ ^\/nextcloud\/(?:build|tests|config|lib|3rdparty|templates|data)\/ { deny all; } location ~ ^\/nextcloud\/(?:\.|autotest|occ|issue|indie|db_|console) { deny all; } location ~ ^\/nextcloud\/(?: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 ~ ^\/nextcloud\/(?: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 ~ ^\/nextcloud\/.+[^\/]\.(?:css|js|woff2?|svg|gif|map)$ { try_files $uri /nextcloud/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 ~ ^\/nextcloud\/.+[^\/]\.(?:png|html|ttf|ico|jpg|jpeg|bcmap)$ { try_files $uri /nextcloud/index.php$request_uri; # Optional: Don't log access to other assets access_log off; } }
官方演示的目录是/nextcloud,所以我们要把伪静态规则中的nextcloud改为/_pan
# 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; # 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; location = /robots.txt { allow all; log_not_found off; access_log off; } # 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 /_pan/public.php?service=host-meta last; #rewrite ^/.well-known/host-meta.json /_pan/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 /_pan/public.php?service=webfinger last; location = /.well-known/carddav { return 301 $scheme://$host:$server_port/_pan/remote.php/dav; } location = /.well-known/caldav { return 301 $scheme://$host:$server_port/_pan/remote.php/dav; } location /.well-known/acme-challenge { } location ^~ /_pan{ # 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 /_pan { rewrite ^ /_pan/index.php$request_uri; } location ~ ^\/_pan\/(?:build|tests|config|lib|3rdparty|templates|data)\/ { deny all; } location ~ ^\/_pan\/(?:\.|autotest|occ|issue|indie|db_|console) { deny all; } location ~ ^\/_pan\/(?: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 ~ ^\/_pan\/(?: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 ~ ^\/_pan\/.+[^\/]\.(?:css|js|woff2?|svg|gif|map)$ { try_files $uri /_pan/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 ~ ^\/_pan\/.+[^\/]\.(?:png|html|ttf|ico|jpg|jpeg|bcmap)$ { try_files $uri /_pan/index.php$request_uri; # Optional: Don't log access to other assets access_log off; } }
改完后,记得更改配置文件中的root为你的网站根目录,并把fastcgi_pass php-handler指向你的php-fpm
自此,NextCloud部分就安装完毕
2.配置H5ai
首先在你的NextCloud账户中创建任意目录,本文使用public作为目录。

创建public目录后,nextcloud会相对应的在data/{NextCloud用户名}/files下创建public目录
所以我们要把H5ai安装在 data/{NextCloud用户名}/files/public 目录下让H5ai前端能访问到public目录下的所有内容。
请记得把_h5ai目录设置为 0770 权限,文件所有者和用户组要与Nginx和php-fpm保持一致。
为H5ai配置Nginx伪静态规则
我们想在域名根目录访问H5ai,所以要使用 location / 块来处理
location / { root {root}/_pan/data/{NextCloud用户名}/files/public; index index.php index.html /_h5ai/public/index.php; location ~* ^.+\.(jpeg|jpg|png|gif|bmp|ico|svg|css|js)$ { expires max; } location ~ [^/]\.php(/|$) { fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; if (!-f $document_root$fastcgi_script_name) { return 404; } fastcgi_pass {php-fpm地址及端口,例如:127.0.0.1:9009}; fastcgi_index index.php; include /etc/nginx/fastcgi_params; } }
记得把配置文件中的 root, NextCloud用户名, php-fpm地址及端口按自己实际情况更改,然后把配置放入Nginx虚拟机设置的Server块中。
自此,所有配置已经完成。
3.遇坑经历
配置这个东西花了我近3天的时间,下面说说我遇到的问题。
- NextCloud的data目录的权限一定要为 0770,否则打开NextCloud时会报 “RouteNotFoundException”
- Nginx与php-fpm的用户名与用户组应保持一致,否则H5ai会提示403 Forbidden。这是因为NextCloud对data中文件的访问不是直接走Nginx的,而是交由php-fpm处理的,而H5ai是直接交由Nginx处理的。如果php-fpm与Nginx的用户或用户组不一致时,加上上文提到NextCloud的data目录的权限一定要为 0770 ,Nginx就对data目录没有访问权限,所以就会返回403 Forbidden的错误。
- Safari浏览器不支持MKV格式的视频或H.265编码的视频。
4.写在最后
我对Nginx了解还不是很多,所以上述的Nginx伪静态设置如果有什么更好的方法或者存在什么漏洞,欢迎在留言里指出!(*^▽^*)
目前打算在h5ai上加一下上传功能
apache2作为webserver方便及多。我也是这样做了一个发布服务器。
H5ai 怎么复制直链啊,作者的 demo 里面右键图片也是一个 preview 的 URL。
额,直接右键复制链接就行了啊(/ω\)
学到一手,等回家试试。
(⑅ōᴗō)۶nice