Compare commits

..

20 Commits

Author SHA1 Message Date
fb3bbe212d removed datetime from docker log output
All checks were successful
/ build-docker-image (push) Successful in 50s
2025-01-28 19:56:01 +00:00
e79bfbf384 revision
All checks were successful
/ build-docker-image (push) Successful in 24s
2025-01-20 20:16:51 +00:00
11af5b8729 docker context revision
All checks were successful
/ build-docker-image (push) Successful in 1m21s
2024-09-16 20:30:10 +01:00
54fe3460b6 fix docker file
Some checks failed
/ build-docker-image (push) Failing after 12s
2024-09-16 19:53:11 +01:00
03c4aa8f83 fix CDI 2
Some checks failed
/ build-docker-image (push) Failing after 40s
2024-09-16 19:50:04 +01:00
2afc508157 fix ci
Some checks failed
/ build-docker-image (push) Failing after 10s
2024-09-16 19:48:39 +01:00
4b7d6b8cd4 continous integration
Some checks failed
/ build-docker-image (push) Failing after 12s
2024-09-16 19:45:00 +01:00
bc4b4c322e Update README.md 2024-04-01 15:12:01 +00:00
9d48fc6d2d docker log message revision 2024-03-16 23:57:45 +00:00
174b528899 added docker log 2024-03-16 23:39:58 +00:00
90e90d64a2 fix: message impr 2023-06-10 09:59:24 +01:00
feeaf2e9d5 feat: added INFLUXDB_CLIENT_HOSTNAME to influxdb report 2023-06-10 09:48:02 +01:00
6d6b30d934 fix: script error 2023-06-10 09:31:25 +01:00
a4e05c1f33 fix: encoding problems 2023-06-10 09:11:59 +01:00
94db5c16d7 fix: small fixes 2023-06-10 08:57:16 +01:00
19f857e1fd feat: influxdb reporting
Reviewed-on: #2
2023-06-10 07:34:24 +00:00
9c5f9e8d30 . 2023-06-10 07:57:39 +01:00
734a6b99e0 . 2023-06-10 07:38:17 +01:00
1b8e7fde9b . 2023-06-10 05:02:55 +01:00
f5c52389e6 . 2023-06-10 05:02:31 +01:00
13 changed files with 460 additions and 209 deletions

7
.devcontainer/Dockerfile Normal file
View File

@@ -0,0 +1,7 @@
FROM duplicati/duplicati
RUN apt update && \
apt install -y default-mysql-client && \
rm -rf /var/lib/apt/lists/*
EXPOSE 8200

View File

@@ -0,0 +1,38 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/ubuntu
{
"name": "duplicati_dev-container",
"build": {
// Path is relative to the devcontainer.json file.
"dockerfile": "Dockerfile"
},
"features": {
"ghcr.io/devcontainers/features/git:1": {
"ppa": true,
"version": "latest"
},
"ghcr.io/prulloac/devcontainer-features/gitlint:1": {}
},
"containerEnv": {}
//"features": {
// "ghcr.io/wxw-matt/devcontainer-features/command_runner:0": {},
// "ghcr.io/wxw-matt/devcontainer-features/script_runner:0": {},
// "ghcr.io/devcontainers-extra/features/act:1": {}
// }
// Features to add to the dev container. More info: https://containers.dev/features.
// "features": {},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "uname -a",
// Configure tool-specific properties.
// "customizations": {},
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}

View File

@@ -0,0 +1,31 @@
on:
push:
paths:
- "docker/**"
- ".gitea/**"
- "scripts/**"
jobs:
build-docker-image:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Log in to git.limbosolutions.com docker registry
uses: docker/login-action@v3
with:
registry: git.limbosolutions.com
username: ${{ secrets.GITLIMBO_DOCKER_REGISTRY_USERNAME }}
password: ${{ secrets.GITLIMBO_DOCKER_REGISTRY_PASSWORD }}
- name: Build and push Docker images
id: push
uses: docker/build-push-action@v6
with:
context: ${{gitea.workspace}}
file: ${{gitea.workspace}}/docker/Dockerfile
push: true
tags: git.limbosolutions.com/kb/duplicati:latest

12
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,12 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for more information:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
# https://containers.dev/guide/dependabot
version: 2
updates:
- package-ecosystem: "devcontainers"
directory: "/"
schedule:
interval: weekly

19
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,19 @@
{
"docker.commands.composeUpSubset": [
{
"label": "Compose Up",
"template": "${composeCommand} ${profileList} ${configurationFile} up ${detached} ${build} ${serviceList}"
}
],
"docker.commands.composeUp": [
{
"label": "Compose Up",
"template": "${composeCommand} ${configurationFile} up ${detached} ${build}"
}
],
"docker.contexts.showInStatusBar": true
} // {
// "docker.commands.build": "${containerCommand} build --pull --rm -f \"${dockerfile}\" -t ${tag} . --progress=plain"
// }

237
README.md
View File

@@ -1,91 +1,146 @@
# Duplicati # Duplicati
## Custom Docker Images - [Docker](#docker)
- [Duplicati/mySql Client - image](#duplicatimysql-client---image)
### Duplicati with mySql Client - [Scripts](#scripts)
- [mysql - dump backup](#mysql---dump-backup)
[+ Information](docker/mysqlclient/README.md) - [Influxdb Reporting](#influxdb-reporting)
- [Docker log](#docker-log)
- [Environment Variables](#environment-variables)
## Send Mail - [Exit Codes](#exit-codes)
- [cli](#cli)
```bash - [Send Mail](#send-mail)
#for testing - [Settings](#settings)
duplicati-cli send-mail --send-mail-password="pass" --send-mail-to="target@mail.lan" --send-mail-username="suer@mail.lan" --send-mail-url="smtp://serveraddress:25" - [Send Email](#send-email)
``` - [nginx](#nginx)
## Docker
### Global Settings
### Duplicati/mySql Client - image
```bash
Image contains all scripts
--send-mail-any-operation=true
--send-mail-body=%RESULT% [+ Information](docker/README.md)
--send-mail-level=all
--send-mail-subject=Duplicati %OPERATIONNAME% report for -> %backup-name% ## Scripts
--send-mail-to=destination@mail.lan
--send-http-result-output-format=Duplicati Source: <https://github.com/duplicati/duplicati/blob/master/Duplicati/Library/Modules/Builtin/run-script-example.sh>
--send-mail-url=smtp://serveraddress:25
--send-mail-password=password ### mysql - dump backup
--send-mail-username=user@mail.lan
Duplicati options set `run-script-before-required` to [duplicati-mysql-backup](scripts/duplicati-mysql-backup).
```
## Scripts ```bash
MYSQL_HOST="mysqlserver"
### Transfer To another system MYSQL_USER="msqluser"
1. Copy docker compose and execute on another system MYSQL_PASSWORD="msqlpassord"
2. Check volumes and service started succesfully MYSQL_DATABASE="msqlpassword"
3. Stop all compose services MYSQL_BACKUP_FOLDER="/var/db-dumps"
4. Change volume on duplicati service to user a temporary volume example (duclicati_tmpdata) ```
5. Check if all volumes are writable on duplication service
6. Start only the duplicati service (with temporary volume) on target system ### Influxdb Reporting
7. On source system Stop app services on docker compose except duplicati
8. Execute a full backup ou source system ```bash
9. On target system execute a manual restore to original destination #/etc/default/duplicati-influxdb
10. Stop duplicati INFLUXDB_SERVER=http://influxdb01.lan:8086
11. Change duplicati to use original volume INFLUXDB_BUCKET=bucketname
12. And change volumes on duplicati to RO INFLUXDB_ORG=orgname
13. Start all services INFLUXDB_TOKEN=influxdbname
14. Check everything ok #by default it uses client hostname in measurement field host
#to override uncomment
### Environment Variables #INFLUXDB_CLIENT_HOSTNAME=xxx
```
_Source: https://github.com/duplicati/duplicati/blob/master/Duplicati/Library/Modules/Builtin/run-script-example.sh_
Add [script](scripts/duplicati-influxdb-notify) to default settings.
- DUPLICATI__EVENTNAME Example:
--run-script-after=duplicati-influxdb-notify
Eventname is BEFORE if invoked as --run-script-before, and AFTER if invoked as --run-script-after. This value cannot be changed by writing it back!
### Docker log
- DUPLICATI__OPERATIONNAME
Add [script](docker/scripts/dockerlog) to default settings.
Operation name can be any of the operations that Duplicati supports. For example it can be "Backup", "Cleanup", "Restore", or "DeleteAllButN". This value cannot be changed by writing it back! Example:
--run-script-after=dockerlog
- DUPLICATI__RESULTFILE
### Environment Variables
If invoked as --run-script-after this will contain the name of the file where result data is placed. This value cannot be changed by writing it back!
Source: <https://github.com/duplicati/duplicati/blob/master/Duplicati/Library/Modules/Builtin/run-script-example.sh>_
- DUPLICATI__REMOTEURL
- DUPLICATI__EVENTNAME
This is the remote url for the target backend. This value can be changed by echoing --remoteurl = "new value".
Eventname is BEFORE if invoked as --run-script-before, and AFTER if invoked as --run-script-after. This value cannot be changed by writing it back!
- DUPLICATI__LOCALPATH
- DUPLICATI__OPERATIONNAME
This is the path to the folders being backed up or restored. This variable is empty operations other than backup or restore. The local path can contain : to separate multiple folders. This value can be changed by echoing --localpath = "new value".
Operation name can be any of the operations that Duplicati supports. For example it can be "Backup", "Cleanup", "Restore", or "DeleteAllButN". This value cannot be changed by writing it back!
- DUPLICATI__PARSED_RESULT
- DUPLICATI__RESULTFILE
This is a value indicating how well the operation was performed. It can take the values: Unknown, Success, Warning, Error, Fatal.
If invoked as --run-script-after this will contain the name of the file where result data is placed. This value cannot be changed by writing it back!
### Exit Codes
- DUPLICATI__REMOTEURL
_Source: https://github.com/duplicati/duplicati/blob/master/Duplicati/Library/Modules/Builtin/run-script-example.sh_
This is the remote url for the target backend. This value can be changed by echoing --remoteurl = "new value".
The following exit codes are supported:
- DUPLICATI__LOCALPATH
- 0: OK, run operation
- 1: OK, don't run operation This is the path to the folders being backed up or restored. This variable is empty operations other than backup or restore. The local path can contain : to separate multiple folders. This value can be changed by echoing --localpath = "new value".
- 2: Warning, run operation
- 3: Warning, don't run operation - DUPLICATI__PARSED_RESULT
- 4: Error, run operation
- 5: Error don't run operation This is a value indicating how well the operation was performed. It can take the values: Unknown, Success, Warning, Error, Fatal.
- other: Error don't run operation
### Exit Codes
The following exit codes are supported:
- 0: OK, run operation
- 1: OK, don't run operation
- 2: Warning, run operation
- 3: Warning, don't run operation
- 4: Error, run operation
- 5: Error don't run operation
- other: Error don't run operation
## cli
## Send Mail
```bash
#for testing
duplicati-cli send-mail --send-mail-password="pass" --send-mail-to="target@mail.lan" --send-mail-username="suer@mail.lan" --send-mail-url="smtp://serveraddress:25"
```
## Settings
### Send Email
```bash
--send-mail-any-operation=true
--send-mail-body=%RESULT%
--send-mail-level=all
--send-mail-subject=Duplicati %OPERATIONNAME% report for -> %backup-name%
--send-mail-to=destination@mail.lan
--send-http-result-output-format=Duplicati
--send-mail-url=smtp://serveraddress:25
--send-mail-password=password
--send-mail-username=user@mail.lan
```
## nginx
Example running on _duplicati sub folder
```bash
location /_duplicati/ {
proxy_pass http://<duplicatiserver>:8200/;
proxy_redirect ~^/(.*) $scheme://$http_host/_duplicati/$1;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Protocol $scheme;
proxy_set_header X-Url-Scheme $scheme;
}
```

17
docker/Dockerfile Normal file
View File

@@ -0,0 +1,17 @@
FROM duplicati/duplicati
RUN apt update && \
apt install -y default-mysql-client && \
rm -rf /var/lib/apt/lists/*
#repo root scripts
COPY /docker/scripts /usr/local/bin
#docker scripts
COPY ./scripts /usr/local/bin
RUN \
chmod +x /usr/local/bin/duplicati-influxdb-notify; \
chmod +x /usr/local/bin/duplicati-mysql-backup; \
chmod +x /usr/local/bin/dockerlog
EXPOSE 8200

34
docker/README.md Normal file
View File

@@ -0,0 +1,34 @@
# Duplicati / mySql Client
- [Docker Compose](#docker-compose)
- [Development](#development)
- [Docker Build](#docker-build)
## Docker Compose
```yaml
version: "3"
services:
duplicati:
image: git.limbosolutions.com/kb/duplicati:mysql-latest
environment:
- MYSQL_HOST=${MYSQL_HOST}
- MYSQL_DATABASE=${MYSQL_DATABASE}
- MYSQL_USER=${MYSQL_USER}
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
- INFLUXDB_SERVER=${INFLUXDB_SERVER}
- INFLUXDB_BUCKET=${INFLUXDB_BUCKET}
- INFLUXDB_ORG=${INFLUXDB_ORG}
- INFLUXDB_TOKEN=${INFLUXDB_TOKEN}
- INFLUXDB_CLIENT_HOSTNAME=${INFLUXDB_CLIENT_HOSTNAME}
volumes:
- duplicati-data:/data
- db-dumps:/db-dumps
ports:
- 8200:8200
restart: unless-stopped
volumes:
duplicati-data:
db-dumps:
```

View File

@@ -1,9 +0,0 @@
#check ../README.md for more information
FROM duplicati/duplicati
RUN apt update && apt install -y default-mysql-client && rm -rf /var/lib/apt/lists/*
RUN mkdir duplicati-mysqlclient
RUN mkdir duplicati-mysqlclient/scripts
COPY /docker/mysqlclient/scripts/* /duplicati-mysqlclient/scripts/
RUN chmod +x /duplicati-mysqlclient/scripts/*
EXPOSE 8200

View File

@@ -1,60 +0,0 @@
# Duplicati / mySql Client
Using option run-script-before-required on duplicati job set value to /duplicati-mysqlclient/scripts/backupdb.sh.
And job will create a database dump configured using docker environment variables
## Build Image
### docker
```bash
#Executed on repository root folder
docker build -t duplicati-mysqlclient:latest -f docker/mysqlclient/Dockerfile .
```
### tar
```bash
#Executed on repository root folder
sudo docker build -t duplicati-mysqlclient:latest -f docker/mysqlclient/Dockerfile --output type=tar,dest=build/duplicati-mysqlclient.tar .
```
### Portainer
Images -> Build a new Image -> URL
**Name:** duplicati-mysqlclient:latest
**URL:** https://git.limbosolutions.com/kb/duplicati.git
**Dockerfile path:** docker/mysqlclient/Dockerfile
## Run Container
### Docker Compose
```yaml
version: "3"
services:
duplicati:
image: duplicati-mysqlclient
environment:
- MYSQL_HOST=${MYSQL_HOST}
- MYSQL_DATABASE=${MYSQL_DATABASE}
- MYSQL_USER=${MYSQL_USER}
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
- DESTINATION=/db-dumps
volumes:
- duplicati-data:/data
- db-dumps:/db-dumps
ports:
- 8200:8200
restart: unless-stopped
volumes:
duplicati-data:
db-dumps:
````

10
docker/scripts/dockerlog Normal file
View File

@@ -0,0 +1,10 @@
#!/bin/bash
#printf $(date '+%Y-%m-%d') >> /proc/1/fd/1;
#printf " " >> /proc/1/fd/1;
#printf $(date '+%H:%M:%S') >> /proc/1/fd/1;
printf "INFO:" >> /proc/1/fd/1;
printf " %s" $DUPLICATI__OPERATIONNAME >> /proc/1/fd/1;
printf " %s" $DUPLICATI__PARSED_RESULT >> /proc/1/fd/1;
printf " %s" $DUPLICATI__backup_name >> /proc/1/fd/1;
printf " %s" $DUPLICATI__LOCALPATH >> /proc/1/fd/1;
printf "\n" >> /proc/1/fd/1

View File

@@ -0,0 +1,86 @@
#!/bin/bash
if [ -f "/etc/default/duplicati-influxdb" ]; then
export $(cat /etc/default/duplicati-influxdb)
fi
if [ -f "~/.config/duplicati-influxdb" ]; then
export $(cat ~/default/duplicati-influxdb)
fi
TAGS=""
MESSAGE_FIELD_VALUE=""
UNSCAPED=""
ESCAPED=""
escape_tag_str () {
ESCAPED=${UNSCAPED//[ ]/\\ }
}
if [[ ! -z "$INFLUXDB_CLIENT_HOSTNAME" ]]; then
UNSCAPED=$INFLUXDB_CLIENT_HOSTNAME
escape_tag_str
TAGS="${TAGS},host=${ESCAPED}"
MESSAGE_FIELD_VALUE="${MESSAGE_FIELD_VALUE}${INFLUXDB_CLIENT_HOSTNAME} "
else
if [[ ! -z "$HOSTNAME" ]]; then
UNSCAPED=$HOSTNAME
escape_tag_str
TAGS="${TAGS},host=${ESCAPED}"
MESSAGE_FIELD_VALUE="${MESSAGE_FIELD_VALUE}${HOSTNAME} "
fi
fi
if [[ ! -z "$DUPLICATI__EVENTNAME" ]]; then
UNSCAPED=$DUPLICATI__EVENTNAME
escape_tag_str
TAGS="${TAGS},eventName=\"${ESCAPED}\""
fi
if [[ ! -z "$DUPLICATI__OPERATIONNAME" ]]; then
UNSCAPED=$DUPLICATI__OPERATIONNAME
escape_tag_str
TAGS="${TAGS},operationName=${ESCAPED}"
MESSAGE_FIELD_VALUE="${MESSAGE_FIELD_VALUE}${DUPLICATI__OPERATIONNAME} "
fi
if [[ ! -z "$DUPLICATI__backup_name" ]]; then
UNSCAPED=$DUPLICATI__backup_name
escape_tag_str
TAGS="${TAGS},backupName=${ESCAPED}"
MESSAGE_FIELD_VALUE="${MESSAGE_FIELD_VALUE}${DUPLICATI__backup_name} "
fi
if [[ ! -z "$DUPLICATI__PARSED_RESULT" ]]; then
UNSCAPED=$DUPLICATI__PARSED_RESULT
escape_tag_str
TAGS="${TAGS},status=${ESCAPED}"
MESSAGE_FIELD_VALUE="${MESSAGE_FIELD_VALUE}${DUPLICATI__PARSED_RESULT} "
fi
if [[ ! -z "$DUPLICATI__RESULTFILE" ]]; then
UNSCAPED=$DUPLICATI__RESULTFILE
escape_tag_str
TAGS="${TAGS},resultFile=${ESCAPED}"
fi
if [[ ! -z "$DUPLICATI__LOCALPATH" ]]; then
UNSCAPED=$DUPLICATI__LOCALPATH
escape_tag_str
TAGS="${TAGS},localPath=${ESCAPED}"
fi
FIELDS="message=\"${MESSAGE_FIELD_VALUE}\""
#echo $TAGS
curl --request POST \
"$INFLUXDB_SERVER/write?db=$INFLUXDB_BUCKET&ORG=$INFLUXDB_ORG" \
--header "Authorization: Token $INFLUXDB_TOKEN" \
--header "Content-Type: text/plain; charset=utf-8" \
--header "Accept: application/json" \
--data-raw "duplicati${TAGS} ${FIELDS}" > /dev/null 2>&1
exit 0

View File

@@ -1,49 +1,60 @@
#!/bin/bash #!/bin/bash
# mysql database backup.
# executed by duplicati run-script-before-required # mysql database backup.
# required environment variables: # executed by duplicati run-script-before-required
# DESTINATION # required environment variables:
# MYSQL_HOST
# MYSQL_USER # MYSQL_HOST
# MYSQL_PASSWORD # MYSQL_USER
# MYSQL_DATABASE # MYSQL_PASSWORD
# MYSQL_DATABASE
#any error must stop execution # MYSQL_BACKUP_FOLDER
set -e
#any error must stop execution
if [ $DUPLICATI__OPERATIONNAME == "Backup" ] set -e
then
echo "Backup Job!!" if [ -f "/etc/default/duplicati-mysql" ]; then
else export $(cat /etc/default/duplicati-mysql)
echo "Not a backup operation. exiting!" fi
#OK, run operation
exit if [ -f "~/.config/duplicati-mysql" ]; then
fi export $(cat ~/default/duplicati-mysql)
fi
if [ -z ${DESTINATION} ]
then if [ $DUPLICATI__OPERATIONNAME == "Backup" ]
echo "\$DESTINATION environment variable cannot be empty empty" then
#5: Error don't run operation echo "Backup Job!!"
exit 5 else
fi echo "Not a backup operation. exiting!"
#OK, run operation
TARGETFILENAME=${MYSQL_DATABASE}_dump_$(date -d "today" +"%Y%m%d%H%M%S").sql exit
echo "dump file name:$TARGETFILENAME" fi
if [ -f /tmp/${TARGETFILENAME} ] if [ -z "$MYSQL_BACKUP_FOLDER" ]; then
then MYSQL_BACKUP_FOLDER="/var/db-dumps"
rm /tmp/${TARGETFILENAME} fi
fi
if [ ! -d $MYSQL_BACKUP_FOLDER ]; then
mkdir -p $MYSQL_BACKUP_FOLDER;
mysqldump -h ${MYSQL_HOST} --user=${MYSQL_USER} -p"${MYSQL_PASSWORD}" ${MYSQL_DATABASE} > /tmp/${TARGETFILENAME} fi
TARGETFILENAME=${MYSQL_DATABASE}_dump_$(date -d "today" +"%Y%m%d%H%M%S").sql
if [ x$(find "$DESTINATION" -prune -empty) = x"$DESTINATION" ]; then echo "dump file name:$TARGETFILENAME"
echo "folder is empty... ignoring clean db dump folder"
else if [ -f /tmp/${TARGETFILENAME} ]
rm -r ${DESTINATION}/* then
fi rm /tmp/${TARGETFILENAME}
fi
mv /tmp/${TARGETFILENAME} ${DESTINATION}/${TARGETFILENAME}
mysqldump -h ${MYSQL_HOST} --user=${MYSQL_USER} -p"${MYSQL_PASSWORD}" ${MYSQL_DATABASE} > /tmp/${TARGETFILENAME}
if [ x$(find "$MYSQL_BACKUP_FOLDER" -prune -empty) = x"$MYSQL_BACKUP_FOLDER" ]; then
echo "folder is empty... ignoring clean db dump folder"
else
rm -r ${MYSQL_BACKUP_FOLDER}/*
fi
mv /tmp/${TARGETFILENAME} ${MYSQL_BACKUP_FOLDER}/${TARGETFILENAME}