haiwen / seafile-docker

A Docker image for Seafile server
Other
544 stars 183 forks source link

Requests for avatars denied with default nginx configuration #228

Closed svengreb closed 8 months ago

svengreb commented 4 years ago

I followed the official guide about how to deploy Seafile with Docker and everything worked fine except avatar images. All requests to the /media/avatars/* route fail with a 403 Permission Denied response. Other requests to sub-routes of /media like e.g. /media/assets/* and /media/fontawesome succeed without problems so CSS and JS files are loaded.

I'm using the recommended configurations for Docker Compose by mounting the /shared path of the seafile service container to my Docker host system. I checked that all paths have the correct filesystem attributes (owner root:root) to be sure that this is not the root cause. I also checked the data structure and layout within the container and noticed that the directory that contains the avatars /opt/seafile/seafile-server-latest/seahub/media/avatars is actually a relative symbolic link (../../../seahub-data/avatars) that resolves to /shared/seafile/seahub-data/avatars. The target path is located within the mounted volume and I verified that the files of my custom avatar images exist and also have the correct filesystem permissions. Strangely enough requests for my custom background image for the login page work totally fine even though the actual directory is a relative symbolic link to /shared/seafile/seahub-data/custom and the target directory is also within the mounted volume.

Analysis Findings

I found a location block in the nginx configuration that is included in the Docker image by default:

https://github.com/haiwen/seafile-docker/blob/873656cd59a426bce0acf27b3b821dad046f486d/image/seafile_7.1/templates/seafile.nginx.conf.template#L85-L87

I wondered why this block is defined at all because there are no other location blocks for other routes like e.g. /api. I removed the whole location block for the /media path to see if this breaks requests to CSS/JS resources, but instead all requests succeeded including the ones for custom avatars.

Can someone from the team explain what the exact purpose of the location /media is? Is this required for the frontend framework (Django)? I also checked the commit history of this code snippet and it looks like it was added for the first time 4 months ago in c75d241e7868de24560855abf1554d9350c4d8dc.

Reproduction Steps

This step-by-step list should make it possible to reproduce the problem:

  1. Prepare a clean Seafile stack, e.g. by using the official Docker Compose file from the documentations.
  2. Run the stack to bootstrap Seafile/SeaHub/CCNet and initialize the database: sudo docker-compose up -d
  3. Log into the SeaHub web UI, open the developer tools of your browser (Firefox / Chrome) and check in the “Network“ tab that requests to /media/avatars/* are failing (403 Permission Denied) even when no custom avatar image has been set yet. Also check that other requests to the /media sub-route (e.g. /media/assets) succeed and CSS/JS files are loaded and applied correctly to the web UI.
  4. Hook into the Docker container (sudo docker exec -it seafile /bin/bash) and remove the location /media block from the /shared/nginx/conf/seafile.nginx.conf file (lines 52 to 54).
  5. Restart the stack (ensures to clear the cache): sudo docker-compose restart
  6. Log into the SeaHub web UI again and verify that requests to /media/avatars/* are now succeeding (200 OK) as well as other CSS/JS requests (/media/assets).

Possible Root Cause Starting Points

I've never really been a fan of nginx and only used and configured it because it was a requirement (job related projects), but I found a “Root inside Location Block“ section in their official “Pitfalls and Common Mistakes“ documentation which looks like it matches the defined block in the SeaHub source code.

svengreb commented 4 years ago

Also to clarify some possible question beforehand:

  1. The SERVICE_URL and FILE_SERVER_ROOT properties are both set to the correct URL and the URL of the avatar request reflect these configurations.
  2. I've added
    USE_X_FORWARDED_HOST = True
    SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

    to my seahub_settings.py file (like mentioned and often marked as solution in some forum threads) to ensure the header is allowed and passed through. I've configured my Traefik router to also allow this header being passed though.

  3. I'm using memcached so there is no /tmp/seahub_cache directory that I could delete, but I always made sure to wipe the memcached container after testing other configurations.
  4. I've always delete the /shared/seafile/conf/__pycache__ directory to make sure there are no cached configuration values when restarting the container.
dimejo commented 2 years ago

@svengreb I just encountered the same issue, and looks like I've found the reason.

nginx is configured to use the directories avatars and custom inside the /opt/seafile/seafile-server-latest/seahub/media directory. But avatars and custom are symlinks and effectively located inside /shared/seafile/seahub-data. Unfortunately nginx (running as www-data user) is not able to access this directory because /shared is set to 750 permissions. chmod o=rx /shared fixes this issue.

@freeplant If you want I can create a PR for this issue but I'm not familiar with the scripts and unsure where to put the fix.

davidrudlstorfer commented 1 year ago

Same problem here