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

:warning: Please consider sponsoring this project to help me maintaining and improving it. As of right now, you can support me through Liberay, available in the project badges

Supported tags

9, 9.0, 9.0.4, latest

8, 8.0, 8.0.10

7, 7.0, 7.0.10

Features

  • Synchronize one or more Seafile libraries.
  • Support password protected librairies.
  • Support two factor authentication.
  • Configure upload and download limits.
  • Skip SSL certificates.
  • Set file ownership with user/group ID

Usage

Start a Seafile client

Docker command-line

The following command start the Seafile client with one library:

docker run \ 
    -e SEAF_SERVER_URL="https://seafile.example/" \
    -e SEAF_USERNAME="a_seafile_user" \
    -e SEAF_PASSWORD="SoMePaSSWoRD" \
    -e SEAF_LIBRARY="an-hexadecimal-library-uuid" \
    -v path/to/library:/library \
    -v path/to/client/data:/seafile \
    flowgunso/seafile-client:latest

Docker Compose

The following Docker Compose start a Seafile client with two libraries, with one password protected:

version: "3"

services:

  seafile-client:
    image: flowgunso/seafile-client:latest
    volumes:
      - audio:/library/audio
      - documents:/library/documents
      - client:/seafile
    environment:
      SEAF_SERVER_URL: "https://seafile.example/"
      SEAF_USERNAME: "a_seafile_user"
      SEAF_PASSWORD: "SoMePaSSWoRD"
      SEAF_LIBRARY_AUDIO: "audio-library-uuid"
      SEAF_LIBRARY_AUDIO_PASSWORD: "auDioLiBRaRyPaSSWoRD"
      SEAF_LIBRARY_DOCUMENTS: "documents-library-uuid"

volumes:
  audio:
  documents:
  client:

Librairies

Environment variables allows librairies configuration, as shown in the examples above.

You can configure either a single librairy or multiple librairies.

Single library

To synchronize a single library, use the environment variables SEAF_LIBRARY and SEAF_LIBRARY_PASSWORD. The library will be synchronized in /library.

Multiple librairies

To synchronise multiple librairies, use the same environment variable as above but suffixed with a single identifier word. That word will be used for the library password and it’s synchronization path as well.

Hence, to synchronise a library identified as audio, the environment variables would be SEAF_LIBRARY_AUDIO for the library UUID and SEAF_LIBRARY_AUDIO_PASSWORD for the library password. The library will be then synchronized in /library/audio.

Identifiers allows to add as many libraries as possible. Identifier are single word only.

Environment variables

Environment variable allows you to configure the Seafile client.

SEAF_SERVER_URL

This variable is mandatory.

The Seafile server URL.

SEAF_USERNAME

This variable is mandatory.

The username for the Seafile account.

SEAF_PASSWORD

This variable is mandatory.

The password for the Seafile account.

SEAF_LIBRARY, SEAF_LIBRARY_[IDENTIFIER]

This variable is mandatory.

The UUID of the library, libraries to synchronize.
Replace [IDENTIFIER] with the a unique single word identifier for each library you want to synchronize.

SEAF_LIBRARY_PASSWORD, SEAF_LIBRARY_[IDENTIFIER]_PASSWORD

The password of the library, libraries to synchronize.
Replace [IDENTIFIER] with the a unique single word identifier for each library you want to synchronize corresponding to the SEAF_LIBRARY_[IDENTIFIER].

SEAF_2FA_SECRET

Two factor authentication is supported but your secret key must be provided. That key can be found on your Seafile web interface, only at the 2FA setup, when the QR code is shown. The secret key is embedded in the QR or available as a cookie.

SEAF_UPLOAD_LIMIT, SEAF_DOWNLOAD_LIMIT

Set upload and download speeds limits. Limits are in bytes.

SEAF_SKIP_SSL_CERT

Skip SSL certificates verifications.

Any string is considered true, omit the variable to set to false. Enable this if you have synchronization failures regarding SSL certificates.

UID, GID

Override the UID and GID for user running the Seafile client, hence the volume ownership.

Docker Secrets

All environments variable supports Docker Secrets, as environment variable variant suffixed with _FILE as files.

Full example

version: "3"

services:

  seafile-client:
    image: flowgunso/seafile-client:latest
    volumes:
      - audio:/library/audio
      - documents:/library/documents
      - client:/seafile
    environment:
      SEAF_SERVER_URL: "https://seafile.example/"
      SEAF_USERNAME: "a_seafile_user"
      SEAF_PASSWORD: "SoMePaSSWoRD"
      SEAF_LIBRARY_AUDIO: "audio-library-uuid"
      SEAF_LIBRARY_AUDIO_PASSWORD: "auDioLiBRaRyPaSSWoRD"
      SEAF_LIBRARY_DOCUMENTS: "documents-library-uuid"
      SEAF_2FA_SECRET: "JBSWY3DPEHPK3PXPIXDAUMXEDOXIUCDXWC32CS"
      SEAF_UPLOAD_LIMIT: "1000000"
      SEAF_DOWNLOAD_LIMIT: "1000000"
      SEAF_SKIP_SSL_CERT: "true"
      UID: "1000"
      GID: "1000"

volumes:
  audio:
  documents:
  client:

Troubleshooting

Changelog

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog,
and this project adheres to Semantic Versioning.

3.0.0 - 2024/03/16

Added

  • Support for multiple libraries synchronization (#44, #43, #41)
  • Support for Docker Secrets (#25)
  • Support for Seafile client’s version through Docker tags (#9)
  • Build documentation with Jinja2 templates (#42)
  • Manage the project with a Makefile (#38)
  • Mock Seafile server for testings (#6)

Changed

  • Revised project layout and workflow (#38, #39)

Fixed

  • Fixed the Docker Hub description publish through their API (#10)
  • Add ca-certificates and gnupg to support more HTTP certificates (#24)

2.2.0 - 2022/08/26

  • Update from Debian Buster to Debian Bullseye (!7)
  • Improved Seafile apt source installation (!7)

2.1.1 - 2020/03/10

  • Prevent re-initialization and re-synchronization of the container if it’s life cycle change but is not deleted (#14)

2.1.0 - 2020/01/30

  • Replace previous Bash script that parse seaf-cli status with a Python script that use pysearpc to run checks (#13)
  • Implement a workaround to probable issue, waiting for the issue to appear (#14)

2.0.3 - 2020/01/14

2.0.2 - 2020/01/14

  • Propagate the CI_COMMIT_TAG and CI_PROJECT_URL environment variables into the Dockerfile as the docs states (#5)

2.0.1 - 2020/01/14

  • Update chown path to library, comment chown to an obsolete healthcheck.sh (#11)
  • Pass $CI_PROJECT_URL to the Dockerfile as a build argument (#5)

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

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

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 #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

Hey @flow.gunso, thanks for the project - this really helps with my truenas / seafile setup.

I just wanted to say (if you are still working on this project), that i am also interested in the option to sync multiple libraries from one container. Currently i am using ~10 containers to achieve that, which is probably not the most efficient solution.

Cheers

I think at that point you’d be better off using seaf-cli inside the container to configure the libraries the usual way. After that just run seaf-daemon without the --daemon flag and point it to all the config directories.

The code around this project seems to be heavily biased towards using a single library.