Nextcloud Sync Client for Docker
I’ve found the ‘native’ macOS Nextcloud client to be a bit flakey. It’s all Qt and C++ and times out all the time.
I’m trying to replace Dropbox on my Mac, as they get up to all sorts of scummy behaviour, but it’s a little harder than expected.
I mentioned in an earlier post that I sync my photos to my NAS, then sync to Nextcloud via their command line client, running in a Docker container. I run all my containers on my Synology NAS using their Docker package:
In the last screenshot there you can see my image: stoutyhk/nextcloud-client. It’s based on the image from juanitomint, with some small tweaks to add functionality to exclude certain folders and to set folders for selective sync. I also slightly tweaked how the arguments to the client are constructed and exposed the media
and config
folders.
The config folder can contain files named:
exclude
- this contains files/folders/patterns that you don’t want to syncunsyncedfolders
- contains the list of un-synced remote folders (selective sync)
For example, I want to exclude syncing the Synology-generated metadata @eaDir directories to my server:
So I have a config directory containing an exclude
file:
Containing:
Additionally, on my server there are folders that I do not want to sync down to my NAS. So those folders go in the unsyncedfolders
file:
So you download the image, launch and set the volumes and environment variables, and start it up:
From the command line this would be something like:
docker run -it --rm \
-v some_named_volume:/media/nextcloud \
-v some_config_volume:/config \
-e NC_USER=$username -e NC_PASS=$password \
-e NC_URL=$server_url\
stoutyhk/nextcloud-client
The Dockerfile CMD is run.sh, a script that parses the arguments to construct the nextcloudcmd command. For my setup it’s this:
"/bin/su -s /bin/ash $USER -c 'nextcloudcmd --exclude /config/exclude \
--unsyncedfolders /config/unsyncedfolders --max-sync-retries 6 \
--non-interactive -u $NC_USER -p $NC_PASS /media/nextcloud $NC_URL'"
This simply runs in a while true loop, sleeping for 500s after it syncs and then checking if it needs to sync again after 500s.
It’s very stable, hasn’t crashed or timed out yet. I highly recommend this method vs the native macOS client.
Going full No Dropbox would mean syncing further folders and mounting them on my Mac. That’s up next.
BTW, building and tweaking this is very simple. The Dockerfile describes what to do:
Build image based on Alpine (a tiny, 2.7MB, version of Linux):
FROM alpine:latest
Set some ARGS and ENVS:
ARG USER=ncsync
ARG GROUP=users
ARG USER_UID=1000
ARG USER_GID=100
ENV USER=$USER \
GROUP=$GROUP \
USER_UID=$USER_UID \
USER_GID=$USER_GID \
NC_USER=username \
NC_PASS=password \
NC_INTERVAL=500 \
NC_URL="" \
NC_TRUST_CERT=false \
NC_SILENT=false \
NC_EXIT=false \
NC_HIDDEN=false \
NC_MAX_SYNC_RETRIES=3
Create user/group:
RUN adduser -G $GROUP -D -u $USER_UID $USER
Update repositories and install nextcloud-client:
RUN apk update && apk add nextcloud-client && rm -rf /etc/apk/cache
Add run script and expose volumes:
ADD run.sh /usr/bin/run.sh
VOLUME [ "/media/nextcloud" ]
VOLUME [ "/config" ]
Finally, execute the command:
CMD /usr/bin/run.sh
The build command to build the image is:
docker build \
--build-arg VCS_REF=$(git rev-parse --short HEAD) \
--build-arg BUILD_DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ") \
-t stoutyhk/nextcloud-client . | tee build.log
docker images stoutyhk/nextcloud-client
You can see my current image is the one from DockerHub:
The build output:
root@dusky2: /volume1/homes/james/src/nextcloud-client-docker on master[!?]
$ ./build.sh
Sending build context to Docker daemon 28.67kB
Step 1/19 : FROM alpine:latest
---> a187dde48cd2
Step 2/19 : LABEL maintainer="stoutyhk" version="0.1" description="nextcloud sync client"
---> Running in d7bcd965c0d4
Removing intermediate container d7bcd965c0d4
---> b6a1c94582c9
Step 3/19 : LABEL based-on="https://github.com/juanitomint/nextcloud-client-docker"
---> Running in fba05915652c
Removing intermediate container fba05915652c
---> 92e4f3b6aba1
Step 4/19 : LABEL repo="https://github.com/jamesstout/nextcloud-client-docker"
---> Running in 63258ff88545
Removing intermediate container 63258ff88545
---> 07233dc234c6
Step 5/19 : ARG VCS_REF
---> Running in f03e352100f4
Removing intermediate container f03e352100f4
---> 172784412e92
Step 6/19 : ARG BUILD_DATE
---> Running in 80600d7575e4
Removing intermediate container 80600d7575e4
---> 77bc2f5d481a
Step 7/19 : LABEL vcs-ref=$VCS_REF
---> Running in c58cdd8b58f6
Removing intermediate container c58cdd8b58f6
---> 2e598c72729a
Step 8/19 : LABEL build-date=$BUILD_DATE
---> Running in d51c564b1354
Removing intermediate container d51c564b1354
---> 2cf77c7ccd0f
Step 9/19 : ARG USER=ncsync
---> Running in 10c452b72d23
Removing intermediate container 10c452b72d23
---> 62d6402dfe64
Step 10/19 : ARG GROUP=users
---> Running in 2c7c84cca017
Removing intermediate container 2c7c84cca017
---> 32af7f7e31a6
Step 11/19 : ARG USER_UID=1000
---> Running in a76b14779d6e
Removing intermediate container a76b14779d6e
---> d16b1dc7fda7
Step 12/19 : ARG USER_GID=100
---> Running in 16a3579c0537
Removing intermediate container 16a3579c0537
---> b06b174ac1cb
Step 13/19 : ENV USER=$USER GROUP=$GROUP USER_UID=$USER_UID USER_GID=$USER_GID NC_USER=username NC_PASS=password NC_INTERVAL=500 NC_URL="" NC_TRUST_CERT=false NC_SILENT=false NC_EXIT=false NC_HIDDEN=false NC_MAX_SYNC_RETRIES=3
---> Running in 85c579929ce1
Removing intermediate container 85c579929ce1
---> 82c168659c42
Step 14/19 : RUN adduser -G $GROUP -D -u $USER_UID $USER
---> Running in 84755af084c9
Removing intermediate container 84755af084c9
---> 9888ccca2dcc
Step 15/19 : RUN apk update && apk add nextcloud-client && rm -rf /etc/apk/cache
---> Running in 702eef96b765
fetch http://dl-cdn.alpinelinux.org/alpine/v3.11/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.11/community/x86_64/APKINDEX.tar.gz
v3.11.6-32-g9ddc349524 [http://dl-cdn.alpinelinux.org/alpine/v3.11/main]
v3.11.6-28-g4b76c8208f [http://dl-cdn.alpinelinux.org/alpine/v3.11/community]
OK: 11273 distinct packages available
(1/95) Installing dbus-libs (1.12.16-r2)
(2/95) Installing libgcc (9.2.0-r4)
(3/95) Installing libffi (3.2.1-r6)
-----8<---snip---8<----
(95/95) Installing nextcloud-client (2.6.1-r0)
^@Executing busybox-1.31.1-r9.trigger
OK: 300 MiB in 109 packages
Removing intermediate container 702eef96b765
---> 3147165b6612
Step 16/19 : ADD run.sh /usr/bin/run.sh
---> 11a9c630e797
Step 17/19 : VOLUME [ "/media/nextcloud" ]
---> Running in 69454b15f6b6
Removing intermediate container 69454b15f6b6
---> af98dc485510
Step 18/19 : VOLUME [ "/config" ]
---> Running in 94ac262e01a9
Removing intermediate container 94ac262e01a9
---> b964f6b7c97c
Step 19/19 : CMD /usr/bin/run.sh
---> Running in 942c9ddf5ddd
Removing intermediate container 942c9ddf5ddd
---> aa064981bb5b
Successfully built aa064981bb5b
Successfully tagged stoutyhk/nextcloud-client:latest
real 5m50.592s
user 0m0.096s
sys 0m0.047s
REPOSITORY TAG IMAGE ID CREATED SIZE
stoutyhk/nextcloud-client latest aa064981bb5b 1 second ago 311MB
stoutyhk/nextcloud-client <none> 6ca8291dece4 3 weeks ago 311MB
You can see the latest
tag is now pointing to image aa064981bb5b
. To update, you export the settings, stop the container, docker rm stoutyhk-nextcloud-client
, then import the settings and launch the new image:
Spot of housekeeping:
root@dusky2: /usr/local/bin
$ for image in $(docker images -f "dangling=true" | grep stouty | grep -vE 'IMAGE' | awk '{ print $3 }'); do
docker rmi "$image";
done
Untagged: stoutyhk/nextcloud-client@sha256:024ba23cc5e182aedb3d30df1bc4e31127fe21f94b35aed55804989b8e154a98
Deleted: sha256:6ca8291dece42c3dda0cf2b6601e0ff1180cf854909b5f3474710ca84babaf04
Deleted: sha256:be8054c4d017455ca6b4afd7e00fb7da03e58beae4a3705575aabcff8af23fb9
Deleted: sha256:c9eae4086cf6c94c60590bb909fbffa90f166371d9c13a53a4a988d48747cdcc
Deleted: sha256:688a57e452c154219a34c88e18ec695ef3a15ce4a1d4f73875d56ff40a8a6de6
I have a script that runs weekly to automate pulling of new images:
I then need to do the export, rm, import manually as I haven’t figured out how to automate that with Synology Docker package yet.
Dive is a nice tool for examining Docker images and layers.
You can see what each command in the Dockerfile does to the image. It also gives you an image efficiency estimate:
Image Efficiency
The lower left pane shows basic layer info and an experimental metric that will guess how much wasted space your image contains. This might be from duplicating files across layers, moving files across layers, or not fully removing files. Both a percentage “score” and total wasted file space is provided.
Mine is fairly good:
Total Image size: 311MB
Potential wasted space: 179kB
Image efficiency score: 99 %
Here’s a look at dive
: