diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..36fb9b8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.devcontainer/ +.vscode/ \ No newline at end of file diff --git a/paperless-ngx/DOCS.md b/paperless-ngx/DOCS.md index 98345b6..6827c3f 100644 --- a/paperless-ngx/DOCS.md +++ b/paperless-ngx/DOCS.md @@ -70,6 +70,10 @@ consumer_subdirs_as_tags: false ssl: false certfile: fullchain.pem keyfile: privkey.pem +backup_enabled: false +backup_path: /data/exports +backup_cron: "0 3 * * *" +backup_keep_count: 3 ``` ### Option: `url` @@ -152,6 +156,22 @@ The private key file to use for SSL. Let you set `client_max_body_size` of _nginx_ manually +### Option: `backup_enabled` + +Enables or disables automatic backups of your Paperless data. Set to `true` to enable scheduled backups. `false` ist default. + +### Option: `backup_path` + +Specifies the directory where backup files will be stored. The default path is `/data/exports`. + +### Option: `backup_cron` + +Defines the cron schedule for automatic backups. The default value `"0 2 * * *"` runs backups daily at 3:00 AM. Use standard cron syntax to customize the backup schedule. + +### Option: `backup_keep_count` + +Sets the number of most recent backups to retain. Older backups beyond this count will be automatically deleted. The default is `3` backups. + ### More personalisation You can add more configurations options in `/addon_config/paperless_ngx/paperless.conf` diff --git a/paperless-ngx/Dockerfile b/paperless-ngx/Dockerfile index 5ee741c..b598ee5 100644 --- a/paperless-ngx/Dockerfile +++ b/paperless-ngx/Dockerfile @@ -94,7 +94,9 @@ ARG RUNTIME_PACKAGES="\ libgs10-common=${GHOSTSCRIPT_VERSION} \ ghostscript=${GHOSTSCRIPT_VERSION} \ libjbig2enc-dev=0.30-1 \ - qpdf=12.2.0-1" + qpdf=12.2.0-1 \ + zip \ + unzip" # Buildx provided, must be defined to use though ARG TARGETARCH @@ -168,6 +170,19 @@ RUN --mount=type=cache,target=/root/.cache/uv/,id=uv-cache \ && rm -rf /var/tmp/* \ && rm -rf /var/cache/apt/archives/ + +# Install supercronic +# Latest releases available at https://github.com/aptible/supercronic/releases +ENV SUPERCRONIC_URL=https://github.com/aptible/supercronic/releases/download/v0.2.41/supercronic-linux-amd64 \ + SUPERCRONIC_SHA1SUM=f70ad28d0d739a96dc9e2087ae370c257e79b8d7 \ + SUPERCRONIC=supercronic-linux-amd64 + +RUN curl -fsSLO "$SUPERCRONIC_URL" \ + && echo "${SUPERCRONIC_SHA1SUM} ${SUPERCRONIC}" | sha1sum -c - \ + && chmod +x "$SUPERCRONIC" \ + && mv "$SUPERCRONIC" "/usr/local/bin/${SUPERCRONIC}" \ + && ln -s "/usr/local/bin/${SUPERCRONIC}" /usr/local/bin/supercronic + WORKDIR /usr/src/paperless/docker/ RUN set -eux \ @@ -202,6 +217,10 @@ VOLUME ["/usr/src/paperless/data", \ # Copy root filesystem COPY rootfs/ / +RUN chmod +x /usr/local/bin/paperless_backup.sh \ + && chmod +x /etc/cont-init.d/90-cron-backup.sh \ + && chmod +x /etc/services.d/supercronic/run + # Build arguments ARG BUILD_ARCH ARG BUILD_DATE diff --git a/paperless-ngx/config.yaml b/paperless-ngx/config.yaml index 9144488..f70c2d3 100644 --- a/paperless-ngx/config.yaml +++ b/paperless-ngx/config.yaml @@ -37,6 +37,10 @@ options: keyfile: privkey.pem ingress_auth: false tika_gotenberg: false + backup_enabled: false + backup_path: "/data/exports" + backup_cron: "0 3 * * *" + backup_keep_count: 3 schema: url: str? csrf_allowed: @@ -59,3 +63,7 @@ schema: ingress_auth: bool tika_gotenberg: bool locales: str? + backup_enabled: bool + backup_path: str + backup_cron: str + backup_keep_count: int diff --git a/paperless-ngx/rootfs/etc/cont-init.d/90-cron-backup.sh b/paperless-ngx/rootfs/etc/cont-init.d/90-cron-backup.sh new file mode 100644 index 0000000..21b5853 --- /dev/null +++ b/paperless-ngx/rootfs/etc/cont-init.d/90-cron-backup.sh @@ -0,0 +1,30 @@ +#!/command/with-contenv bashio +# shellcheck shell=bash +set -e + +echo "[INFO] Configuring backup cron job..." + +if bashio::config.has_value 'backup_enabled'; then + BACKUP_ENABLED="$(bashio::config 'backup_enabled')" +else + BACKUP_ENABLED="false" +fi + +if bashio::config.has_value 'backup_cron'; then + CRON_SCHEDULE="$(bashio::config 'backup_cron')" +else + CRON_SCHEDULE="0 2 * * *" +fi + +if [ "$BACKUP_ENABLED" == "false" ]; then + echo "[INFO] Backup cron job is disabled in configuration. Skipping setup." + exit 0 +fi + +mkdir -p /etc/cron.d + +echo "${CRON_SCHEDULE} /usr/local/bin/paperless_backup.sh >> /proc/1/fd/1 2>&1" > /etc/cron.d/paperless-backup + +chmod 0644 /etc/cron.d/paperless-backup + +echo "[INFO] Backup cron job configured with schedule: $CRON_SCHEDULE" diff --git a/paperless-ngx/rootfs/etc/services.d/supercronic/run b/paperless-ngx/rootfs/etc/services.d/supercronic/run new file mode 100644 index 0000000..f532ea7 --- /dev/null +++ b/paperless-ngx/rootfs/etc/services.d/supercronic/run @@ -0,0 +1,3 @@ +#!/command/with-contenv bashio +# shellcheck shell=bash +exec /usr/local/bin/supercronic /etc/cron.d/paperless-backup \ No newline at end of file diff --git a/paperless-ngx/rootfs/usr/local/bin/paperless_backup.sh b/paperless-ngx/rootfs/usr/local/bin/paperless_backup.sh new file mode 100644 index 0000000..bfbe6dd --- /dev/null +++ b/paperless-ngx/rootfs/usr/local/bin/paperless_backup.sh @@ -0,0 +1,45 @@ +#!/command/with-contenv bashio +# shellcheck shell=bash +set -e + +cd /usr/src/paperless/src || { echo "[ERROR] Cannot change into /usr/src/paperless/src"; exit 1; } + +if bashio::config.has_value 'backup_path'; then + BACKUP_PATH="$(bashio::config 'backup_path')" +else + echo "[ERROR] No backup path configured. Please set 'backup_path' in the add-on configuration." + exit 1 +fi + +if bashio::config.has_value 'backup_keep_count'; then + BACKUP_KEEP_COUNT="$(bashio::config 'backup_keep_count')" +else + echo "[WARN] 'backup_keep_count' not set, defaulting to 3" + BACKUP_KEEP_COUNT=3 +fi + +NOW=$(date '+%Y-%m-%d-%H:%M:%S') +echo "[INFO] Backup started: $NOW" + +mkdir -p "$BACKUP_PATH" + +python3 manage.py document_exporter \ + "$BACKUP_PATH" \ + -z \ + -zn "paperless-export-$NOW" \ + --no-progress-bar \ + || { echo "[ERROR] Creating export failed"; exit 1; } + +echo "[INFO] Backup completed: $BACKUP_PATH/paperless-export-$NOW.zip" + +# ----------------------------- +# Delete old backups +# ----------------------------- +mapfile -t BACKUPS < <(ls -1t "$BACKUP_PATH"/paperless-export-*.zip 2>/dev/null) + +if [ "${#BACKUPS[@]}" -gt "$BACKUP_KEEP_COUNT" ]; then + for ((i=BACKUP_KEEP_COUNT; i<${#BACKUPS[@]}; i++)); do + echo "[INFO] Deleting old backup: ${BACKUPS[i]}" + rm -f "${BACKUPS[i]}" + done +fi \ No newline at end of file diff --git a/paperless-ngx/translations/en.yaml b/paperless-ngx/translations/en.yaml index 205fe97..95c0ded 100644 --- a/paperless-ngx/translations/en.yaml +++ b/paperless-ngx/translations/en.yaml @@ -64,5 +64,17 @@ configuration: locales: name: Locales description: Your language (fr_FR, en_US, de_DE, etc) + backup_enabled: + name: Enable Backup + description: Enable or disable automatic backups + backup_path: + name: Backup Path + description: Path to store backups + backup_cron: + name: Backup Cron Schedule + description: Cron schedule for automatic backups + backup_keep_count: + name: Backup Keep Count + description: Number of backups to keep network: 80/tcp: Web interface (Not required for Ingress)