Daily Sync is a lightweight solution for syncing files to various targets. It currently supports syncing to a WebDAV server, an FTP server, or another directory on the host. It was originally developed for use on NAS systems that lack built-in WebDAV sync capabilities or encryption options. It supports optional encryption using password-protected zip files (AES-256) and is designed to run as a Docker container with a configurable cron schedule.
- Sync files to a WebDAV server, FTP server, or a local directory.
- Optional encryption using password-protected zip files.
- Configurable cron schedule for automated syncing.
- Debug mode for manual testing.
This Docker image is available on Docker Hub under the tag ghcr.io/tsafs/daily-sync:latest
. You can pull it directly using:
docker pull ghcr.io/tsafs/daily-sync:latest
- Docker installed on your system.
- A WebDAV server with valid credentials.
To build the Docker image locally, run:
docker build -t daily-sync .
Run the container in production mode to sync to WebDAV:
docker run -d \
--name daily-sync-webdav \
-v /path/to/your/data:/data:ro \
-e SYNC_MODE="webdav" \
-e WEBDAV_URL="https://<webdav-host>/remote.php/dav/files/<username>/<folder>" \
-e WEBDAV_USERNAME="<username>" \
-e WEBDAV_PASSWORD="<password>" \
-e WEBDAV_TARGET_DIR="<target-directory>" \
-e USE_ENCRYPTION=true \
-e ENCRYPTION_PASSWORD="<password-for-encryption>" \
-e CRON_TIME="<time>" \
-e CRON_DAYS="<days>" \
-e TIMEZONE="Europe/Berlin" \
ghcr.io/tsafs/daily-sync:latest
Run the container in production mode to sync to FTP:
docker run -d \
--name daily-sync-ftp \
-v /path/to/your/data:/data:ro \
-e SYNC_MODE="ftp" \
-e FTP_HOST="<ftp-host>" \
-e FTP_USER="<username>" \
-e FTP_PASSWORD="<password>" \
-e FTP_TARGET_DIR="<target-directory>" \
-e USE_ENCRYPTION=true \
-e ENCRYPTION_PASSWORD="<password-for-encryption>" \
-e CRON_TIME="<time>" \
-e CRON_DAYS="<days>" \
-e TIMEZONE="Europe/Berlin" \
ghcr.io/tsafs/daily-sync:latest
Run the container in production mode to sync to another directory on the host:
docker run -d \
--name daily-sync-dir \
-v /path/to/your/data:/data:ro \
-v /path/to/target/directory:/target \
-e SYNC_MODE="directory" \
-e USE_ENCRYPTION=true \
-e ENCRYPTION_PASSWORD="<password-for-encryption>" \
-e CRON_TIME="<time>" \
-e CRON_DAYS="<days>" \
-e TIMEZONE="Europe/Berlin" \
ghcr.io/tsafs/daily-sync:latest
Note: Ensure the target directory (/path/to/target/directory
on the host) exists. The ownership of the synced file will automatically match the ownership of the /path/to/target/directory
on the host.
Run the container in debug mode to test the sync process manually. This will essentially skip using cron entirely.
docker run --rm \
-v ./test_data:/data:ro \
-e SYNC_MODE="webdav" \
... \
-e DEBUG=true \
ghcr.io/tsafs/daily-sync:latests
version: '3.8'
services:
daily-sync-webdav:
image: ghcr.io/tsafs/daily-sync:latest
container_name: daily-sync-webdav
volumes:
- /path/to/your/data:/data:ro
- /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro
environment:
SYNC_MODE: "webdav"
WEBDAV_URL: "https://<webdav-host>/remote.php/dav/files/<username>"
WEBDAV_USERNAME: "<username>"
WEBDAV_PASSWORD: "<password>"
WEBDAV_TARGET_DIR: "<target-directory>"
USE_ENCRYPTION: "true"
ENCRYPTION_PASSWORD: "<password-for-encryption>"
CRON_TIME: "<time>"
CRON_DAYS: "<days>"
version: '3.8'
services:
daily-sync-ftp:
image: ghcr.io/tsafs/daily-sync:latest
container_name: daily-sync-ftp
volumes:
- /path/to/your/data:/data:ro
- /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro
environment:
SYNC_MODE: "ftp"
FTP_HOST: "<ftp-host>"
FTP_USER: "<username>"
FTP_PASSWORD: "<password>"
FTP_TARGET_DIR: "<target-directory>"
USE_ENCRYPTION: "true"
ENCRYPTION_PASSWORD: "<password-for-encryption>"
CRON_TIME: "<time>"
CRON_DAYS: "<days>"
version: '3.8'
services:
daily-sync-dir:
image: ghcr.io/tsafs/daily-sync:latest
container_name: daily-sync-dir
volumes:
- /path/to/your/data:/data:ro
- /path/to/target/directory:/target
- /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro
environment:
SYNC_MODE: "directory"
USE_ENCRYPTION: "true"
ENCRYPTION_PASSWORD: "<password-for-encryption>"
CRON_TIME: "<time>"
CRON_DAYS: "<days>"
Start the container with:
docker-compose up -d
Variable | Description | Default Value | Required For |
---|---|---|---|
SYNC_MODE |
Sync target mode (webdav , directory , or ftp ). |
webdav |
Always |
WEBDAV_URL |
URL of the WebDAV server. | None | webdav |
WEBDAV_USERNAME |
Username for the WebDAV server. | None | webdav |
WEBDAV_PASSWORD |
Password for the WebDAV server. | None | webdav |
WEBDAV_TARGET_DIR |
Target directory on the WebDAV server. | /data |
webdav (Optional) |
FTP_HOST |
Hostname or IP address of the FTP server. | None | ftp |
FTP_USER |
Username for the FTP server. | None | ftp |
FTP_PASSWORD |
Password for the FTP server. | None | ftp |
FTP_TARGET_DIR |
Target directory on the FTP server. | / |
ftp (Optional) |
USE_ENCRYPTION |
Whether to encrypt the files before syncing (true or false ). |
true |
Always |
ENCRYPTION_PASSWORD |
Password for encrypting the zip file. Required if USE_ENCRYPTION is true. |
None | If USE_ENCRYPTION=true |
RETAIN_BACKUPS |
Number of recent backups to keep in the target location. Older backups are deleted. | 1 |
Always (Optional) |
CHUNK_SIZE_MB |
Maximum size (in MB) for each part of the multi-volume zip archive for WebDAV or FTP uploads. Must be > 10 MB. Internally, 10 MB is subtracted from this value as a safety margin before creating zip volumes to avoid potential size limit issues. If set to 0 or less than 11, a single archive file will be created. | 0 |
webdav , ftp (Optional) |
CRON_TIME |
Cron schedule time (e.g., 0 2 for 2:00 AM, 30 22 for 22:30). |
0 2 |
Always (Optional) |
CRON_DAYS |
Days for the cron job (e.g., * for every day, 0 for Sunday, 1,3,5 for Monday, Wednesday, and Friday). |
* |
Always (Optional) |
DEBUG |
Enable debug mode to skip cron and run the sync script directly. | false |
Always (Optional) |
TIMEZONE |
Timezone for cron jobs (e.g., Europe/Berlin , UTC ). See IANA Time Zone Database for valid values. |
None | Always (Optional) |
Note: For directory
sync mode, the ownership of the created zip file in the target directory will automatically match the ownership of the mounted target directory itself.
The container supports timezone configuration to ensure cron jobs run at the correct local time, including adjustments for daylight saving time (DST).
If the TIMEZONE
variable is unset and the /etc/localtime
and /etc/timezone
files are not mounted, the container will use the default timezone of the base image. This could lead to unexpected behavior. To avoid this, you should either use the host's timezone or set the TIMEZONE
variable explicitly.
To use the host's timezone, you can mount the /etc/localtime
and /etc/timezone
files into the container. This is supported on Linux systems where these files are available. For example:
docker run -d \
--name webdav-sync \
-v /path/to/your/data:/data:ro \
-v /etc/localtime:/etc/localtime:ro \
-v /etc/timezone:/etc/timezone:ro \
...
ghcr.io/tsafs/daily-sync:latest
This approach works on most Linux distributions that use /etc/localtime
and /etc/timezone
for timezone configuration. Note that this method is not supported on systems like macOS or Windows, as they do not use these files for timezone management.
If you explicitly set the TIMEZONE
variable, this ensures that the container uses the specified timezone, regardless of whether the timezone files are mounted. For example:
docker run -d \
--name webdav-sync \
-v /path/to/your/data:/data:ro \
...
-e TIMEZONE="Europe/Berlin" \
ghcr.io/tsafs/daily-sync:latest
Setting the TIMEZONE
variable to a UTC-based value (e.g., UTC
) ensures that the container operates without being affected by daylight saving time (DST) changes, providing consistent scheduling behavior.
I welcome contributions to the Daily Sync project! To contribute, please follow these steps:
- Fork the Repository: Create a fork of this repository on GitHub.
- Create a Branch: Create a new branch for your feature or bug fix. Use a descriptive name for the branch (e.g.,
feature/add-logging
orbugfix/fix-sync-issue
). - Make Changes: Implement your changes in the new branch. Ensure your code adheres to the project's coding standards and is well-documented.
- Test Your Changes: Thoroughly test your changes to ensure they work as expected and do not introduce regressions.
- Submit a Pull Request (PR): Open a pull request to the
main
branch of this repository. Provide a clear description of your changes and the problem they solve.
If you encounter a bug or have a feature request, please open an issue on GitHub. Provide as much detail as possible to help me understand and address the issue.
This project uses a custom versioning format stored in the version.txt
file. The version format is:
YYYY-MM-DD-Index
YYYY-MM-DD
: The release date in the format year-month-day.Index
: A numeric index starting at0
for the first release of the day. If multiple releases occur on the same day, increment the index (e.g.,2025-04-13-0
,2025-04-13-1
).
If the first release of the day is on April 13, 2025, the version would be:
2025-04-13-0
If a second release is made on the same day, the version would be:
2025-04-13-1
The version.txt
file is located in the root directory of the project and should be updated with each release.
Copyright (c) 2025, Sebastian Fast All rights reserved.
This source code is licensed under the GPL-style license found in the LICENSE file in the root directory of this source tree.