├── .github ├── containerscan │ └── allowedlist.yaml ├── dependabot.yml ├── linters │ └── .jscpd.json ├── renovate.json └── workflows │ └── docker.image.yml ├── .hadolint.yaml ├── Dockerfile ├── Makefile ├── README.md ├── docker-compose-complex-example.yml ├── docker-compose-example.yml ├── hooks └── build └── run.sh /.github/containerscan/allowedlist.yaml: -------------------------------------------------------------------------------- 1 | # https://github.com/Azure/container-scan#ignoring-vulnerabilities 2 | general: 3 | vulnerabilities: 4 | - CVE-2022-30065 5 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: github-actions 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "04:00" 8 | reviewers: 9 | - "waja" 10 | pull-request-branch-name: 11 | separator: "-" 12 | open-pull-requests-limit: 10 13 | - package-ecosystem: docker 14 | directory: "/" 15 | schedule: 16 | interval: daily 17 | time: "04:00" 18 | target-branch: "master" 19 | reviewers: 20 | - "waja" 21 | pull-request-branch-name: 22 | separator: "-" 23 | open-pull-requests-limit: 10 24 | -------------------------------------------------------------------------------- /.github/linters/.jscpd.json: -------------------------------------------------------------------------------- 1 | { 2 | "threshold": 4, 3 | "ignore": [ 4 | "**/.github/workflows/docker.image.yml", 5 | "**/docker-compose-*-example.yml" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": ["config:recommended", "docker:pinDigests"], 4 | "packageRules": [ 5 | { "matchFileNames": [".github/workflows/**"], "pinDigests": false }, 6 | { 7 | "matchFileNames": ["**/docker-compose*-example.yml"], 8 | "pinDigests": false 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /.github/workflows/docker.image.yml: -------------------------------------------------------------------------------- 1 | name: Docker Image CI 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - $default-branch 8 | - development 9 | - master 10 | tags: 11 | - "*.*.*-*" 12 | # Run tests for any PRs 13 | pull_request: 14 | schedule: 15 | - cron: "43 10 * * 4" 16 | 17 | env: 18 | IMAGE_NAME: calcardbackup 19 | 20 | jobs: 21 | codespell: 22 | name: codespell 23 | strategy: 24 | fail-fast: false 25 | runs-on: ubuntu-latest 26 | steps: 27 | - name: Checkout 28 | uses: actions/checkout@v4 29 | - name: Codespell 30 | uses: codespell-project/actions-codespell@master 31 | with: 32 | ignore_words_list: ro,rw 33 | skip: .git 34 | check_filenames: true 35 | check_hidden: true 36 | super-linter: 37 | name: super-linter 38 | strategy: 39 | fail-fast: false 40 | runs-on: ubuntu-latest 41 | steps: 42 | - name: Checkout 43 | uses: actions/checkout@v4 44 | with: 45 | # super-linter needs the full git history to get the 46 | # list of files that changed across commits 47 | fetch-depth: 0 48 | - name: Lint Code Base 49 | uses: super-linter/super-linter@v7 50 | env: 51 | DEFAULT_BRANCH: master 52 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 53 | shiftleft: 54 | name: shiftleft 55 | strategy: 56 | fail-fast: false 57 | runs-on: ubuntu-latest 58 | steps: 59 | - uses: actions/checkout@v4 60 | - name: Perform ShiftLeft Scan 61 | uses: ShiftLeftSecurity/scan-action@master 62 | env: 63 | WORKSPACE: "" 64 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 65 | SCAN_AUTO_BUILD: true 66 | with: 67 | output: reports 68 | # Scan auto-detects the languages in your project. To override uncomment the below variable and set the type 69 | # type: credscan,java 70 | # type: python 71 | - name: Upload report 72 | uses: github/codeql-action/upload-sarif@v3 73 | with: 74 | sarif_file: reports 75 | test-build: 76 | needs: 77 | - codespell 78 | - super-linter 79 | - shiftleft 80 | strategy: 81 | fail-fast: false 82 | runs-on: ubuntu-latest 83 | steps: 84 | - uses: actions/checkout@v4 85 | - name: Set up QEMU 86 | uses: docker/setup-qemu-action@v3 87 | with: 88 | platforms: linux/amd64 89 | - name: Set up Docker Buildx 90 | id: buildx 91 | uses: docker/setup-buildx-action@v3 92 | with: 93 | driver-opts: network=host 94 | - name: Build the Docker image 95 | id: docker_test 96 | uses: docker/build-push-action@v6 97 | with: 98 | builder: ${{ steps.buildx.outputs.name }} 99 | push: false 100 | outputs: type=docker,dest=/tmp/${{ env.IMAGE_NAME }}-${{ github.run_number }}.tar 101 | tags: localhost:5000/foobar/${{ env.IMAGE_NAME }} 102 | cache-from: type=local,src=/tmp/.buildx-cache 103 | cache-to: type=local,dest=/tmp/.buildx-cache 104 | context: . 105 | file: ./Dockerfile 106 | platforms: linux/amd64 107 | build-args: | 108 | BUILD_DATE="$(date -u +'%Y-%m-%dT%H:%M:%SZ')" 109 | BUILD_VERSION="$(git describe --tags)" 110 | VCS_REF="$(git rev-parse --short HEAD)" 111 | VCS_URL="$(git config --get remote.origin.url)" 112 | VCS_BRANCH="$(git rev-parse --abbrev-ref HEAD)" 113 | - name: Upload artifact 114 | uses: actions/upload-artifact@v4 115 | with: 116 | name: ${{ env.IMAGE_NAME }}-${{ github.run_number }} 117 | path: /tmp/${{ env.IMAGE_NAME }}-${{ github.run_number }}.tar 118 | test: 119 | name: Run test 120 | needs: 121 | - test-build 122 | strategy: 123 | fail-fast: false 124 | runs-on: ubuntu-latest 125 | services: 126 | registry: 127 | image: registry:3 128 | ports: 129 | - 5000:5000 130 | steps: 131 | - name: Download artifact 132 | uses: actions/download-artifact@v4 133 | with: 134 | name: ${{ env.IMAGE_NAME }}-${{ github.run_number }} 135 | path: /tmp 136 | - name: Load image and push to local registry 137 | run: | 138 | docker load --input /tmp/${{ env.IMAGE_NAME }}-${{ github.run_number }}.tar 139 | docker image ls -a 140 | docker push localhost:5000/foobar/${{ env.IMAGE_NAME }} 141 | - name: Inspect the Docker image 142 | run: | 143 | docker buildx imagetools inspect localhost:5000/foobar/${{ env.IMAGE_NAME }} 144 | - name: Test the Docker image 145 | run: | 146 | CONTAINER_OUTPUT="$(docker run --rm -t localhost:5000/foobar/${{ env.IMAGE_NAME }} /opt/calcardbackup/calcardbackup -h)" 147 | # shellcheck disable=SC2086 148 | TEST_STRING="$(echo ${CONTAINER_OUTPUT} | grep -c 'START calcardbackup')" 149 | if ! [ "${TEST_STRING}" = "1" ]; then exit 1; fi 150 | dockle: 151 | name: Run Dockle tests 152 | needs: 153 | - test-build 154 | strategy: 155 | fail-fast: false 156 | runs-on: ubuntu-latest 157 | services: 158 | registry: 159 | image: registry:3 160 | ports: 161 | - 5000:5000 162 | steps: 163 | - name: Download artifact 164 | uses: actions/download-artifact@v4 165 | with: 166 | name: ${{ env.IMAGE_NAME }}-${{ github.run_number }} 167 | path: /tmp 168 | - name: Load image and push to local registry 169 | run: | 170 | docker load --input /tmp/${{ env.IMAGE_NAME }}-${{ github.run_number }}.tar 171 | docker image ls -a 172 | docker push localhost:5000/foobar/${{ env.IMAGE_NAME }} 173 | - name: Run dockle container image linter 174 | uses: goodwithtech/dockle-action@v0.4.15 175 | with: 176 | image: "registry:5000/foobar/${{ env.IMAGE_NAME }}" 177 | insecure: true 178 | format: "sarif" 179 | exit-code: "1" 180 | exit-level: "warn" 181 | ignore: "CIS-DI-0001,CIS-DI-0010,DKL-DI-0006" 182 | output: sarif-reports 183 | - name: Upload Reports 184 | uses: github/codeql-action/upload-sarif@v3 185 | with: 186 | sarif_file: "sarif-reports" 187 | trivy: 188 | name: Run Trivy tests 189 | needs: 190 | - test-build 191 | strategy: 192 | fail-fast: false 193 | runs-on: ubuntu-latest 194 | services: 195 | registry: 196 | image: registry:3 197 | ports: 198 | - 5000:5000 199 | steps: 200 | - name: Download artifact 201 | uses: actions/download-artifact@v4 202 | with: 203 | name: ${{ env.IMAGE_NAME }}-${{ github.run_number }} 204 | path: /tmp 205 | - name: Load image and push to local registry 206 | run: | 207 | docker load --input /tmp/${{ env.IMAGE_NAME }}-${{ github.run_number }}.tar 208 | docker image ls -a 209 | docker push localhost:5000/foobar/${{ env.IMAGE_NAME }} 210 | - name: Run Trivy vulnerability scanner 211 | uses: aquasecurity/trivy-action@master 212 | with: 213 | image-ref: localhost:5000/foobar/${{ env.IMAGE_NAME }} 214 | format: "template" 215 | template: "@/contrib/sarif.tpl" 216 | output: "trivy-results.sarif" 217 | severity: "CRITICAL,HIGH" 218 | - name: Upload Reports 219 | uses: github/codeql-action/upload-sarif@v3 220 | with: 221 | sarif_file: "trivy-results.sarif" 222 | anchore: 223 | name: Run Anchore tests 224 | needs: 225 | - test-build 226 | strategy: 227 | fail-fast: false 228 | runs-on: ubuntu-latest 229 | services: 230 | registry: 231 | image: registry:3 232 | ports: 233 | - 5000:5000 234 | steps: 235 | - name: Download artifact 236 | uses: actions/download-artifact@v4 237 | with: 238 | name: ${{ env.IMAGE_NAME }}-${{ github.run_number }} 239 | path: /tmp 240 | - name: Load image and push to local registry 241 | run: | 242 | docker load --input /tmp/${{ env.IMAGE_NAME }}-${{ github.run_number }}.tar 243 | docker image ls -a 244 | docker push localhost:5000/foobar/${{ env.IMAGE_NAME }} 245 | - name: Run the Anchore scan action itself with GitHub Advanced Security code scanning integration enabled 246 | uses: anchore/scan-action@main 247 | with: 248 | image: localhost:5000/foobar/${{ env.IMAGE_NAME }} 249 | acs-report-enable: true 250 | fail-build: false 251 | output-file: "./results.sarif" 252 | - name: Move reports 253 | run: mkdir -p sarif-reports && cp ./results.sarif ./sarif-reports/ 254 | - name: Upload Reports 255 | uses: github/codeql-action/upload-sarif@v3 256 | with: 257 | sarif_file: "sarif-reports" 258 | release-docker: 259 | name: Release Docker images 260 | needs: 261 | - test 262 | - dockle 263 | - trivy 264 | - anchore 265 | strategy: 266 | fail-fast: false 267 | runs-on: ubuntu-latest 268 | steps: 269 | - name: Checkout 270 | uses: actions/checkout@v4 271 | 272 | - name: Prepare 273 | id: prep 274 | env: 275 | DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} 276 | DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} 277 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 278 | QUAY_USERNAME: ${{ secrets.QUAY_USERNAME }} 279 | QUAY_TOKEN: ${{ secrets.QUAY_TOKEN }} 280 | run: | 281 | USER="${GITHUB_REPOSITORY_OWNER}" 282 | IMAGE_NAME="$(echo '${{ github.repository }}' | awk -F '/' '{print $2}' | sed s/docker-//)" 283 | DOCKER_IMAGE="${USER}/${IMAGE_NAME}" 284 | VERSION=edge 285 | # running on a tag 286 | if [[ $GITHUB_REF == refs/tags/* ]]; then 287 | VERSION="${GITHUB_REF#refs/tags/}" 288 | fi 289 | # running on a branch 290 | if [[ "$GITHUB_REF" == refs/heads/* ]]; then 291 | VERSION="${GITHUB_REF#refs/heads/}" 292 | fi 293 | # running on schedule 294 | # shellcheck disable=SC2050 295 | if [ "${{ github.event_name }}" = "schedule" ]; then 296 | VERSION=nightly 297 | fi 298 | # running on master branch 299 | if [ "$VERSION" = "master" ]; then 300 | VERSION=latest 301 | fi 302 | TAGS="${DOCKER_IMAGE}:${VERSION}" 303 | if [[ "$VERSION" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\-[0-9]{1,3}$ ]]; then 304 | REALEASE_TAG=true 305 | fi 306 | TAGS_INT="$TAGS" 307 | TAGS="" 308 | if [ "$DOCKERHUB_USERNAME" != '' ] && [ "$DOCKERHUB_TOKEN" != '' ]; then 309 | if [ "$REALEASE_TAG" = "true" ]; then 310 | TAGS="$TAGS_INT,${DOCKER_IMAGE}:latest" 311 | else 312 | TAGS="$TAGS_INT" 313 | fi 314 | fi 315 | if [ "$GITHUB_TOKEN" != '' ]; then 316 | if [ "$REALEASE_TAG" = "true" ]; then 317 | TAGS="$TAGS,ghcr.io/$TAGS_INT,ghcr.io/${DOCKER_IMAGE}:latest" 318 | else 319 | TAGS="$TAGS,ghcr.io/$TAGS_INT" 320 | fi 321 | fi 322 | if [ "$QUAY_USERNAME" != '' ] && [ "$QUAY_TOKEN" != '' ]; then 323 | if [ "$REALEASE_TAG" = "true" ]; then 324 | TAGS="$TAGS,quay.io/$TAGS_INT,quay.io/${DOCKER_IMAGE}:latest" 325 | else 326 | TAGS="$TAGS,quay.io/$TAGS_INT" 327 | fi 328 | fi 329 | echo "tags=${TAGS}" >> "$GITHUB_OUTPUT" 330 | 331 | - name: Download artifact 332 | uses: actions/download-artifact@v4 333 | with: 334 | name: ${{ env.IMAGE_NAME }}-${{ github.run_number }} 335 | path: /tmp 336 | 337 | - name: Load image from test job 338 | run: | 339 | docker load --input /tmp/${{ env.IMAGE_NAME }}-${{ github.run_number }}.tar 340 | 341 | - name: Set up QEMU 342 | uses: docker/setup-qemu-action@v3 343 | with: 344 | platforms: all 345 | 346 | - name: Set up Docker Buildx 347 | id: buildx 348 | uses: docker/setup-buildx-action@v3 349 | 350 | - name: Cache Docker layers 351 | uses: actions/cache@v4 352 | with: 353 | path: /tmp/.buildx-cache 354 | key: ${{ runner.os }}-buildx-${{ github.sha }} 355 | restore-keys: | 356 | ${{ runner.os }}-buildx- 357 | 358 | - name: Login to ghcr 359 | env: 360 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 361 | if: ${{ github.event_name != 'pull_request' && env.GITHUB_TOKEN != '' }} 362 | uses: docker/login-action@v3 363 | with: 364 | registry: ghcr.io 365 | username: ${USER} 366 | password: ${{ env.GITHUB_TOKEN }} 367 | 368 | - name: Login to DockerHub Container Registry 369 | env: 370 | DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} 371 | DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} 372 | if: ${{ github.event_name != 'pull_request' && env.DOCKERHUB_USERNAME != '' && env.DOCKERHUB_TOKEN != '' }} 373 | uses: docker/login-action@v3 374 | with: 375 | username: ${{ env.DOCKERHUB_USERNAME }} 376 | password: ${{ env.DOCKERHUB_TOKEN }} 377 | 378 | - name: Login to Quay Container Registry 379 | env: 380 | QUAY_USERNAME: ${{ secrets.QUAY_USERNAME }} 381 | QUAY_TOKEN: ${{ secrets.QUAY_TOKEN }} 382 | if: ${{ github.event_name != 'pull_request' && env.QUAY_USERNAME != '' && env.QUAY_TOKEN != '' }} 383 | uses: docker/login-action@v3 384 | with: 385 | registry: quay.io 386 | username: ${{ env.QUAY_USERNAME }} 387 | password: ${{ env.QUAY_TOKEN }} 388 | 389 | - name: Test 390 | id: docker_test 391 | uses: docker/build-push-action@v6 392 | with: 393 | builder: ${{ steps.buildx.outputs.name }} 394 | context: . 395 | file: ./Dockerfile 396 | platforms: linux/amd64 397 | build-args: | 398 | BUILD_DATE="$(date -u +'%Y-%m-%dT%H:%M:%SZ')" 399 | BUILD_VERSION="$(git describe --tags)" 400 | VCS_REF="$(git rev-parse --short HEAD)" 401 | VCS_URL="$(git config --get remote.origin.url)" 402 | VCS_BRANCH="$(git rev-parse --abbrev-ref HEAD)" 403 | 404 | - name: Build and push 405 | id: docker_build 406 | uses: docker/build-push-action@v6 407 | with: 408 | builder: ${{ steps.buildx.outputs.name }} 409 | context: . 410 | file: ./Dockerfile 411 | platforms: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64 412 | push: ${{ github.event_name != 'pull_request' }} 413 | tags: | 414 | ${{ steps.prep.outputs.tags }} 415 | cache-from: type=local,src=/tmp/.buildx-cache 416 | cache-to: type=local,dest=/tmp/.buildx-cache 417 | build-args: | 418 | BUILD_DATE="$(date -u +'%Y-%m-%dT%H:%M:%SZ')" 419 | BUILD_VERSION="$(git describe --tags)" 420 | VCS_REF="$(git rev-parse --short HEAD)" 421 | VCS_URL="$(git config --get remote.origin.url)" 422 | VCS_BRANCH="$(git rev-parse --abbrev-ref HEAD)" 423 | 424 | - name: Image digest 425 | run: echo ${{ steps.docker_build.outputs.digest }} 426 | -------------------------------------------------------------------------------- /.hadolint.yaml: -------------------------------------------------------------------------------- 1 | ignored: 2 | - DL3017 3 | - DL3018 4 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax = docker/dockerfile:1@sha256:9857836c9ee4268391bb5b09f9f157f3c91bb15821bb77969642813b0d00518d 2 | # requires DOCKER_BUILDKIT=1 set when running docker build 3 | # checkov:skip=CKV_DOCKER_2: no healthcheck (yet) 4 | # checkov:skip=CKV_DOCKER_3: no user (yet) 5 | FROM alpine:3.22.0@sha256:8a1f59ffb675680d47db6337b49d22281a139e9d709335b492be023728e11715 6 | 7 | ARG BUILD_DATE 8 | ARG BUILD_VERSION 9 | ARG VCS_URL 10 | ARG VCS_REF 11 | ARG VCS_BRANCH 12 | 13 | ENV GIT_PROJECT=BernieO/calcardbackup 14 | ENV CALCARDBACKUP_VERSION 8.2.0 15 | 16 | # See http://label-schema.org/rc1/ and https://microbadger.com/labels 17 | LABEL maintainer="Jan Wagner " \ 18 | org.label-schema.name="calcardbackup - ownCloud/Nextcloud backup tool" \ 19 | org.label-schema.description="backup calendars and addressbooks from a local ownCloud/Nextcloud installation on Alpine Linux based container" \ 20 | org.label-schema.vendor="Cyconet" \ 21 | org.label-schema.schema-version="1.0" \ 22 | org.label-schema.build-date="${BUILD_DATE:-unknown}" \ 23 | org.label-schema.version="${BUILD_VERSION:-unknown}" \ 24 | org.label-schema.vcs-url="${VCS_URL:-unknown}" \ 25 | org.label-schema.vcs-ref="${VCS_REF:-unknown}" \ 26 | org.label-schema.vcs-branch="${VCS_BRANCH:-unknown}" \ 27 | org.opencontainers.image.source="https://github.com/waja/docker-calcardbackup" 28 | 29 | COPY ["run.sh", "/"] 30 | 31 | # hadolint ignore=DL3017,DL3018 32 | RUN apk --no-cache update && apk --no-cache upgrade && \ 33 | # Install dependencies 34 | apk --no-cache add --virtual build-dependencies ca-certificates tar curl jq && \ 35 | # Create directory 36 | mkdir -p /opt/calcardbackup 37 | WORKDIR /opt/calcardbackup 38 | # Download latest release 39 | SHELL ["/bin/ash", "-eo", "pipefail", "-c"] 40 | # hadolint ignore=DL3017,DL3018 41 | RUN curl -L "https://codeberg.org/BernieO/calcardbackup/archive/v$CALCARDBACKUP_VERSION.tar.gz" | tar xz --strip=1 && \ 42 | # Remove build deps 43 | apk del build-dependencies && \ 44 | # Install needed packages 45 | apk --no-cache add bash curl findutils mysql-client postgresql-client sqlite gzip zip gnupg && \ 46 | # Create backup dir and make our start script executable 47 | mkdir /backup 48 | 49 | VOLUME ["/backup"] 50 | 51 | CMD ["/run.sh"] 52 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | IMAGE_NAME := waja/calcardbackup 2 | 3 | build: 4 | docker build --rm -t $(IMAGE_NAME) . 5 | 6 | run: 7 | @echo docker run --rm -it $(IMAGE_NAME) 8 | 9 | shell: 10 | docker run --rm -it --entrypoint sh $(IMAGE_NAME) -l 11 | 12 | test: build 13 | @if ! [ "$$(docker run --rm -it $(IMAGE_NAME) /opt/calcardbackup/calcardbackup -h | grep 'START calcardbackup' | sed 's/.* START //' | sed 's/ ver\..*//')" = "calcardbackup" ]; then exit 1; fi 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Docker-Calcardbackup 4 | 5 | [![](https://images.microbadger.com/badges/version/waja/calcardbackup.svg)](https://hub.docker.com/r/waja/calcardbackup/) 6 | [![](https://images.microbadger.com/badges/image/waja/calcardbackup.svg)](https://hub.docker.com/r/waja/calcardbackup/) 7 | [![Build Status](https://travis-ci.org/Cyconet/docker-calcardbackup.svg?branch=development)](https://travis-ci.org/Cyconet/docker-calcardbackup) 8 | [![Docker Build Status](https://img.shields.io/docker/build/waja/calcardbackup.svg)](https://hub.docker.com/r/waja/calcardbackup/) 9 | [![GitHub tag](https://img.shields.io/github/tag/Cyconet/docker-calcardbackup.svg)](https://github.com/Cyconet/docker-calcardbackup/tags) 10 | [![](https://img.shields.io/docker/pulls/waja/calcardbackup.svg)](https://hub.docker.com/r/waja/calcardbackup/) 11 | [![](https://img.shields.io/docker/stars/waja/calcardbackup.svg)](https://hub.docker.com/r/waja/calcardbackup/) 12 | [![](https://img.shields.io/docker/automated/waja/calcardbackup.svg)](https://hub.docker.com/r/waja/calcardbackup/) 13 | 14 | ## Usage 15 | 16 | 17 | 18 | docker container run -d \ 19 | --link mysql 20 | --volume /path/to/my/backup/folder:/backup 21 | --volume /path/to/my/nextcloud/config:/nextcloud/config 22 | waja/calcardbackup 23 | 24 | 25 | 26 | ## docker compose 27 | 28 | There is a [`docker-compose-example.yml`](https://raw.githubusercontent.com/waja/docker-calcardbackup/development/docker-compose-example.yml) and a [`docker-compose-complex-example.yml`](https://raw.githubusercontent.com/waja/docker-calcardbackup/development/docker-compose-complex-example.yml) available. Feel free to have a look if there is something you can use. 29 | 30 | ## Variables 31 | 32 | CRON_TIME the interval of cron job to run mysqldump. `5 4 * * *` by default, which is every day at 04:05 (optional) 33 | INIT_BACKUP if set, create a backup when the container starts (optional) 34 | BACKUP_DIR location where the backup should be stored (optional) 35 | NC_DIR location where Nextcloud config/config.php is searched for (optional) 36 | NC_HOST hostname Nextcloud webinterface running on (optional) 37 | NC_PORT port Nextcloud webinterface running on (optional) 38 | DB_HOST hostname database running on (optional) 39 | DB_PORT port database running on (optional) 40 | CALCARD_OPTS options passed to calcardbackup (optional) 41 | MARIADB_SSL_SKIP set to 'true' to prevent mariadb client force to use SSL 42 | -------------------------------------------------------------------------------- /docker-compose-complex-example.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | nextcloud: 5 | image: ghcr.io/hoellen/nextcloud:31 6 | labels: 7 | - com.centurylinklabs.watchtower.enable=true 8 | - traefik.enable=true 9 | - traefik.backend=nextcloud 10 | - traefik.frontend.rule=Host:nextcloud.test.org 11 | - traefik.docker.network=traefik_default 12 | - traefik.port=8888 13 | - traefik.default.protocol=http 14 | - "traefik.frontend.redirect.regex=^(.*)/.well-known/webfinger" 15 | - "traefik.frontend.redirect.replacement=$$1/public.php?service=webfinger" 16 | links: 17 | - nextcloud-db:nextcloud-db 18 | - nextcloud-redis:nextcloud-redis 19 | environment: 20 | - UID=1000 21 | - GID=1000 22 | - UPLOAD_MAX_SIZE=10G 23 | - APC_SHM_SIZE=128M 24 | - OPCACHE_MEM_SIZE=128 25 | - CRON_PERIOD=15m 26 | - TZ=Europe/Berlin 27 | - DOMAIN=nextcloud.test.org 28 | - DB_TYPE=mysql 29 | - DB_NAME=nextcloud 30 | - DB_USER=nextcloud 31 | - DB_PASSWORD=YOUSHOULDHAVECHANGEDTHAT 32 | - DB_HOST=nextcloud-db 33 | - CHECK_PERMISSIONS=1 34 | depends_on: 35 | - nextcloud-db 36 | - nextcloud-redis 37 | networks: 38 | - default 39 | - traefik_default 40 | restart: unless-stopped 41 | volumes: 42 | - ./data:/data 43 | - ./config:/config 44 | - ./apps:/apps2 45 | - ./themes:/nextcloud/themes 46 | - /etc/localtime:/etc/localtime:ro 47 | - /etc/timezone:/etc/timezone:ro 48 | 49 | nextcloud-db: 50 | image: mariadb:11.7 51 | labels: 52 | com.centurylinklabs.watchtower.enable: "true" 53 | environment: 54 | - MYSQL_ROOT_PASSWORD=YOUSHOULDHAVECHANGEDTHATTOO 55 | - MYSQL_DATABASE=nextcloud 56 | - MYSQL_USER=nextcloud 57 | - MYSQL_PASSWORD=YOUSHOULDHAVECHANGEDTHAT 58 | restart: unless-stopped 59 | volumes: 60 | - ./mysql:/var/lib/mysql 61 | - /etc/localtime:/etc/localtime:ro 62 | - /etc/timezone:/etc/timezone:ro 63 | 64 | nextcloud-redis: 65 | image: redis:8.0-alpine 66 | labels: 67 | com.centurylinklabs.watchtower.enable: "true" 68 | restart: unless-stopped 69 | volumes: 70 | - ./redis:/data 71 | - /etc/localtime:/etc/localtime:ro 72 | - /etc/timezone:/etc/timezone:ro 73 | 74 | nextcloud-db-backup: 75 | image: fradelg/mysql-cron-backup 76 | labels: 77 | com.centurylinklabs.watchtower.enable: "true" 78 | links: 79 | - nextcloud-db:nextcloud-db 80 | environment: 81 | - MYSQL_HOST=nextcloud-db 82 | - MYSQL_USER=nextcloud 83 | - MYSQL_PASS=YOUSHOULDHAVECHANGEDTHAT 84 | - MAX_BACKUPS=20 85 | - CRON_TIME=0 0 * * * 86 | depends_on: 87 | - nextcloud-db 88 | restart: unless-stopped 89 | volumes: 90 | - ./mysql-backups:/backup 91 | - /etc/localtime:/etc/localtime:ro 92 | - /etc/timezone:/etc/timezone:ro 93 | 94 | nextcloud-nc-backup: 95 | image: waja/calcardbackup 96 | labels: 97 | com.centurylinklabs.watchtower.enable: "true" 98 | links: 99 | - nextcloud-db:nextcloud-db 100 | - nextcloud:nextcloud 101 | environment: 102 | - CRON_TIME=0 0 * * * 103 | - INIT_BACKUP=yes 104 | - CALCARD_OPTS=-i -r 20 105 | - NC_DIR=/nextcloud 106 | - NC_HOST=nextcloud 107 | - NC_PORT=8888 108 | - DB_HOST=nextcloud-db 109 | depends_on: 110 | - nextcloud-db 111 | - nextcloud 112 | restart: unless-stopped 113 | volumes: 114 | - ./calcardbackup:/backup 115 | - ./config:/nextcloud/config 116 | - /etc/localtime:/etc/localtime:ro 117 | - /etc/timezone:/etc/timezone:ro 118 | 119 | networks: 120 | traefik_default: 121 | external: true 122 | -------------------------------------------------------------------------------- /docker-compose-example.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | nextcloud: 5 | image: ghcr.io/hoellen/nextcloud:31 6 | restart: unless-stopped 7 | volumes: 8 | - ./data:/data 9 | - ./config:/config 10 | - ./apps:/apps2 11 | - ./themes:/nextcloud/themes 12 | - /etc/localtime:/etc/localtime:ro 13 | - /etc/timezone:/etc/timezone:ro 14 | 15 | nextcloud-db: 16 | image: mariadb:11.7 17 | environment: 18 | - MYSQL_ROOT_PASSWORD=YOUSHOULDHAVECHANGEDTHATTOO 19 | - MYSQL_DATABASE=nextcloud 20 | - MYSQL_USER=nextcloud 21 | - MYSQL_PASSWORD=YOUSHOULDHAVECHANGEDTHAT 22 | restart: unless-stopped 23 | volumes: 24 | - ./mysql:/var/lib/mysql 25 | - /etc/localtime:/etc/localtime:ro 26 | - /etc/timezone:/etc/timezone:ro 27 | 28 | nextcloud-nc-backup: 29 | image: waja/calcardbackup 30 | links: 31 | - nextcloud-db:nextcloud-db 32 | - nextcloud:nextcloud 33 | environment: 34 | - CRON_TIME=0 0 * * * 35 | - INIT_BACKUP=yes 36 | - CALCARD_OPTS=-i -r 20 37 | - NC_DIR=/nextcloud 38 | - NC_HOST=nextcloud 39 | - NC_PORT=8888 40 | - DB_HOST=nextcloud-db 41 | depends_on: 42 | - nextcloud-db 43 | - nextcloud 44 | restart: unless-stopped 45 | volumes: 46 | - ./calcardbackup:/backup 47 | - ./config:/nextcloud/config 48 | - /etc/localtime:/etc/localtime:ro 49 | - /etc/timezone:/etc/timezone:ro 50 | -------------------------------------------------------------------------------- /hooks/build: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # File needs to be called /hooks/build relative to the Dockerfile. 4 | # $IMAGE_NAME var is injected into the build so the tag is correct. 5 | # See https://gist.github.com/rossf7/664dc1eb02f514993c7215d37058965c and 6 | # https://docs.docker.com/docker-cloud/builds/advanced/ 7 | 8 | echo "Build hook running" 9 | docker build --build-arg BUILD_DATE="$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \ 10 | --build-arg BUILD_VERSION="$(git describe --tags)" \ 11 | --build-arg VCS_REF="$(git rev-parse --short HEAD)" \ 12 | --build-arg VCS_URL="$(git config --get remote.origin.url)" \ 13 | --build-arg VCS_BRANCH="$(git rev-parse --abbrev-ref HEAD)" \ 14 | -t "$IMAGE_NAME" . 15 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [ "${MARIADB_SSL_SKIP:=false}" == "true" ]; then 3 | cat >/etc/my.cnf.d/mariadb-client.cnf < Create a backup on the startup" 16 | if [ -n "${NC_HOST}" ]; then 17 | until nc -z "${NC_HOST}" "${NC_PORT:=443}"; do 18 | echo "waiting for Nextcloud webinterface ..." 19 | sleep 1 20 | done 21 | fi 22 | if [ -n "${DB_HOST}" ]; then 23 | until nc -z "${DB_HOST}" "${DB_PORT:=3306}"; do 24 | echo "waiting for database container ..." 25 | sleep 1 26 | done 27 | fi 28 | ${BACKUP_CMD} >>${BACKUP_LOG} 2>&1 29 | fi 30 | 31 | echo "${CRON_TIME:=5 4 * * *} ${BACKUP_CMD} >> ${BACKUP_LOG} 2>&1" >/crontab.conf 32 | crontab /crontab.conf 33 | echo "=> Running cron task manager" 34 | exec crond -f 35 | --------------------------------------------------------------------------------