Compare commits

..

20 Commits

Author SHA1 Message Date
Tobias Müller
31286b4b71 got mounting working, added needed params to exmaple docker-compose
All checks were successful
Build And Test / build (push) Successful in 42s
2025-01-19 03:00:36 +01:00
Tobias Müller
fa3f93b1eb debug
All checks were successful
Build And Test / build (push) Successful in 40s
2025-01-19 01:12:33 +01:00
Tobias Müller
004f9b69d7 prepare for first test
All checks were successful
Build And Test / build (push) Successful in 39s
2025-01-19 01:06:54 +01:00
Tobias Müller
5ad9c1bfd9 modified: docker/src/helper_scripts/mount-backup
All checks were successful
Build And Test / build (push) Successful in 38s
2025-01-19 01:01:00 +01:00
Tobias Müller
2820fdcf44 building mount command
All checks were successful
Build And Test / build (push) Successful in 40s
2025-01-19 00:55:07 +01:00
Tobias Müller
a692543bfb implement ability to mount backups as fuse mount, first step is to get selection working 2025-01-19 00:30:22 +01:00
Tobias Müller
50164f64cd test of adding notification via ntfy
All checks were successful
Build And Test / build (push) Successful in 39s
2025-01-18 22:29:39 +01:00
Tobias Müller
64007a8e21 Customized Readme for PI
All checks were successful
Build And Test / build (push) Successful in 40s
modified:   README.md
	deleted:    docker/README.md
2025-01-17 12:27:42 +01:00
Tobias Müller
990101e8a4 still path
All checks were successful
Build And Test / build (push) Successful in 42s
2025-01-17 11:46:52 +01:00
Tobias Müller
c35198f9c2 path still wrong
Some checks failed
Build And Test / build (push) Failing after 15s
2025-01-17 11:44:48 +01:00
Tobias Müller
4dcc9a3686 typo
Some checks failed
Build And Test / build (push) Failing after 14s
2025-01-17 11:43:38 +01:00
Tobias Müller
70a220ad04 change path to upstream structure
Some checks failed
Build And Test / build (push) Failing after 16s
2025-01-17 11:40:27 +01:00
Tobias Müller
f28eac21ff update readme 2025-01-17 11:38:30 +01:00
edv-pi
a4c1bce7e4
Update README.md
Some checks failed
Build And Test / build (push) Failing after 15s
2025-01-17 11:35:02 +01:00
Tobias Müller
69ca732aaf use internal workflow 2025-01-17 11:29:58 +01:00
Tobias Müller
bd3e02aee8 pi additions 2025-01-17 11:27:59 +01:00
Tobias Müller
9cb6a3e828 add possibility to exclude files and folders 2025-01-16 07:32:09 +01:00
Tobias Müller
e94a086ead added some text 2025-01-15 12:41:10 +01:00
Tobias Müller
7b1d90ed7e modified: docker/src/s6-services/key_setup/run
modified:   docker/src/s6-services/setup_check/run_include
2025-01-15 12:39:19 +01:00
Tobias Müller
83406b84af added possiblity to turn off encryption 2025-01-15 12:18:28 +01:00
10 changed files with 205 additions and 73 deletions

View File

@ -0,0 +1,31 @@
#
# .gitea/gitea-ci.yaml
#
name: Build And Test
run-name: ${{ gitea.actor }} is runs ci pipeline
on: [ push ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: https://github.com/actions/checkout@v4
- name: Set up Docker Buildx
uses: https://github.com/docker/setup-buildx-action@v3
with:
config-inline: |
[registry."images.physi.uni-heidelberg.de"]
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: images.physi.uni-heidelberg.de/pibackup
- name: Build and push Docker image
uses: https://github.com/docker/build-push-action@v6
with:
context: ./docker
push: true
#tags: "images.physi.uni-heidelberg.de/pibackup,images.physi.uni-heidelberg.de/pibackup:latest"
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

View File

@ -1,8 +1,6 @@
# Proxmox Backup Server: Client Docker
[![Build and Publish Docker Image](https://github.com/Aterfax/pbs-client-docker/actions/workflows/docker-publish.yml/badge.svg)](https://github.com/Aterfax/pbs-client-docker/actions/workflows/docker-publish.yml)
![Docker Image Size (tag)](https://img.shields.io/docker/image-size/aterfax/pbs-client/latest)
![Docker Pulls](https://img.shields.io/docker/pulls/aterfax/pbs-client)
![Build and Publish Docker Image](https://git.physi.uni-heidelberg.de/tmueller/pbs-client-docker/actions/workflows/build_image.yaml/badge.svg)
## **tl;dr?**
@ -23,6 +21,7 @@ For more in depth instructions, see: [Using-the-DockerHub-provided-image](#Using
## Table of Contents
- [PI Customs](#PI)
- [Quickstart](#Quickstart)
- [Configuration](#Configuration)
- [FAQ](#FAQ)
@ -30,6 +29,14 @@ For more in depth instructions, see: [Using-the-DockerHub-provided-image](#Using
- [Contributing](#Contributing)
- [License](#License)
## PI
### Changes
Encryption can be turned off.
Most of the Data is scientific related and does not contain any secrets and it would be a waste of ressources to encrypt that and loose the deduplication of it because older backups of similar data arent encrypted.
For sensible data you can and should enable the encryption with its own set of keypairs and keep them stored seperate from the backups.
## Quickstart
### Prerequisites
@ -40,9 +47,6 @@ For more in depth instructions, see: [Using-the-DockerHub-provided-image](#Using
### Using the DockerHub provided image
> [!WARNING]
> It is possible, but highly discouraged for you to make unencrypted backups by setting `UNENCRYPTED=1` in your ``.env`` file. This will bypass the automatic key generation process but **this is a bad idea** as the backed-up data will be stored in plaintext. This means that the owner of the PBS backup server you are backing up to will have full access to explore the backed-up content.
* Run the image with the provided docker-compose file after amending it and the ``.env`` file where needed.
* If allowing the container to conduct an auto setup, don't set a ``PBS_ENCRYPTION_PASSWORD`` value yet as the container first run will autogenerate one for you.
* Supply your desired ``master-public.pem``, ``master-private.pem`` and ``encryption-key.json`` files with a matching ``PBS_ENCRYPTION_PASSWORD`` or allow the container to automatically generate these for you on first run.
@ -84,9 +88,17 @@ The following environment variables can be configured to customize the behavior
| Variable Name | Default Docker Compose Value | Valid Values | Description |
|--------------------|------------------------------|------------------------|-----------------------------------------------------------------------------------------------------------------------|
| Variable Name | Default Docker Compose Value | Valid Values | Description |
| PBS_ENDPOINT | none | fqdn | target PBS-server |
| PBS_FINGERPRINT | none | XX:XX:XX:XX... | your fringerprint of your pbs instance |
| PBS_DATASTORE | none | string | name of your pbs datastore |
| PBS_DATASTORE_ns | none | string | name of your pbs namespace |
| CRON_SCHEDULE | none | * * * * * | cron expression to define the shedule for backups |
| CRON_BACKUP_ONLY | none | boolean | controls if first backup will be done at the first start |
| PBS_API_KEY_NAME or PBS_USER | none | string | credentials for pbs either define an api token or specify user |
| PBS_API_KEY_SECRET or PBS_PASSWORD | none | string | password or secret |
| TZ | none | IANA's time zone database long | Timezone to use for tuimestamps in backup |
| UNENCRYPTED | 0 | boolean | disables encryption if set to 1 |
| CHANGE_DETECT_MODE | metadata | metadata, data, legacy | Let you choose the desired mode for detecting file changes between backups |
## FAQ
@ -100,11 +112,6 @@ See also:
- https://github.com/Aterfax/pbs-client-docker/issues/8
- https://forum.proxmox.com/threads/backup-client-encryption-not-working-inside-docker-container.139054/
> [!WARNING]
> It is possible, but highly discouraged for you to bypass this issue by taking unencrypted backups. You can do this by setting `UNENCRYPTED=1` in your ``.env`` file and this will bypass the automatic key generation process.
>
>**This is a bad idea** as the backed-up data will be stored in plaintext. This means that the owner of the PBS backup server you are backing up to will have full access to explore the backed-up content.
## Troubleshooting
If you encounter issues, check the [Troubleshooting section](TROUBLESHOOTING.md) for solutions to common problems.

View File

@ -1,34 +1,32 @@
# The 4 variables below are required.
PBS_ENCRYPTION_PASSWORD=123456789abcdefghijklmn
PBS_ENDPOINT=pbs.mydomain.com
PBS_DATASTORE=test-datastore
CRON_SCHEDULE=0 */4 * * *
PBS_ENCRYPTION_PASSWORD="123456789abcdefghijklmn"
PBS_ENDPOINT="pbs.mydomain.com"
PBS_DATASTORE="test-datastore"
CRON_SCHEDULE="0 */4 * * *"
# If you want to skip backup on startup, set CRON_BACKUP_ONLY=1 otherwise CRON_BACKUP_ONLY=0
CRON_BACKUP_ONLY=0
# Set UNENCRYPTED=1 to bypass automatic encryption key generation and allow the backups to be unencrypted.
# This is a bad idea as the owner of the PBS backup server you are backing up to will have full access to
# explore the backed-up content.
UNENCRYPTED=0
# Use of the PBS_API_KEY_NAME and PBS_API_KEY_SECRET is recommended!
# If unset, ensure PBS_USER and PBS_PASSWORD are set.
PBS_API_KEY_NAME=username@pam!test
PBS_API_KEY_SECRET=4054356a-f1a6-441e-86fc-e338367db185
PBS_API_KEY_NAME="username@pam!test"
PBS_API_KEY_SECRET="4054356a-f1a6-441e-86fc-e338367db185"
# PBS_USER is not required if PBS_API_KEY_NAME is set.
# PBS_PASSWORD is not required if PBS_API_KEY_SECRET is set.
PBS_USER=
PBS_PASSWORD=
PBS_USER=""
PBS_PASSWORD=""
# PBS_DATASTORE_NS is optional but should be set if using namespaces.
PBS_DATASTORE_NS=test
PBS_DATASTORE_NS="test"
# PBS_FINGERPRINT is required if using a self signed SSL certificate.
PBS_FINGERPRINT=
PBS_FINGERPRINT=""
# Healthchecks.io details - Optional.
HEALTHCHECKSUUID=aa7b0de3-2c17-4fce-b051-388a5415e656
HEALTHCHECKSHOSTNAME=https://healthchecks.mydomain.com
HEALTHCHECKSUUID="aa7b0de3-2c17-4fce-b051-388a5415e656"
HEALTHCHECKSHOSTNAME="https://healthchecks.mydomain.com"
TZ=Etc/UTC
# Disable Encryption
ENCRYPTION=1

View File

@ -1,7 +1,6 @@
version: '3.3'
services:
pbs-client:
image: aterfax/pbs-client
image: tmueller/pbs-client
container_name: pbs-client
hostname: pbs-client
restart: unless-stopped
@ -12,8 +11,17 @@ services:
- /run:exec
volumes:
- ./pbsconfig/:/root/.config/proxmox-backup/
# Note - if you want to restore backups make sure to change to read write below.
# See the 'restore-backup' command inside the container.
- ./backups/test1:/backups/test1:ro
- ./backups/test2:/backups/test2:ro
- ./backups/test3:/backups/test3:ro
- type: bind
source: /restore
target: /restore
bind:
propagation: rshared
cap_add:
- SYS_ADMIN
devices:
- /dev/fuse:/dev/fuse
security_opt:
- apparmor:unconfined

View File

@ -0,0 +1,73 @@
#!/usr/bin/with-contenv bash
# shellcheck shell=bash
source /etc/s6-overlay/s6-rc.d/setup_check/run_include
# We need to build this command in case namespaces are in use.
MOUNTCMD="proxmox-backup-client mount"
LISTCMD="proxmox-backup-client snapshot list"
if [ -n "$PBS_DATASTORE_NS" ]; then
LISTCMD+=" --ns ${PBS_DATASTORE_NS}"
MOUNTCMD+=" --ns ${PBS_DATASTORE_NS}"
fi
LISTCMD+=" --output-format json"
data=$(${LISTCMD})
host_name=$(hostname)
# Backups in einer nummerierten Liste ausgeben
options=$(echo "$data" | jq -r --arg host "$host_name" '
.[] |
select(.["backup-id"] == $host) |
"\(.["backup-type"])/\($host)/\(.["backup-time"] | tonumber | strftime("%Y-%m-%dT%H:%M:%SZ"))"')
# Array erstellen und anzeigen
echo "Verfügbare Backups:"
IFS=$'\n' read -d '' -r -a backups <<< "$options"
for i in "${!backups[@]}"; do
echo "$((i + 1)). ${backups[i]}"
done
# Benutzereingabe für die Auswahl
read -p "Wählen Sie ein Backup aus (Nummer eingeben): " selection
# Überprüfen, ob die Eingabe gültig ist
if [[ "$selection" -ge 1 && "$selection" -le "${#backups[@]}" ]]; then
selected_backup="${backups[$((selection - 1))]}"
MOUNTCMD+=" $selected_backup"
echo "Ausgewähltes Backup: $selected_backup"
# Dateien des ausgewählten Backups abrufen
backup_index=$((selection - 1))
files=$(echo "$data" | jq -r --argjson index "$backup_index" '
.[$index].files[].filename | select(test("\\.pxar.didx$|\\.mpxar.didx$"))')
# Dateien in einer nummerierten Liste ausgeben
echo "Verfügbare Dateien:"
IFS=$'\n' read -d '' -r -a file_list <<< "$files"
for i in "${!file_list[@]}"; do
echo "$((i + 1)). ${file_list[i]}"
done
# Benutzereingabe für die Dateiauswahl
read -p "Wählen Sie eine Datei aus (Nummer eingeben): " file_selection
# Überprüfen, ob die Eingabe gültig ist
if [[ "$file_selection" -ge 1 && "$file_selection" -le "${#file_list[@]}" ]]; then
selected_file="${file_list[$((file_selection - 1))]}"
MOUNTCMD+=" $selected_file"
echo "Ausgewählte Datei: $selected_file"
echo "DEBUG: $MOUNTCMD"
MOUNTCMD+=" /restore"
$(${MOUNTCMD})
echo "Dont forget to unmount when finished (just umount /path/on/the/host i.e. /restore)"
else
echo "Ungültige Auswahl. Abbruch."
exit 1
fi
else
echo "Ungültige Auswahl. Abbruch."
exit 1
fi

View File

@ -116,7 +116,7 @@ read -rp "Are these details correct? Press Enter to continue or Ctrl+C to cancel
#proxmox-backup-client restore host/elsa/2019-12-03T09:35:01Z root.pxar /target/path/
# We need to build this command in case namespaces are in use.
RESTORECMD="proxmox-backup-client restore ${selected_backup_type}/${selected_backup_id}/${selected_backup_time} ${selected_file} ${restore_path}"
if [ -n "$PBS_DATASTORE_NS" ]; then
if [ -n "$RESTORECMD" ]; then
RESTORECMD+=" --ns ${PBS_DATASTORE_NS}"
fi
echo -e "\nRestore command:"

View File

@ -47,6 +47,21 @@ if [ -n "$PBS_DATASTORE_NS" ]; then
BACKUPCMD+=" --ns ${PBS_DATASTORE_NS}"
fi
# Add possibility to exlude paths
if [ -n "$EXCLUDE" ]; then
IFS=', ' read -r -a array <<< "$EXCLUDE"
for element in "${array[@]}"
do
BACKUPCMD+=" --exclude ${element}"
done
fi
if [ -n "$CHANGE_DETECT_MODE" ]; then
BACKUPCMD+=" --change-detection-mode=${CHANGE_DETECT_MODE}"
else
BACKUPCMD+=" --change-detection-mode=metadata"
fi
# Source the variables from the setup_check scripting include file.
source /etc/s6-overlay/s6-rc.d/setup_check/run_include
@ -60,7 +75,7 @@ fi
# to allow the first backup or we're
if [ "$CRON_BACKUP_ONLY" = "0" ] || [ -e "${lastrunfile}" ]; then
if [ -n "$HEALTHCHECKSURL" ]; then
curl -fsS -m 10 --retry 5 -o /dev/null $HEALTHCHECKSURL/start
curl -fsS -m 10 --retry 5 $HEALTHCHECKSURL/start
fi
# Run the actual backup command.
@ -72,7 +87,7 @@ if [ "$CRON_BACKUP_ONLY" = "0" ] || [ -e "${lastrunfile}" ]; then
if [ -n "$HEALTHCHECKSURL" ]; then
# We pipe the exit code to healthchecks, if it isn't zero, a warning will fire.
curl -fsS -m 10 --retry 5 -o /dev/null ${HEALTHCHECKSURL}/${BACKUP_EXIT_CODE}
curl -fsS -m 10 --retry 5 ${HEALTHCHECKSURL}/${BACKUP_EXIT_CODE}
fi
elif [ "$CRON_BACKUP_ONLY" = "1" ]; then
echo "CRON_BACKUP_ONLY=1, skipping container start up initial backup."

View File

@ -32,7 +32,7 @@ fi
CRONLOG_FILE="/root/.config/proxmox-backup/cron.log"
CRON_FILE="/etc/cron.d/cron-backup"
CRON_LINE="${CRON_SCHEDULE} root bash -c '/etc/s6-overlay/s6-rc.d/backup/run_include' >> $CRONLOG_FILE 2>&1 "
CRON_LINE="${CRON_SCHEDULE} root bash -c '/etc/s6-overlay/s6-rc.d/backup/run_include' >> $CRONLOG_FILE || curl -d \"Archsync failed\" ntfy-server/pbs 2>&1"
TIMEOUT=60
touch "${CRONLOG_FILE}"

View File

@ -20,39 +20,35 @@ handle_error() {
}
trap handle_error ERR
# Check if encryption is disabled via environment variable
if [ "${UNENCRYPTED}" = "1" ]; then
echo "Encrypted backups are disabled. Skipping key setup process."
echo ""
echo "This is a bad idea as the owner of the PBS backup server you are backing up to will have full access to explore the backed-up content."
exit 0
fi
client_encryption_keyfile="/root/.config/proxmox-backup/encryption-key.json"
master_private_keyfile="/root/.config/proxmox-backup/master-private.pem"
master_public_keyfile="/root/.config/proxmox-backup/master-public.pem"
expect="/usr/bin/expect"
# Check if client encryption keyfile exists and do stuff.
if [ -f "$client_encryption_keyfile" ]; then
echo "Client encryption keyfile exists. Skipping client encryption keyfile creation."
if [ "$UNENCRYPTED" = "1" ]; then
echo "Encryption set to false not gonna create any Keys."
else
# Check if client encryption keyfile exists and do stuff.
if [ -f "$client_encryption_keyfile" ]; then
echo "Client encryption keyfile exists. Skipping client encryption keyfile creation."
else
echo "Client encryption keyfile does not exist. Creating new client encryption keyfile."
$expect /etc/s6-overlay/s6-rc.d/key_setup/client_key
fi
fi
# Check if both Master keyfiles exist and do stuff.
if [ -f "$master_private_keyfile" ] && [ -f "$master_public_keyfile" ]; then
# Check if both Master keyfiles exist and do stuff.
if [ -f "$master_private_keyfile" ] && [ -f "$master_public_keyfile" ]; then
echo "Both master private and public keys exist. Skipping client Master keyfiles creation."
elif [ ! -f "$master_private_keyfile" ] && [ ! -f "$master_public_keyfile" ]; then
elif [ ! -f "$master_private_keyfile" ] && [ ! -f "$master_public_keyfile" ]; then
echo "Both master private and public keys do not exist. Creating master keyfiles new pair."
cd /root/.config/proxmox-backup/ && $expect /etc/s6-overlay/s6-rc.d/key_setup/client_master_key
elif [ ! -f "$master_private_keyfile" ] || [ ! -f "$master_public_keyfile" ]; then
elif [ ! -f "$master_private_keyfile" ] || [ ! -f "$master_public_keyfile" ]; then
echo "One of the master keyfiles is missing. Error! User intervention required. Ensure correct files present, or remove both: \n"
echo "$master_private_keyfile \n"
echo "$master_oublic_keyfile \n"
echo "To allow for automatic key recreation."
fi
fi

View File

@ -30,11 +30,15 @@ if [ -z "$PBS_PASSWORD" ]; then
exit 1
fi
# Evaluate each subvariable and replace all spaces with nothing - if not zero length set variable.
if [[ ! -z "${HEALTHCHECKSHOSTNAME// }" ]] && [[ ! -z "${HEALTHCHECKSUUID// }" ]]; then
HEALTHCHECKSURL="${HEALTHCHECKSHOSTNAME}/ping/${HEALTHCHECKSUUID}"
export HEALTHCHECKSURL="${HEALTHCHECKSURL}"
if [ -n "$UNENCRYPTED" ]; then
UNENCRYPTED="${UNENCRYPTED}"
else
UNENCRYPTED="0"
fi
HEALTHCHECKSURL="${HEALTHCHECKSHOSTNAME}/ping/${HEALTHCHECKSUUID}"
export UNENCRYPTED
export HEALTHCHECKSURL="${HEALTHCHECKSURL}"
export PBS_PASSWORD="${PBS_PASSWORD}"
export PBS_REPOSITORY="${PBS_USER}@${PBS_ENDPOINT}:${PBS_DATASTORE}"