Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revision | |||
selfhost:fileserver [2025/03/19 14:08] – [H) File Server] willy | selfhost:fileserver [2025/03/19 15:09] (current) – willy | ||
---|---|---|---|
Line 1: | Line 1: | ||
====== H) File Server ====== | ====== H) File Server ====== | ||
- | |||
- | **Note:** i recently switched from what has been described below to a much simpler approach using [[services: | ||
- | |||
- | --- | ||
I will not discuss how to share your files on the home network using __legacy__ tools like [[https:// | I will not discuss how to share your files on the home network using __legacy__ tools like [[https:// | ||
Line 13: | Line 9: | ||
You will be using your SSO authentication, | You will be using your SSO authentication, | ||
+ | In the past i used a more complex solution leveraging more tools. That obsolete solution has been moved, for reference, [[selfhost: | ||
===== Overall Architecture and Shares ===== | ===== Overall Architecture and Shares ===== | ||
- | This solution leverages | + | This solution leverages |
- | * [[services:cloudcommander|CloudCommander]], full featured file manager | + | |
- | * [[services: | + | |
- | * [[https:// | + | |
- | Note: choosing between FileBrowser or Cloud Commander is a matter of preference. I use both, for different kind of shares. | + | AList itself also support SSO integration, |
- | The NGINX reverse proxy will integrate with your preferred [[selfhost: | + | You can also define as many shared folders as you like, and even connect |
- | I will assume that your shares are under **/ | + | I will assume that your shares are under **/data/shares**, but of course each share can be located anywhere you like. Let's also assume, as an example, that your share is called __/data/ |
Each share folder will have the following structure: | Each share folder will have the following structure: | ||
- | * / | + | * /data/ |
- | * /share/common/db: contains the FileBrowser database, needed for browser access (not needed for CloudCommander) | + | * /data/share/other_share/ |
- | * /share/ | + | * /data/share/another_share/ |
- | * /share/common/data: contains the actual shared files and directories. | + | |
- | This structure is provided as an example to follow, of course you can move the individual folders where you prefer. The only caveat is that, for security reasons, the **db** and **webdav** folder should **not** be inside the **data** folder. | + | Your AList installation |
- | + | ||
- | You will also need to assign two ports for each share, as an example for our //common// share: | + | |
- | * 3002: port for FileBrowser or Cloud Commander | + | |
- | * 10001: port for Apache | + | |
- | + | ||
- | Any other share can start from these port numbers and go up in numbering. | + | |
I choose to assign a dedicated subdomain, **drive.mydomain.com**, | I choose to assign a dedicated subdomain, **drive.mydomain.com**, | ||
+ | * **https:// | ||
* **https:// | * **https:// | ||
+ | * **https:// | ||
* **https:// | * **https:// | ||
- | * **https:// | + | * **https:// |
+ | * **https:// | ||
+ | |||
+ | I think that /webdav is easier to remember than /dav, but AList by default shared WebDAV under /dav, NGINX will be used to map the /webdav path to /dav. | ||
You can add any more folders as separate shares as you like. Due to how WebDAV works, it is mandatory to separate the browser accessible URLs from the WebDAV ones, like i did above. | You can add any more folders as separate shares as you like. Due to how WebDAV works, it is mandatory to separate the browser accessible URLs from the WebDAV ones, like i did above. | ||
Line 51: | Line 43: | ||
=== Permissions and Users === | === Permissions and Users === | ||
- | (Note: you should | + | (Note: you should |
- | Each share will be accessible by different users, so this needs to be planned a bit. For user-specific shares, not much needs to be done except run FileBrowser/ | + | I assume you have already created |
- | For common shares instead, it's important | + | You need to set the //umask// for the fileserver user to **0002** so that any new files created by it will be writable by the users: |
- | + | ||
- | You need to assign | + | |
<code bash> | <code bash> | ||
- | useradd -d /shares/common -m fileserver -g users | + | mkdir /data/shares |
- | </code> | + | mkdir /data/shares/common |
- | + | chown fileserver:users /data/shares | |
- | You need to set the //umask// for the fileserver | + | |
- | <code bash> | + | |
- | su - fileserver | + | |
- | echo "umask 0002" >> ~/.bashrc | + | |
- | source ~/.bashrc | + | |
- | mkdir db | + | |
- | mkdir webdav | + | |
- | mkdir data | + | |
</ | </ | ||
Line 75: | Line 57: | ||
===== Fileserver access via Browser ===== | ===== Fileserver access via Browser ===== | ||
- | Both [[services: | + | Nothing extra needs to be done except install AList, |
- | + | ||
- | You can find installation instruction for both tools in the links above. Install both or the one you prefer, i will assume you have installed your pick on your system already by following my guides above. | + | |
- | + | ||
- | You will need to run **one** instance of the tool you choose for //each share//, so you will to allocate one specific port for each share. I will describe how to run it for the **common** share, so the tool will run as the **fileserver** user that you created above. | + | |
- | + | ||
- | If you choose FileBrowser: | + | |
- | So, create the specific **/ | + | |
- | <file - filebrowser.common> | + | |
- | BASE_URL="/ | + | |
- | DATABASE="/ | + | |
- | DESCRIPTION=" | + | |
- | FOLDER="/ | + | |
- | GROUP=" | + | |
- | PORT=3002 | + | |
- | USER=" | + | |
- | </ | + | |
- | + | ||
- | If you choose Cloud Commander: | + | |
- | So, create the specific **/ | + | |
- | <file - cloudcmd.common> | + | |
- | BASE_URL="/ | + | |
- | DESCRIPTION=" | + | |
- | FOLDER="/ | + | |
- | GROUP=" | + | |
- | PORT=3002 | + | |
- | USER=" | + | |
- | </ | + | |
- | + | ||
- | Create the **init.d** symlink too, and start it. Of course, choose a free port (3002). | + | |
Line 111: | Line 64: | ||
__NOTE:__ using HTTP will cause a 301 redirect to HTTPS, and WebDAV clients will fail. So use HTTPS URL in webdav clients and not HTTP. | __NOTE:__ using HTTP will cause a 301 redirect to HTTPS, and WebDAV clients will fail. So use HTTPS URL in webdav clients and not HTTP. | ||
- | While there are a few WebDAV servers like [[https:// | + | The only chnage |
- | + | <code> | |
- | The idea here is to run a dedicated copy of Apache as user // | + | |
- | <code bash> | + | proxy_pass http:// |
- | emerge apache | + | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; |
- | </ | + | proxy_set_header X-Forwarded-Proto $scheme; |
- | WebDAV | + | proxy_set_header Host $http_host; |
- | + | proxy_set_header X-Real-IP $remote_addr; | |
- | You will **not** be running Apache as system service, because that will mess with our user permission approach. I have prepared | + | proxy_set_header Range $http_range; |
- | <file - webdav> | + | proxy_set_header If-Range $http_if_range; |
- | # | + | proxy_redirect off; |
- | # Copyright 2024 Willy Garidol | + | client_max_body_size 20000m; |
- | # Distributed under the terms of the GNU General Public License v3 | + | |
- | + | ||
- | depend() { | + | |
- | | + | |
- | } | + | |
- | + | ||
- | # Name of the share | + | |
- | WD_SHARE_NAME=" | + | |
- | # Where is the original data | + | |
- | WD_DATA_FOLDER=" | + | |
- | # Where WebDAV temporary stuff will be located | + | |
- | WD_TEMP_FOLDER=" | + | |
- | WD_ROOT_FOLDER=" | + | |
- | WD_MOUNT_FOLDER=" | + | |
- | WD_LOCKS_FOLDER=" | + | |
- | + | ||
- | WD_TIMEOUT=${TIMEOUT:-5} | + | |
- | WD_LOG_PATH=" | + | |
- | WD_SLOT=" | + | |
- | WD_USER=${USER: | + | |
- | WD_GROUP=${GROUP: | + | |
- | + | ||
- | description=${DESCRIPTION: | + | |
- | pidfile="/ | + | |
- | apache_args=( | + | |
- | -c " | + | |
- | -c " | + | |
- | -c " | + | |
- | -c " | + | |
- | -c " | + | |
- | -c "User ${WD_USER}" | + | |
- | -c "Group ${WD_GROUP}" | + | |
- | -c " | + | |
- | -c " | + | |
- | -c " | + | |
- | -c " | + | |
- | -c " | + | |
- | -c " | + | |
- | -c " | + | |
- | -c "< | + | |
- | -c " DAV On" | + | |
- | -c " AllowOverride All" | + | |
- | -c " Options -Indexes +FollowSymlinks -ExecCGI -Includes" | + | |
- | -c " Require all granted" | + | |
- | -c "</Directory>" | + | |
- | -c " | + | |
- | ) | + | |
- | + | ||
- | start_pre() { | + | |
- | # script must be run with " | + | |
- | if [ "${WD_SLOT}" | + | |
- | | + | |
- | ebegin " | + | |
- | eend 255 | + | |
- | return 255 | + | |
- | fi | + | |
- | # Data folder must exist: | + | |
- | if [ -z ${WD_DATA_FOLDER} | + | |
- | | + | |
- | ebegin " | + | |
- | eend 255 | + | |
- | return 255 | + | |
- | fi | + | |
- | # Create log paths | + | |
- | test -e "${WD_LOG_PATH}" | + | |
- | | + | |
- | ebegin " | + | |
- | mkdir " | + | |
- | } && chown -R ${WD_USER} " | + | |
- | # Create all temporary paths: | + | |
- | for path in ${WD_TEMP_FOLDER} ${WD_ROOT_FOLDER} ${WD_MOUNT_FOLDER} ${WD_LOCKS_FOLDER} | + | |
- | do | + | |
- | test -e ${path} || { | + | |
- | | + | |
- | mkdir -p ${path} | + | |
- | chown ${WD_USER}: | + | |
- | } | + | |
- | done | + | |
- | test -z " | + | |
- | ebegin " | + | |
- | mount -o bind ${WD_DATA_FOLDER} ${WD_MOUNT_FOLDER} | + | |
} | } | ||
- | eend 0 | ||
- | } | ||
- | |||
- | start() { | ||
- | start-stop-daemon -w ${WD_TIMEOUT} --start --pidfile " | ||
- | / | ||
- | eend $? | ||
- | } | ||
- | |||
- | stop_post() { | ||
- | test -n " | ||
- | ebegin " | ||
- | umount ${WD_MOUNT_FOLDER} | ||
- | } | ||
- | eend 0 | ||
- | } | ||
- | </ | ||
- | and make it executable: | ||
- | <code bash> | ||
- | chmod +x / | ||
</ | </ | ||
- | + | which will remap /webdav to /dav | |
- | === Create apache configuration files for each share === | + | |
- | + | ||
- | By using the above init script, defining a new share means to create a share symlink of that script and the associated config file. | + | |
- | + | ||
- | For our __common__ example share, create the following **/ | + | |
- | <file - webdav.common> | + | |
- | DESCRIPTION=" | + | |
- | # this must point to where your data to be shared is located | + | |
- | DATA_FOLDER="/ | + | |
- | # this will contain temporary webdav stuff, will be created if missing | + | |
- | TEMP_FOLDER="/ | + | |
- | # this refers to the URL " | + | |
- | SHARE_NAME=" | + | |
- | GROUP=" | + | |
- | USER=" | + | |
- | PORT=10001 | + | |
- | </ | + | |
- | Note the port, it needs to be unique and available. | + | |
- | + | ||
- | Create the symlink: | + | |
- | <code bash> | + | |
- | ln -s / | + | |
- | </ | + | |
- | + | ||
- | + | ||
- | === Prepare apache folders for each share === | + | |
- | + | ||
- | The above mentioned init script will create all the needed sub-folders for you, but here is a recap: | + | |
- | * / | + | |
- | * / | + | |
- | + | ||
- | Those wll be created by the init script above if missing. They will not be deleted in any case, if existing. | + | |
- | + | ||
- | + | ||
- | === Messing with the WebDAV root folder === | + | |
- | + | ||
- | Now, the fun part is that you want to protect this behind the NGINX reverse proxy (for HTTPS and authorization reasons) and it seems that WebDAV does **not** play well with URL redirection and similar funny things. In other words, the base url you will be using on the reverse proxy **must match** the url in the Apache. You **cannot use** rewrite directives or Alias stuff. | + | |
- | + | ||
- | Since you will be exposing the browser-based access as **https:// | + | |
- | + | ||
- | Since symbolic links cannot be used by WebDAV (could it be //that// simple?), the only viable option is **mount -o bind**. This is taken care automatically in the above init script. | + | |
- | + | ||
- | + | ||
- | === Startup Apache for the share (and autostart) === | + | |
- | + | ||
- | Since you have already created the share specific startup script symlink and the associated config file, all you need to do is add it to the default runlevel and start it: | + | |
- | <code bash> | + | |
- | rc-update add webdav.common default | + | |
- | / | + | |
- | </ | + | |
- | + | ||
- | ===== Reverse Proxy and wrap-up ===== | + | |
- | + | ||
- | Everything is protected behind the [[selfhost: | + | |
- | <file - drive.conf> | + | |
- | server { | + | |
- | server_name drive.mydomain.com; | + | |
- | listen 443 ssl; | + | |
- | listen 8443 ssl; | + | |
- | http2 on; | + | |
- | + | ||
- | access_log / | + | |
- | error_log / | + | |
- | + | ||
- | # WebDAV requires basic auth, while normal auth can be used with FileBrowser | + | |
- | include " | + | |
- | include " | + | |
- | + | ||
- | location / { | + | |
- | include " | + | |
- | include " | + | |
- | root / | + | |
- | } | + | |
- | + | ||
- | location = /common { | + | |
- | | + | |
- | } | + | |
- | + | ||
- | location /common/ { | + | |
- | include " | + | |
- | include " | + | |
- | client_max_body_size 512M; | + | |
- | proxy_pass http:// | + | |
- | proxy_set_header Connection $http_connection; | + | |
- | proxy_set_header Connection ' | + | |
- | proxy_cache_bypass $http_upgrade; | + | |
- | } | + | |
- | + | ||
- | | + | |
- | include " | + | |
- | include " | + | |
- | + | ||
- | # https:// | + | |
- | # https:// | + | |
- | set $dest $http_destination; | + | |
- | if ($http_destination ~ " | + | |
- | set $dest http:// | + | |
- | } | + | |
- | + | ||
- | # Warning: adding / at the end of the proxy_pass will break WebDAV! | + | |
- | proxy_pass http:// | + | |
- | proxy_buffering off; | + | |
- | gzip off; | + | |
- | proxy_pass_request_headers on; | + | |
- | | + | |
- | } | + | |
- | client_max_body_size 100M; | + | |
- | } | + | |
- | </ | + | |
- | + | ||
- | The reverse proxy configuration doesn' | + | |
- | + | ||
- | This example also shows how i have integrated [[selfhost: | + | |
- | + | ||
- | Refer to the [[selfhost: | + | |
- | + | ||
- | ==== Main Directory Page ==== | + | |
- | + | ||
- | As you can spot from the above NGINX configuration, | + | |
- | + | ||
- | For this i am using my [[services: | + | |
- | <file - site.json> | + | |
- | { | + | |
- | " | + | |
- | " | + | |
- | " | + | |
- | " | + | |
- | }, | + | |
- | " | + | |
- | { | + | |
- | " | + | |
- | " | + | |
- | " | + | |
- | [ { | + | |
- | " | + | |
- | " | + | |
- | " | + | |
- | " | + | |
- | " | + | |
- | } ] | + | |
- | } | + | |
- | ], | + | |
- | " | + | |
- | " | + | |
- | " | + | |
- | " | + | |
- | " | + | |
- | } | + | |
- | } | + | |
- | </ | + | |
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | ===== Experimental stuff ===== | + | |
- | + | ||
- | Just some additional experiments i did, for future references. | + | |
- | + | ||
- | === Nephele-Serve === | + | |
- | Replacing WebDAV with Nephele-Serve (which will support also CardDAV/ | + | |
- | + | ||
- | https:// | + | |
- | https:// | + | |
- | + | ||
- | NPM needs to be enabled for the fileserver user: | + | |
- | < | + | |
- | NPM_PACKAGES=" | + | |
- | mkdir -p " | + | |
- | echo " | + | |
- | </ | + | |
- | + | ||
- | And in **~/ | + | |
- | + | ||
- | < | + | |
- | # NPM packages in homedir | + | |
- | NPM_PACKAGES=" | + | |
- | # Tell our environment about user-installed node tools | + | |
- | PATH=" | + | |
- | # Unset manpath so we can inherit from / | + | |
- | unset MANPATH # delete if you already modified MANPATH elsewhere in your configuration | + | |
- | MANPATH=" | + | |
- | # Tell Node about these packages | + | |
- | NODE_PATH=" | + | |
- | </ | + | |
- | + | ||
- | Install: | + | |
- | <code bash> | + | |
- | source ~/ | + | |
- | npm install -g nephele-serve | + | |
- | </ | + | |
- | + | ||
- | Advantages: it's a simple server that supports pam_auth. In the future, it might **also** replace [[services: | + | |
- | + | ||
- | Disadvantages: | + | |
- | + | ||
- | === sFtpGO WebDAV / web browser === | + | |
- | + | ||
- | Interesting [[https:// | + | |
- | + | ||
- | You need to start it once then edit **sftpgo.json**: | + | |
- | < | + | |
- | " | + | |
- | " | + | |
- | " | + | |
- | { | + | |
- | " | + | |
- | " | + | |
- | " | + | |
- | " | + | |
- | " | + | |
- | " | + | |
- | " | + | |
- | " | + | |
- | " | + | |
- | " | + | |
- | " | + | |
- | " | + | |
- | " | + | |
- | } | + | |
- | ], | + | |
- | </ | + | |
- | Advnatages: easier than Apache to setup, support base_url | + | |
- | + | ||
- | Disadvantages: | + | |
- | + | ||
- | === KaraDAV / PicoDAV === | + | |
- | + | ||
- | [[https:// | + | |
- | + | ||
- | [[https:// | + | |
- | + | ||
- | Unfortunately, | + | |