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

Pipeline status
Docker image size
Docker pulls
License
Release
Donation
BuyMeACoffee
Build date

Please use flrnnc/seafile-client instead of flowgunso/seafile-client from now on.

This project is switching namespaces. The sources previously in flwgnso-docker/docker-seafile-client are now in flrnnc-oss/docker-seafile-client. The Docker image can still be found at flowgunso/seafile-client but it will be deprecated, the image flrnnc/seafile-client should be used instead.

flowgunso/seafile-client will still be updated until usage is low enough to be archived.

Supported tags

The versions match Seafile versions.

9, 9.0, 9.0.7, 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

The Docker image is built weekly to keep up with security updates.

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

1 Like

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.