NextCloud + H5ai 打造你的专属文件分享存储服务

0.写在前面

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

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

1.云盘选型

自建云盘首先想到的就是OwnCloud,NextCloud,Seafile这几个方案。网上都说NextCloud是OwnCloud的继任者(OwnCloud元老离开并创立NextCloud项目),我也没深入研究,就不多说了。但是前两年使用OwnCloud的蛋疼经历至今我仍感觉历历在目,所以就OwnCloud好感度-1。

方案
\
项目
OwnCloudNextCloudSeafile
环境依赖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配置

  1. 自建云盘系列——NextCloud (OwnCloud继任者) – Senraの小窝
  2. Install – NextCloud

安装完成后,请记住您的用户名,并开始配置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天的时间,下面说说我遇到的问题。

  1. NextCloud的data目录的权限一定要为 0770,否则打开NextCloud时会报 “RouteNotFoundException”
  2. Nginx与php-fpm的用户名与用户组应保持一致,否则H5ai会提示403 Forbidden。这是因为NextCloud对data中文件的访问不是直接走Nginx的,而是交由php-fpm处理的,而H5ai是直接交由Nginx处理的。如果php-fpm与Nginx的用户或用户组不一致时,加上上文提到NextCloud的data目录的权限一定要为 0770 ,Nginx就对data目录没有访问权限,所以就会返回403 Forbidden的错误。
  3. Safari浏览器不支持MKV格式的视频或H.265编码的视频。

4.写在最后

我对Nginx了解还不是很多,所以上述的Nginx伪静态设置如果有什么更好的方法或者存在什么漏洞,欢迎在留言里指出!(*^▽^*)

2 条评论

昵称

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据

  1. Mai1me

    学到一手,等回家试试。

    1. Y2Nk4

      (⑅ōᴗō)۶nice