I just set up Seafile 13.0 with a Podman pod and put it behind Traefik 3.5.1 which runs in a separate container. Everything is working fine, I only had to bind gunicorn to 0.0.0.0:8000 instead of 127.0.0.1:8000 and add CSRF_TRUSTED_ORIGINS = [“https://seafile.mydomain.tld”] in seahub_settings.py.
However Django fails to find /media files, in this case while trying to view a PDF file uploaded to my library:
root@seafile:/opt/seafile/logs# cat seahub.log
[2025-09-06 22:13:00] [WARNING] django.request:246 log_response Not Found: /media/js/pdf/web/viewer.js.map
[2025-09-06 22:13:00] [WARNING] django.request:246 log_response Not Found: /media/js/pdf/build/pdf.js.map
[2025-09-06 22:13:24] [WARNING] django.request:246 log_response Not Found: /media/js/pdf/build/pdf.js.map
Checking through the developer tools on my browser, it indeed gets a 404 for those files with a HTML page containing (excerpt):
<div class="w-100 h-100 d-flex flex-column align-items-center justify-content-center text-center">
<img src="/media/img/error-tip.png" alt="" width="100" />
<p>Sorry, but the requested page could not be found.</p>
</div>
</div>
When logging into the container /media is empty but /opt/seafile/seafile-server-latest/seahub/media is correctly populated:
root@seafile:/opt/seafile/seafile-server-latest/seahub/media# ls
assets avatars css favicons js sdoc-editor
audio bootstrap custom img office-template seafile-editor
My Traefik dynamic configuration for Seafile is:
http:
services:
seafile:
loadBalancer:
servers:
- url: "http://seafile-server:8000"
seafhttp:
loadBalancer:
servers:
- url: "http://seafile-server:8082"
seafdav:
loadBalancer:
servers:
- url: "http://seafile-server:8080"
middlewares:
seafhttp-strip-prefix:
stripPrefix:
prefixes:
- "/seafhttp"
routers:
seafile:
tls:
options: modern
rule: Host(`seafile.mydomain.tld`)
middlewares:
- default
service: seafile
entrypoints:
- https
seafhttp:
tls:
options: modern
rule: Host(`seafile.mydomain.tld`) && PathPrefix(`/seafhttp`)
middlewares:
- default
- seafhttp-strip-prefix
service: seafhttp
entrypoints:
- https
seafdav:
tls:
options: modern
rule: Host(`seafile.mydomain.tld`) && PathPrefix(`/seafdav`)
middlewares:
- default
service: seafdav
entrypoints:
- https
What may be going wrong?
I’ve been looking into something similar. I think I tracked it down. Like you, I have my reverse proxy talking directly to gunicorn (seahub) on port 8080 (8000 in my case), and seaf-server on another port (8082). I did this because that’s how my old setup worked before being pushed into using docker images.
The new expected way with docker is that you just send everything to the docker container on port 80, where an nginx is listening, and that nginx will then sort out what goes to seahub, and seaf-server (and seafdav if you are doing webdav). The detail I missed when setting this up is that this nginx will also server files directly for /media.
location /media {
root /opt/seafile/seafile-server-latest/seahub;
}
So you can either forward /media to the seafile container’s port 80, or change all the forwarding in your reverse proxy to just send everything to port 80 (except for stuff in other containers, like the optional notification server and the optional sdoc-server), and let it sort it out.
1 Like
Thank you for your reply! First of all there was a typo in my post, I bound gunicorn to port 8000 (not 8080). I edited it to avoid any confusion.
The integrated nginx reverse proxy is convenient, though I’m running rootless Podman so I can’t bind it to port 80. What I’ve done instead is modify its config file /etc/nginx/sites-enabled/seafile.nginx.conf so that it runs on port 8001, and then I just forward it everything that Traefik receives like so:
http:
services:
seafile:
loadBalancer:
servers:
- url: "http://seafile-server:8001"
routers:
seafile:
tls:
options: modern
rule: Host(`seafile.mydomain.tld`)
middlewares:
- default
service: seafile
entrypoints:
- https
It works fine but unfortunately I’m still getting 404s for /media requests. I’ll ask nginx to log accesses and errors to that file and I’ll get back to you.
Funny, I’m also running rootless podman, and I also put it on 8001, but I did it by changing the container config file to forward 8001 from the host to 80 in the container, like this:
ports:
- "8001:80"
- "8000:8000"
- "8082:8082"
I will probably switch to forwarding everything to 8001 in my reverse proxy in the future, but I was trying to make the smallest change possible to fix it because it was the one in production (the test VM is testing upgrading to version 13, which isn’t going well at the moment).
My only guess about your 404 errors is that the reverse proxy might be rewriting requests before passing them on so that the /media part isn’t getting passed on to the container.
Hah, that works too 
Requests to /media are reaching the nginx reverse proxy in the Seafile server container, however it seems that there is an issue with the PDF viewer specifically where a non-existent locale (en-US) is being queried:
[error] 48#48: *8 open() “/opt/seafile/seafile-server-latest/seahub/media/seafile-editor/locales/en-US/seafile-editor.json” failed (2: No such file or directory)
Only the locale en exists, not en-US:
root@seafile:~# ls /opt/seafile/seafile-server-latest/seahub/media/seafile-editor/locales
cs de en es es-AR es-MX fr it ru zh-CN zh_CN
Even after fixing the issue by symlinking the en folder to en-US the viewer keeps looping and never displays the PDF file. I’ve tried on both LibreWolf and Chromium. It works fine on the iOS client but I suspect that it uses another PDF viewer.
I had a look at my browser console and found this:
Unexpected server response. PDF.js v3.8.162 (build: 2c74323e3) Message: Unexpected server response (400) while retrieving PDF "http://seafile.mydomain.tld/seafhttp/repos/caac3501-3f2c-4cd5-9117-fc2d164e96dd/files/test.pdf/?op=download". viewer.js:917:13
_otherError https://seafile.mydomain.tld/media/js/pdf/web/viewer.js:917
_documentError https://seafile.mydomain.tld/media/js/pdf/web/viewer.js:895
open https://seafile.mydomain.tld/media/js/pdf/web/viewer.js:823
And the stack trace is:
stack: "BaseExceptionClosure@https://seafile.mydomain.tld/media/js/pdf/build/pdf.js:441:29
__webpack_modules__<@https://seafile.mydomain.tld/media/js/pdf/build/pdf.js:444:2
__w_pdfjs_require__@https://seafile.mydomain.tld/media/js/pdf/build/pdf.js:16153:41
@https://seafile.mydomain.tld/media/js/pdf/build/pdf.js:16416:32
@https://seafile.mydomain.tld/media/js/pdf/build/pdf.js:16429:3
@https://seafile.mydomain.tld/media/js/pdf/build/pdf.js:16432:12
webpackUniversalModuleDefinition@https://seafile.mydomain.tld/media/js/pdf/build/pdf.js:31:50
@https://seafile.mydomain.tld/media/js/pdf/build/pdf.js:32:3
"
But strangely if I open the link to download the PDF file http://seafile.mydomain.tld/seafhttp/repos/caac3501-3f2c-4cd5-9117-fc2d164e96dd/files/test.pdf/?op=download, it works fine.
EDIT: resolved by using SEAFILE_SERVER_PROTOCOL=https instead of http. Mixed content was being blocked by my browsers. There is still the issue with locales for seafile-editor.json though.
1 Like