From 5ad8864e7bdaf185b6be05f71f940302c1224d1f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 25 Mar 2026 20:55:27 +0000 Subject: [PATCH 1/4] Initial plan From b5d6da277fcff44a2709f075fc40aa1fe80b5f83 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 25 Mar 2026 20:57:00 +0000 Subject: [PATCH 2/4] Add Dockerfile and Docker publish workflow for GHCR Co-authored-by: amitsaha <512598+amitsaha@users.noreply.github.com> Agent-Logs-Url: https://github.com/amitsaha/gitbackup/sessions/18bf06a1-3421-45a3-a73b-df4a1d29fd7d --- .github/workflows/docker-publish.yml | 45 ++++++++++++++++++++++++++++ Dockerfile | 16 ++++++++++ 2 files changed, 61 insertions(+) create mode 100644 .github/workflows/docker-publish.yml create mode 100644 Dockerfile diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml new file mode 100644 index 0000000..fa64aae --- /dev/null +++ b/.github/workflows/docker-publish.yml @@ -0,0 +1,45 @@ +name: Docker + +on: + release: + types: [published] + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build-and-push: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Log in to the Container registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} + + - name: Build and push Docker image + uses: docker/build-push-action@v6 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..02da9e2 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,16 @@ +FROM golang:1.25 AS builder + +WORKDIR /src + +COPY go.mod go.sum ./ +RUN go mod download + +COPY . . + +RUN CGO_ENABLED=0 go build -o /gitbackup . + +FROM gcr.io/distroless/static-debian12 + +COPY --from=builder /gitbackup /gitbackup + +ENTRYPOINT ["/gitbackup"] From 0091fc08aff767453b9a8b5ad7e8c3cc4c2b5167 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 25 Mar 2026 21:12:26 +0000 Subject: [PATCH 3/4] fix: use non-root user in Dockerfile; add Docker usage docs to README Co-authored-by: amitsaha <512598+amitsaha@users.noreply.github.com> Agent-Logs-Url: https://github.com/amitsaha/gitbackup/sessions/d0832656-ebd9-442d-b721-40da0fa8ac9a --- Dockerfile | 10 ++++++++- README.md | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 02da9e2..8ee90e9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,8 +9,16 @@ COPY . . RUN CGO_ENABLED=0 go build -o /gitbackup . -FROM gcr.io/distroless/static-debian12 +FROM debian:bookworm-slim + +RUN apt-get update \ + && apt-get install -y --no-install-recommends git ca-certificates \ + && rm -rf /var/lib/apt/lists/* \ + && groupadd -g 65532 nonroot \ + && useradd -r -u 65532 -g nonroot -d /home/nonroot -m nonroot COPY --from=builder /gitbackup /gitbackup +USER nonroot:nonroot + ENTRYPOINT ["/gitbackup"] diff --git a/README.md b/README.md index d229421..dd96017 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ Contact us for any custom on-prem or cloud deployment, new feature requests or e - [gitbackup - Backup your GitHub, GitLab, Bitbucket, and Forgejo repositories](#gitbackup---backup-your-github-gitlab-and-bitbucket-repositories) - [Introduction](#introduction) - [Installing `gitbackup`](#installing-gitbackup) + - [Docker image](#docker-image) - [Using `gitbackup`](#using-gitbackup) - [GitHub Specific oAuth App Flow](#github-specific-oauth-app-flow) - [OAuth Scopes/Permissions required](#oauth-scopespermissions-required) @@ -56,6 +57,66 @@ and architecture and copy the binary somewhere in your ``$PATH``. It is recommen If you are on MacOS, a community member has created a [Homebrew formula](https://formulae.brew.sh/formula/gitbackup). +### Docker image + +Docker images are published to [GitHub Container Registry](https://github.com/amitsaha/gitbackup/pkgs/container/gitbackup) on every release: + +```bash +docker pull ghcr.io/amitsaha/gitbackup: +``` + +Replace `` with the desired release tag (e.g. `0.9.1`). + +#### Running with a volume mount + +The container runs as a non-root user (`nonroot`, UID `65532`). You must ensure the backup directory on the host is writable by that UID before mounting it: + +```bash +mkdir -p /data/gitbackup +chown 65532:65532 /data/gitbackup +``` + +Then run the container, mounting the directory as the backup target: + +```bash +docker run --rm \ + -e GITHUB_TOKEN= \ + -v /data/gitbackup:/backup \ + ghcr.io/amitsaha/gitbackup: \ + -service github -backupdir /backup +``` + +#### HTTPS cloning (recommended in containers) + +By default `gitbackup` clones repositories over SSH, which requires access to an SSH key and a populated `known_hosts` file inside the container. The simpler alternative is to use HTTPS cloning via the `-use-https-clone` flag — no SSH keys are required: + +```bash +docker run --rm \ + -e GITHUB_TOKEN= \ + -v /data/gitbackup:/backup \ + ghcr.io/amitsaha/gitbackup: \ + -service github -backupdir /backup -use-https-clone +``` + +#### SSH cloning + +If you need SSH cloning, mount your private key and `known_hosts` into the container user's home directory. Because the container user is `nonroot` (UID `65532`), ensure the key file is readable by that UID: + +```bash +# Make a copy of the key owned by UID 65532 +cp $HOME/.ssh/id_rsa /tmp/gitbackup_id_rsa +chown 65532 /tmp/gitbackup_id_rsa +chmod 600 /tmp/gitbackup_id_rsa + +docker run --rm \ + -e GITHUB_TOKEN= \ + -v /data/gitbackup:/backup \ + -v /tmp/gitbackup_id_rsa:/home/nonroot/.ssh/id_rsa:ro \ + -v $HOME/.ssh/known_hosts:/home/nonroot/.ssh/known_hosts:ro \ + ghcr.io/amitsaha/gitbackup: \ + -service github -backupdir /backup +``` + ## Using `gitbackup` ``gitbackup`` requires a [GitHub API access token](https://github.com/blog/1509-personal-api-tokens) for From 3bd6c035f2018855ffd28a91628fff7eea1fe1cb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 25 Mar 2026 21:16:30 +0000 Subject: [PATCH 4/4] docs: add per-platform Docker usage section (Linux, macOS, Windows) Co-authored-by: amitsaha <512598+amitsaha@users.noreply.github.com> Agent-Logs-Url: https://github.com/amitsaha/gitbackup/sessions/d9a5d8e9-a12f-49d2-969c-9738801e5eea --- README.md | 68 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 57 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index dd96017..1fb7fcb 100644 --- a/README.md +++ b/README.md @@ -67,56 +67,102 @@ docker pull ghcr.io/amitsaha/gitbackup: Replace `` with the desired release tag (e.g. `0.9.1`). -#### Running with a volume mount +The container runs as a non-root user (`nonroot`, UID `65532`). HTTPS cloning (`-use-https-clone`) is recommended inside containers because it requires no SSH key management. -The container runs as a non-root user (`nonroot`, UID `65532`). You must ensure the backup directory on the host is writable by that UID before mounting it: +#### Linux + +On Linux, Docker runs natively so container UIDs map directly to host UIDs. Before mounting a backup directory, grant write access to UID `65532`: ```bash mkdir -p /data/gitbackup chown 65532:65532 /data/gitbackup ``` -Then run the container, mounting the directory as the backup target: +Run with HTTPS cloning (recommended): + +```bash +docker run --rm \ + -e GITHUB_TOKEN= \ + -v /data/gitbackup:/backup \ + ghcr.io/amitsaha/gitbackup: \ + -service github -backupdir /backup -use-https-clone +``` + +If you need SSH cloning, make a copy of your private key readable by UID `65532` and mount it: ```bash +cp $HOME/.ssh/id_rsa /tmp/gitbackup_id_rsa +chown 65532 /tmp/gitbackup_id_rsa +chmod 600 /tmp/gitbackup_id_rsa + docker run --rm \ -e GITHUB_TOKEN= \ -v /data/gitbackup:/backup \ + -v /tmp/gitbackup_id_rsa:/home/nonroot/.ssh/id_rsa:ro \ + -v $HOME/.ssh/known_hosts:/home/nonroot/.ssh/known_hosts:ro \ ghcr.io/amitsaha/gitbackup: \ -service github -backupdir /backup ``` -#### HTTPS cloning (recommended in containers) +#### macOS -By default `gitbackup` clones repositories over SSH, which requires access to an SSH key and a populated `known_hosts` file inside the container. The simpler alternative is to use HTTPS cloning via the `-use-https-clone` flag — no SSH keys are required: +Docker Desktop for Mac runs containers inside a Linux VM and translates volume mounts through its filesystem layer (VirtioFS). Because of this translation, the container UID (`65532`) is mapped automatically — you do **not** need to `chown` the host directory. Paths use the same Unix syntax as Linux. ```bash +mkdir -p $HOME/gitbackup + docker run --rm \ -e GITHUB_TOKEN= \ - -v /data/gitbackup:/backup \ + -v $HOME/gitbackup:/backup \ ghcr.io/amitsaha/gitbackup: \ -service github -backupdir /backup -use-https-clone ``` -#### SSH cloning - -If you need SSH cloning, mount your private key and `known_hosts` into the container user's home directory. Because the container user is `nonroot` (UID `65532`), ensure the key file is readable by that UID: +SSH cloning on macOS requires the same key-ownership step as Linux. Although VirtioFS handles write permissions for the backup directory automatically, `git` performs a strict ownership check on the SSH private key inside the container — the key file must be owned by the user running inside the container (UID `65532`). Host UIDs on macOS are unrelated to container UIDs, so the ownership must be set explicitly on a copy of the key: ```bash -# Make a copy of the key owned by UID 65532 cp $HOME/.ssh/id_rsa /tmp/gitbackup_id_rsa chown 65532 /tmp/gitbackup_id_rsa chmod 600 /tmp/gitbackup_id_rsa docker run --rm \ -e GITHUB_TOKEN= \ - -v /data/gitbackup:/backup \ + -v $HOME/gitbackup:/backup \ -v /tmp/gitbackup_id_rsa:/home/nonroot/.ssh/id_rsa:ro \ -v $HOME/.ssh/known_hosts:/home/nonroot/.ssh/known_hosts:ro \ ghcr.io/amitsaha/gitbackup: \ -service github -backupdir /backup ``` +#### Windows + +Docker Desktop for Windows (WSL2 backend recommended) translates volume mounts through the WSL2 VM, so no `chown` is needed on the host directory. Use PowerShell syntax for environment variables and paths: + +```powershell +# PowerShell +New-Item -ItemType Directory -Force "$env:USERPROFILE\gitbackup" + +docker run --rm ` + -e GITHUB_TOKEN=$env:GITHUB_TOKEN ` + -v "${env:USERPROFILE}\gitbackup:/backup" ` + ghcr.io/amitsaha/gitbackup: ` + -service github -backupdir /backup -use-https-clone +``` + +If you prefer Command Prompt: + +```cmd +mkdir %USERPROFILE%\gitbackup + +docker run --rm ^ + -e GITHUB_TOKEN=%GITHUB_TOKEN% ^ + -v "%USERPROFILE%\gitbackup:/backup" ^ + ghcr.io/amitsaha/gitbackup: ^ + -service github -backupdir /backup -use-https-clone +``` + +SSH cloning on Windows requires your SSH key to be accessible from WSL2 or Docker Desktop. The recommended approach is to store your key under WSL2 and mount it using a WSL path, or use HTTPS cloning to avoid SSH key management altogether. + ## Using `gitbackup` ``gitbackup`` requires a [GitHub API access token](https://github.com/blog/1509-personal-api-tokens) for