Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
164 changes: 164 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
name: build

on:
pull_request:
branches: [master]
push:
branches: [master]
schedule:
- cron: '0 0 * * 0' # weekly
workflow_dispatch:

env:
REGISTRY_DOCKER: docker.io
REGISTRY_GHCR: ghcr.io
IMAGE_NAME_DOCKER: nold360/borgserver
IMAGE_NAME_GHCR: ghcr.io/nold360/borgserver

jobs:
build-arm64:
runs-on: ubuntu-24.04-arm
strategy:
fail-fast: false
matrix:
include:
- base: debian:trixie-slim
tags: |
trixie
latest
- base: debian:bookworm-slim
tags: |
bookworm
- base: debian:unstable-slim
tags: |
unstable

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: |
${{ env.REGISTRY_DOCKER }}/${{ env.IMAGE_NAME_DOCKER }}
${{ env.REGISTRY_GHCR }}/${{ env.IMAGE_NAME_GHCR }}
tags: ${{ matrix.tags }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Dry-run build
if: github.event_name == 'pull_request'
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/arm64
push: false
tags: ${{ steps.meta.outputs.tags }}
build-args: |
BASE_IMAGE=${{ matrix.base }}

- name: Login to Docker Hub
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

- name: Login to GHCR
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GH_PUSH_TOKEN }}

- name: Build and push
if: github.event_name != 'pull_request'
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
BASE_IMAGE=${{ matrix.base }}

build-amd64:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- base: debian:trixie-slim
tags: |
trixie
latest
- base: debian:bookworm-slim
tags: |
bookworm
- base: debian:unstable-slim
tags: |
unstable

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: |
${{ env.REGISTRY_DOCKER }}/${{ env.IMAGE_NAME_DOCKER }}
${{ env.REGISTRY_GHCR }}/${{ env.IMAGE_NAME_GHCR }}
tags: ${{ matrix.tags }}

- name: Set up QEMU
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Dry-run build
if: github.event_name == 'pull_request'
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64
push: false
tags: ${{ steps.meta.outputs.tags }}
build-args: |
BASE_IMAGE=${{ matrix.base }}

- name: Login to Docker Hub
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

- name: Login to GHCR
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GH_PUSH_TOKEN }}

- name: Build and push
if: github.event_name != 'pull_request'
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
BASE_IMAGE=${{ matrix.base }}


8 changes: 1 addition & 7 deletions .woodpecker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,7 @@ matrix:
include:
- BASE: unstable-slim
TAGS: '[ "unstable" ]'
PLATFORMS: linux/386,linux/amd64
- BASE: trixie-slim
TAGS: '[ "trixie", "1.4", "latest" ]'
PLATFORMS: linux/386,linux/amd64,linux/arm/v7,linux/arm64/v8
- BASE: bookworm-slim
TAGS: '[ "bookworm", "1.2", "oldstable" ]'
PLATFORMS: linux/386,linux/amd64,linux/arm/v7,linux/arm64/v8
PLATFORMS: linux/arm64/v8

variables:
- &build-settings
Expand Down
51 changes: 51 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

This is a Docker image for running a BorgBackup server. It builds a Debian-based container with openssh-daemon that accepts SSH key auth for borg clients. Each client SSH key in `/sshkeys/clients/` maps to a separate borg repository.

## Key Files

- `Dockerfile` - Builds the image from `debian:<version>-slim`, installs `borgbackup` + `openssh-server`
- `data/run.sh` - Entrypoint script: adjusts PUID/PGID, generates SSH host keys, imports client keys into `authorized_keys` with restricted `borg serve` commands, starts sshd
- `data/sshd_config` - Hardened SSH config: pubkey-only, no forwarding, no TTY, SFTP disabled
- `.woodpecker.yml` - CI pipeline using Woodpecker CI with Docker Buildx for multi-platform builds
- `docker-compose.yml` - Example compose file

## Architecture

The entrypoint (`run.sh`) works as follows:
1. Adjusts `borg` user/group IDs to match host PUID/PGID
2. Validates `/backup` and `/sshkeys` volumes exist and that at least one client key is present (sshd won't start otherwise)
3. Generates SSH host keys (ed25519, rsa) in `/sshkeys/host/` if missing
4. Iterates over files in `/sshkeys/clients/`, creating an `authorized_keys` entry per client with:
- `restrict` flag + `command=` wrapping a `borg serve --restrict-to-path` command
- If `BORG_ADMIN` is set, that client gets unrestricted access to all repos
- If `BORG_APPEND_ONLY=yes`, non-admin clients get `--append-only`
5. Starts `/usr/sbin/sshd -D -e`

## Environment Variables

| Variable | Default | Description |
|---|---|---|
| `BORG_APPEND_ONLY` | `no` | Restrict clients to append-only mode |
| `BORG_ADMIN` | unset | Client key name that gets full access to all repos |
| `BORG_SERVE_ARGS` | unset | Extra args passed to `borg serve` |
| `PUID` | `1000` | User ID for `borg` user |
| `PGID` | `1000` | Group ID for `borg` group |

## CI/CD

Built via Woodpecker CI (`.woodpecker.yml`). Matrix builds target:
- `unstable-slim` → `linux/arm64/v8` tag `unstable`

Builds publish to Docker Hub (`nold360/borgserver`) and GHCR (`ghcr.io/nold360/borgserver`).

## Building Locally

```bash
docker build -t borgserver:dev .
docker build --build-arg BASE_IMAGE=debian:trixie-slim -t borgserver:trixie .
```
Loading