Docker client to sync files with containers

Hello everyone,

I wanted to use files from my Seafile server within Docker containers.

I started looking for existing image featuring a Seafile client on Docker Hub. There are some, but with issues such as non-existant/vague documentation or improper tagging.

I don’t know if it’s something that people are looking for, but I made one. It’s available at flowgunso/seafile-client in Docker Hub.

Example usage with docker-compose and for the docker cli are provided. Essentially, it runs seaf-cli sync, but you have to pass to the container your Seafile server URL, your credentials and the library ID you want to sync with. Then you can share the path /library as a volume to your containers for your own usages.

Feedback is welcome so I can keep improving it.

Quick informations

flowgunso/seafile-client on Docker Hub, latest stable version: 2.1.1
Contribute and report issues on Gitlab.

Features

  • Synchronize a single Seafile library, available at the path `/library/’.
  • Password protected librairies are supported.
  • Two factor authentication is supported.
  • Upload and download speeds are configurable.
  • SSL certificates are skippable.

Change log

  • Close issue#16: add a templater for Docker Hub and Seafile’s forum topic description

2.2.0 | 2022/08/26

2.1.1 | 2020/03/10

  • Close issue#14: prevent re-initialization and re-synchronization of the container if it’s life cycle change but is not deleted

2.1.0 | 2020/01/30

  • Close issue#13: replace previous Bash script that parse seaf-cli status with a Python script that use pysearpc to run checks
  • Ongoing issue#14: implement a workaround to probable issue, waiting for the issue to appear

2.0.3 | 2020/01/14

2.0.2 | 2020/01/14

  • Ongoing issue#5: propagate the CI_COMMIT_TAG and CI_PROJECT_URL environment variables into the Dockerfile as the docs states.

2.0.1 | 2020/01/14

  • Fix issue#11: update chown path to library, comment chown to an obsolete healthcheck.sh.
  • Ongoing issue#5: pass $CI_PROJECT_URL to the Dockerfile as a build argument.

2.0.0 | 2020/01/06

  • Support 2FA authentication through oathtool using the secret key
  • Support for upload/download limits
  • Support for Seafile library password
  • Allow skipping SSL certificates verifications
  • Drop Bash/supervisord/cron implementations in favor of showing seafile’s log
  • Implement basic integration tests that check expected binairies
  • Improve continuous integration though splitted jobs
  • Revise README
  • Change the volume path from /volume to /library for consistency

1.2.1 | 2019/12/29

  • Fix issue#4:
    • Switch base image from Debian oldoldstable Jessie to Debian stable Buster to fix unmet dependencies of seafile-cli to python-future and python-searpc
    • Replace ; with && as commands separators in the Dockerfile’s RUN to properly report failed commands at CI

1.2.0 | 2019/05/02

  • Replace supervisord with cron for running the front job that keeps the container up. It uses less resources.
  • Improve the infinite-seaf-cli-start.sh into seafile-healthcheck.sh. The Seafile daemon will not be restarted if it’s state are either downloading or committing, which otherwise is problematic.

1.1.2 | 2019/04/18

  • Slim down the Docker image, from 102MB to 67MB, gaining 35MB, reducing size by 34%.

1.1.1 | 2019/04/18

  • Because of the infinite-seaf-cli-start loop, within the container was running many seaf-daemons. Now, the infinite loop stop the current seaf-daemon before starting it again. (see issue#3)

1.1.0 | 2019/04/09

  • The container now actually use the UID/GID provided to it:
    The container entrypoint is run with root, then another entrypoint is run by the container’s user, seafuser, to run the Seafile client.

1.0.6 | 2019/03/25

  • More minor fixes from v1.0.4

1.0.5 | 2019/03/25

  • Minor fixes from v1.0.4

1.0.4 | 2019/03/25

  • Fix the build target detection (@a52559ddb38a64d7fceaa8bf9b8afd7356ccc439)
  • Login to the Docker Hub from within the script, not the gitlab-ci.yml, using (@72bab017c1167b8ab35cef3cc709ff83686eaca4, @f69483354a4cf8afdbea89ef2bb1d9a9b7b2ac10)
  • Require Bash on all Gitlab CI stages (@72bab017c1167b8ab35cef3cc709ff83686eaca4)
  • Add a script to push the README.md into the Docker Hub repository’s full_description (@8cb49cbc8253368701d718c2e38017790c78ceca, @ca6128fb96602da71f3b7a560e834d1b7587abac)

1.0.3 | 2019/03/19

  • Restrict staging pipelines to pushed pipelines
  • Restrict production pipelines to pushed and triggered pipelines
  • Require a build target on triggered production pipelines

1.0.2 | 2019/03/18

  • Fix a minor issue when testing for requested production build.

1.0.1 | 2019/03/18

  • Add failsafe when importing Seafile’s APT-key
  • Restrict production build to latest, majors, minors and revisions version, on-demand.

1.0.0 | 2019/03/15

  • Release to Docker Hub

0.9.2 | 2019/03/15

  • Test release on GitLab, before Docker Hub

Hi flow.gunso

I am not sure if you intended your docker container in use with Docker on OpenMediaVault but its there to use.
I have been trying to get it to work but as I have very little knowledge with Docker I’m unsure if I am implementing it correctly.

Have you gotten it to work with OpenMedaiVault?

One queston I have, is the SEAF_SERVER_URL suppose to have the port number after it eg: http://192.168.x.x:8000 or does the port number go elsewhere?

Thanks for hard work.

I have gotten it to work!!

The seafile client docker in OpenMediaVault works and syncs!!

Woohoo

Well, that’s perfect!

To answer you questions, this docker container is intended to work with others containers, so, yes, you can use it with Docker within OpenMediaVault, although I’ve not tried. But you did, so thank you for that.

About SEAF_SERVER_URL, it is supposed to be the same information you would use in the official Seafile clients. It’s actually used directly with seaf-cli, the Seafile command line interface. so the port number goes along with the address.

Yes once I figured that out I got it to work.
Thanks for the info and putting together the container.

Thank you for the container, it runs seamlessly.

One question though: is my understanding that in order to expose several libraries a new container must be used? Or is there a way to use several libraries with one container?

You’re right, each library require it’s own container.

That being said, it could be implemented, without too much hassle.

Is there a way to use this container with 2FA?
I noticed that ti tries to initialise synchronisation at every start
this probably means that every start would requir new 2FA code
am I correct?

You are correct that every start would require a new 2FA token, if 2FA was supported.
I have no intention of supporting it because it goes against the purpose of two-factor authentications.

While preventing syncs at every start of a container by checking that a library is already synced is possible, starting the container with a token of a 30 seconds lifespan hoping the library syncs before it expire does not make sense. What make sense are application passwords. Most online services that provide 2FA also provide application passwords for that specific use case.

There’s already a topic about that, I encourage you to take part in it:

Hi,
So if I understand correctly, until Seafile supports application passwords
the F2A is semi-usable.
It sort of works ok, for accessing via web interface and maybe even via desktop sync client, but F2A makes no sense for headless sync applications like docker container
am I correct?

Exactly. 2FA is perfectly usable and works great when associated with user operated authentications and IMHO should be more widely used, but it does not fit with headless application and background process.

Quick notice: image builds dating back from october 28th up to a few moments ago were not working anymore due to unmet dependencies of the seafile-cli package. The latest version, 1.2.1 fix that.

Please, pull new images, especially for the tags 1, 1.2 and latest.

Hi!
Thanks for this client.

There is a way to pass the user credential with a file instead plain text?

Thanks!

Yes, you could use Docker secrets in cli as well as in compose. That being said, the current version may not support secrets yet, but I’m not certain. Have you tried that ?

Thanks for your fast response. I’m a little newbie with docker, so I must read a little more to how to use Docker secrets.

But I’ve a problem when I try to run the container:

seafile-client_1  | Initializing Seafile client...
seafile-client_1  | Writen seafile data directory /home/seafuser/.seafile/seafile-data to /home/seafuser/.ccnet/seafile.ini
seafile-client_1  | Starting Seafile client...
seafile-client_1  | New device id created
seafile-client_1  | Starting seafile daemon ...
seafile-client_1  | Started: seafile daemon ...
seafile-client_1  | Synchronizing Seafile library...
seafile-client_1  | Traceback (most recent call last):
seafile-client_1  |   File "/usr/bin/seaf-cli", line 998, in <module>
seafile-client_1  |     main()
seafile-client_1  |   File "/usr/bin/seaf-cli", line 994, in main
seafile-client_1  |     args.func(args)
seafile-client_1  |   File "/usr/bin/seaf-cli", line 658, in seaf_sync
seafile-client_1  |     token = get_token(url, username, password, tfa, conf_dir)
seafile-client_1  |   File "/usr/bin/seaf-cli", line 308, in get_token
seafile-client_1  |     token_json = urlopen("%s/api2/auth-token/" % url, data=data, headers=headers)
seafile-client_1  |   File "/usr/bin/seaf-cli", line 241, in urlopen
seafile-client_1  |     resp = urllib.request.urlopen(req)
seafile-client_1  |   File "/usr/lib/python2.7/dist-packages/future/backports/urllib/request.py", line 171, in urlopen
seafile-client_1  |     return opener.open(url, data, timeout)
seafile-client_1  |   File "/usr/lib/python2.7/dist-packages/future/backports/urllib/request.py", line 500, in open
seafile-client_1  |     response = meth(req, response)
seafile-client_1  |   File "/usr/lib/python2.7/dist-packages/future/backports/urllib/request.py", line 612, in http_response
seafile-client_1  |     'http', request, response, code, msg, hdrs)
seafile-client_1  |   File "/usr/lib/python2.7/dist-packages/future/backports/urllib/request.py", line 538, in error
seafile-client_1  |     return self._call_chain(*args)
seafile-client_1  |   File "/usr/lib/python2.7/dist-packages/future/backports/urllib/request.py", line 466, in _call_chain
seafile-client_1  |     result = func(*args)
seafile-client_1  |   File "/usr/lib/python2.7/dist-packages/future/backports/urllib/request.py", line 620, in http_error_default
seafile-client_1  |     raise HTTPError(req.full_url, code, msg, hdrs, fp)
seafile-client_1  | future.backports.urllib.error.HTTPError: HTTP Error 404: Not Found
seafile-client_1  | Failed to synchronize.
seafileclient_seafile-client_1 exited with code 1

I’m only using the following enviroment variables:

SEAF_SERVER_URL: "https://my.domain"
SEAF_USERNAME: "my@user.com"
SEAF_PASSWORD: "superSecretPassword"
SEAF_LIBRARY_UUID: "libraryHash"

Do you have any clue?

Thanks!!

Your variables seems fine but the client can’t find the server, so look into your container’s networking. Make sure it can reach the server.

I don’t know what’s going on here…
I’m using the simple bridge docker network. Nothing fancy or special. Just default docker network.

Hello
I have this issue with my “seafile host N°2”. With “N°1 seafile host” all is fine, juste the parameters are différents…
Can you help me
Fred
Creating seafile-client_seafile-client_1 … done
Attaching to seafile-client_seafile-client_1
seafile-client_1 | Starting seafile daemon …
seafile-client_1 | Started: seafile daemon …
seafile-client_1 | Traceback (most recent call last):
seafile-client_1 | File “/usr/bin/seaf-cli”, line 1023, in
seafile-client_1 | main()
seafile-client_1 | File “/usr/bin/seaf-cli”, line 1019, in main
seafile-client_1 | args.func(args)
seafile-client_1 | File “/usr/bin/seaf-cli”, line 675, in seaf_sync
seafile-client_1 | token = get_token(url, username, password, tfa, conf_dir)
seafile-client_1 | File “/usr/bin/seaf-cli”, line 301, in get_token
seafile-client_1 | token_json = urlopen("%s/api2/auth-token/" % url, data=data, headers=headers)
seafile-client_1 | File “/usr/bin/seaf-cli”, line 234, in urlopen
seafile-client_1 | resp = urllib.request.urlopen(req)
seafile-client_1 | File “/usr/lib/python3.7/urllib/request.py”, line 222, in urlopen
seafile-client_1 | return opener.open(url, data, timeout)
seafile-client_1 | File “/usr/lib/python3.7/urllib/request.py”, line 531, in open
seafile-client_1 | response = meth(req, response)
seafile-client_1 | File “/usr/lib/python3.7/urllib/request.py”, line 641, in http_response
seafile-client_1 | ‘http’, request, response, code, msg, hdrs)
seafile-client_1 | File “/usr/lib/python3.7/urllib/request.py”, line 569, in error
seafile-client_1 | return self._call_chain(*args)
seafile-client_1 | File “/usr/lib/python3.7/urllib/request.py”, line 503, in _call_chain
seafile-client_1 | result = func(*args)
seafile-client_1 | File “/usr/lib/python3.7/urllib/request.py”, line 649, in http_error_default
seafile-client_1 | raise HTTPError(req.full_url, code, msg, hdrs, fp)
seafile-client_1 | urllib.error.HTTPError: HTTP Error 403: Forbidden