├── .github └── workflows │ └── docker-publish.yml ├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── build.sh ├── data └── example-config │ ├── dav_svn.authz │ └── dav_svn.passwd ├── docker-compose.yml ├── files ├── dav_svn.conf ├── svn-backuper.sh ├── svn-entrypoint.sh └── svn-project-creator.sh └── get-version.sh /.github/workflows/docker-publish.yml: -------------------------------------------------------------------------------- 1 | name: Docker 2 | 3 | # This workflow uses actions that are not certified by GitHub. 4 | # They are provided by a third-party and are governed by 5 | # separate terms of service, privacy policy, and support 6 | # documentation. 7 | 8 | on: 9 | schedule: 10 | - cron: '0 0 * * 0' # weekly 11 | push: 12 | branches: [ "master" ] 13 | # Publish semver tags as releases. 14 | tags: [ 'v*.*.*' ] 15 | pull_request: 16 | branches: [ "master" ] 17 | 18 | env: 19 | # Use docker.io for Docker Hub if empty 20 | REGISTRY: ghcr.io 21 | # github.repository as / 22 | IMAGE_NAME: MarvAmBass/subversion 23 | 24 | 25 | jobs: 26 | build: 27 | 28 | runs-on: ubuntu-latest 29 | permissions: 30 | contents: read 31 | packages: write 32 | # This is used to complete the identity challenge 33 | # with sigstore/fulcio when running outside of PRs. 34 | id-token: write 35 | 36 | steps: 37 | - name: Checkout repository 38 | uses: actions/checkout@v3 39 | 40 | # Install the cosign tool except on PR 41 | # https://github.com/sigstore/cosign-installer 42 | - name: Install cosign 43 | if: github.event_name != 'pull_request' 44 | uses: sigstore/cosign-installer@f3c664df7af409cb4873aa5068053ba9d61a57b6 #v2.6.0 45 | with: 46 | cosign-release: 'v1.13.1' 47 | 48 | 49 | # Workaround: https://github.com/docker/build-push-action/issues/461 50 | - name: Setup Docker buildx 51 | uses: docker/setup-buildx-action@79abd3f86f79a9d68a23c75a09a9a85889262adf 52 | 53 | # Login against a Docker registry except on PR 54 | # https://github.com/docker/login-action 55 | - name: Log into registry ${{ env.REGISTRY }} 56 | if: github.event_name != 'pull_request' 57 | uses: docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336c 58 | with: 59 | registry: ${{ env.REGISTRY }} 60 | username: ${{ github.actor }} 61 | password: ${{ secrets.GITHUB_TOKEN }} 62 | 63 | # Extract metadata (tags, labels) for Docker 64 | # https://github.com/docker/metadata-action 65 | - name: Extract Docker metadata 66 | id: meta 67 | uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 68 | with: 69 | images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} 70 | 71 | - name: Extract Docker Version Tag 72 | id: docker_version_tag 73 | run: | 74 | ./get-version.sh $(echo "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:" | tr '[:upper:]' '[:lower:]') | sed 's/^/tag=/g' >> $GITHUB_OUTPUT 75 | 76 | # Build and push Docker image with Buildx (don't push on PR) 77 | # https://github.com/docker/build-push-action 78 | - name: Build and push Docker image 79 | id: build-and-push 80 | uses: docker/build-push-action@ac9327eae2b366085ac7f6a2d02df8aa8ead720a 81 | with: 82 | context: . 83 | push: ${{ github.event_name != 'pull_request' }} 84 | tags: ${{ steps.docker_version_tag.outputs.tag }} 85 | platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6 86 | labels: ${{ steps.meta.outputs.labels }} 87 | cache-from: type=gha 88 | cache-to: type=gha,mode=max 89 | 90 | 91 | # Sign the resulting Docker image digest except on PRs. 92 | # This will only write to the public Rekor transparency log when the Docker 93 | # repository is public to avoid leaking data. If you would like to publish 94 | # transparency data even for private images, pass --force to cosign below. 95 | # https://github.com/sigstore/cosign 96 | - name: Sign the published Docker image 97 | if: ${{ github.event_name != 'pull_request' }} 98 | env: 99 | COSIGN_EXPERIMENTAL: "true" 100 | # This step uses the identity token to provision an ephemeral certificate 101 | # against the sigstore community Fulcio instance. 102 | run: echo "${{ steps.meta.outputs.tags }}" | xargs -I {} cosign sign {}@${{ steps.build-and-push.outputs.digest }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | data/data -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/servercontainers/apache2-ssl-secure 2 | 3 | ENV LANG C.UTF-8 4 | 5 | RUN apt-get update && apt-get install -y \ 6 | subversion \ 7 | libapache2-mod-svn 8 | 9 | RUN a2enmod dav_svn 10 | RUN a2enmod auth_digest 11 | 12 | RUN mkdir /var/svn-backup 13 | RUN mkdir -p /var/local/svn 14 | RUN mkdir /etc/apache2/dav_svn 15 | 16 | ADD files/dav_svn.conf /etc/apache2/mods-available/dav_svn.conf 17 | 18 | ADD files/svn-backuper.sh /usr/local/bin/ 19 | ADD files/svn-project-creator.sh /usr/local/bin/ 20 | ADD files/svn-entrypoint.sh /usr/local/bin/ 21 | 22 | RUN chmod a+x /usr/local/bin/svn* 23 | 24 | RUN echo "*/10 * * * * root /usr/local/bin/svn-project-creator.sh" >> /etc/crontab 25 | RUN echo "0 0 * * * root /usr/local/bin/svn-backuper.sh" >> /etc/crontab 26 | 27 | RUN sed -i 's/# CMD/&\n echo "$@" | grep runit && svn-entrypoint.sh/g' /container/scripts/entrypoint.sh 28 | 29 | VOLUME ["/var/local/svn", "/var/svn-backup", "/etc/apache2/dav_svn"] 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Marvin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Subversion Container (ghcr.io/marvambass/subversion) based on secured Apache SSL PHP on debian:bullseye [x86 + arm] 2 | _maintained by MarvAmBass_ 3 | 4 | ## What is it 5 | 6 | A Docker Subversion Apache2 Container (based on `ghcr.io/servercontainers/apache2-ssl-secure`). 7 | 8 | Features automatic daily dumps of your SVN Repos for Backup purposes. 9 | 10 | You can control the access of your Project with a htpasswd file in combination with a authz file. 11 | 12 | ## Build & Variants 13 | 14 | You can specify `DOCKER_REGISTRY` environment variable (for example `my.registry.tld`) 15 | and use the build script to build the main container and it's variants for _x86_64, arm64 and arm_ 16 | 17 | You'll find all images tagged like `d11.2-s1.2.1-2.1` which means `d-s`. 18 | This way you can pin your installation/configuration to a certian version. or easily roll back if you experience any problems 19 | (don't forget to open a issue in that case ;D). 20 | 21 | To build a `latest` tag run `./build.sh release` 22 | 23 | ## Changelogs 24 | 25 | * 2023-03-22 26 | * github action to build container 27 | * implemented ghcr.io as new registry 28 | * added example config and `docker-compose.yml` 29 | * new baseimage `ghcr.io/servercontainers/apache2-ssl-secure` 30 | 31 | 32 | ## Creating a project 33 | 34 | You are able to create a new Project by simply adding a new Folder to your repository root directory (`/var/local/svn`). 35 | A cron running every 10 minutes will eventually pick it up. 36 | 37 | ## How to access your repository 38 | 39 | By defdault the repository is host on `/svn`, so for instance you can checkout `yourRepo` using `svn checkout http://yourDockerIp/svn/yourRepo` 40 | 41 | 42 | ## pre run configuration (optional) 43 | 44 | You may create the following two files. If you don't need access control you can just skip this step. 45 | 46 | Create authz file like this example: 47 | 48 | __$DAV_SVN_CONF/dav_svn.authz__ 49 | 50 | ``` 51 | [groups] 52 | admin = user1,user2, testuser 53 | devgroup = user5, user6 54 | 55 | [project1:/] 56 | @admin = rw 57 | @devgroup = r 58 | 59 | # devgroup members are able to read and write on project2 60 | [project2:/] 61 | @devgroup = rw 62 | 63 | # admins have control over every project - and can list all projects on the root point 64 | [/] 65 | @admin = rw 66 | 67 | # everybody is able to read repos and sees all projects 68 | [/] 69 | * = r 70 | ``` 71 | 72 | __$DAV_SVN_CONF/dav_svn.passwd__ 73 | 74 | To add a new User like 'testuser' with password 'test' use the following command 75 | 76 | ``` 77 | htdigest -c $DAV_SVN_CONF/dav_svn.passwd Subversion testuser 78 | ``` 79 | 80 | Or if you're to lazy, just use this line for your file (for testing only!) 81 | 82 | ``` 83 | testuser:Subversion:5d1b8d8c9a69af4b0180cdafe09cb907 84 | ``` 85 | 86 | ## Run the container 87 | 88 | ``` 89 | docker run \ 90 | -d \ 91 | -v $SVN:/var/local/svn \ 92 | -v $SVN_BACKUP:/var/svn-backup \ 93 | -v $DAV_SVN_CONF/:/etc/apache2/dav_svn/ \ 94 | --name subversion ghcr.io/marvambass/subversion 95 | ``` -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -x 2 | 3 | [ -z "$DOCKER_REGISTRY" ] && echo "error please specify docker-registry DOCKER_REGISTRY" && exit 1 4 | IMG="$DOCKER_REGISTRY/$(basename $(cat .git/config | tr ' ' '\n' | grep github.com))" 5 | 6 | PLATFORM="linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6" 7 | 8 | TAG=$(./get-version.sh) 9 | 10 | if echo "$@" | grep -v "force" 2>/dev/null >/dev/null; then 11 | echo "check if image was already build and pushed - skip check on release version" 12 | echo "$@" | grep -v "release" && docker pull "$IMG:$TAG" 2>/dev/null >/dev/null && echo "image already build" && exit 1 13 | fi 14 | 15 | docker buildx build -q --pull --no-cache --platform "$PLATFORM" -t "$IMG:$TAG" --push . 16 | 17 | echo "$@" | grep "release" 2>/dev/null >/dev/null && echo ">> releasing new latest" && docker buildx build -q --pull --platform "$PLATFORM" -t "$IMG:latest" --push . -------------------------------------------------------------------------------- /data/example-config/dav_svn.authz: -------------------------------------------------------------------------------- 1 | [groups] 2 | admin = user1,user2, testuser 3 | devgroup = user5, user6 4 | 5 | [project1:/] 6 | @admin = rw 7 | @devgroup = r 8 | 9 | # devgroup members are able to read and write on project2 10 | [project2:/] 11 | @devgroup = rw 12 | 13 | # admins have control over every project - and can list all projects on the root point 14 | [/] 15 | @admin = rw 16 | 17 | # everybody is able to read repos and sees all projects 18 | [/] 19 | * = r -------------------------------------------------------------------------------- /data/example-config/dav_svn.passwd: -------------------------------------------------------------------------------- 1 | testuser:Subversion:5d1b8d8c9a69af4b0180cdafe09cb907 -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.3' 2 | 3 | services: 4 | 5 | subversion: 6 | build: . 7 | image: ghcr.io/marvambass/subversion 8 | restart: always 9 | volumes: 10 | - ./data/data/backup:/var/local/svn 11 | - ./data/data/svn:/var/svn-backup 12 | - ./data/example-config:/etc/apache2/dav_svn/ 13 | ports: 14 | - "8080:80" -------------------------------------------------------------------------------- /files/dav_svn.conf: -------------------------------------------------------------------------------- 1 | 2 | DAV svn 3 | SVNParentPath /var/local/svn/ 4 | SVNListParentPath on 5 | 6 | AuthzSVNAccessFile /etc/apache2/dav_svn/dav_svn.authz 7 | 8 | Satisfy any 9 | Require valid-user 10 | AuthType Digest 11 | AuthName "Subversion" 12 | AuthUserFile /etc/apache2/dav_svn/dav_svn.passwd 13 | 14 | -------------------------------------------------------------------------------- /files/svn-backuper.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # variables 4 | SVNDIR="/var/local/svn/" 5 | BACKUPDIR="/var/svn-backup" 6 | 7 | find $SVNDIR* -maxdepth 0 -type d | while IFS= read -r DIR 8 | do 9 | NAME=`expr match "$DIR" '.*\(/.*\)'` 10 | echo "svnadmin dump $DIR > $BACKUPDIR$NAME.dump" 11 | svnadmin dump $DIR > $BACKUPDIR$NAME.dump 12 | done 13 | -------------------------------------------------------------------------------- /files/svn-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cat < /etc/apache2/dav_svn/dav_svn.authz 26 | # disable protection - everybody can do what he wants 27 | [/] 28 | * = rw 29 | EOF 30 | fi 31 | 32 | if [ ! -f /etc/apache2/dav_svn/dav_svn.passwd ] 33 | then 34 | echo "generating empty htpasswd file for svn users" 35 | echo "# no users in this htpasswd file" > /etc/apache2/dav_svn/dav_svn.passwd 36 | fi 37 | 38 | chown -R www-data:www-data "/var/local/svn/" 39 | cron -f & 40 | -------------------------------------------------------------------------------- /files/svn-project-creator.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # variables 4 | SVNDIR="/var/local/svn/" 5 | 6 | find $SVNDIR* -maxdepth 0 -type d | while IFS= read -r DIR 7 | do 8 | NAME=`expr match "$DIR" '.*\(/.*\)'` 9 | 10 | if [ -f "$DIR/README.txt" ] && [ `cat "$DIR/README.txt" | grep "This is a Subversion repository" | wc -l` -eq 1 ] 11 | then 12 | echo "$DIR is already a SVN Filesystem" 13 | else 14 | echo "creating new SVN Filesystem: $DIR" 15 | svnadmin create --fs-type fsfs "$DIR" 16 | chown -R www-data:www-data "$DIR" 17 | fi 18 | done 19 | 20 | chown -R www-data:www-data "$SVNDIR" 21 | -------------------------------------------------------------------------------- /get-version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | export IMG=$(docker build -q --pull --no-cache -t 'get-version' .) 3 | 4 | export DEBIAN_VERSION=$(docker run --rm -t get-version cat /etc/debian_version | tail -n1 | tr -d '\r') 5 | export SUBVERSION_VERSION=$(docker run --rm -t get-version dpkg --list subversion | grep '^ii' | sed 's/^[^0-9]*//g' | cut -d ' ' -f1 | sed 's/[+=:~]/_/g' | tr -d '\r') 6 | [ -z "$DEBIAN_VERSION" ] && exit 1 7 | 8 | export IMGTAG=$(echo "$1""d$DEBIAN_VERSION-s$SUBVERSION_VERSION") 9 | export IMAGE_EXISTS=$(docker pull "$IMGTAG" 2>/dev/null >/dev/null; echo $?) 10 | 11 | # return latest, if container is already available :) 12 | if [ "$IMAGE_EXISTS" -eq 0 ]; then 13 | echo "$1""latest" 14 | else 15 | echo "$IMGTAG" 16 | fi --------------------------------------------------------------------------------