├── .gitattributes ├── .gitignore ├── .gitlab-ci.docker.yml ├── .gitlab-ci.kaniko.yml ├── .gitlab-ci.yml ├── README.md ├── filebot ├── Dockerfile ├── checkconfig.sh ├── filebot.conf ├── filebot.sh ├── monitor.sh ├── setuser.py └── start.sh ├── jdownloader ├── Dockerfile ├── JDownloader.jar ├── README.md └── start.sh ├── rclone-mount ├── Dockerfile ├── README.md ├── docker-compose.yml ├── rootfs │ ├── etc │ │ ├── colors.sh │ │ ├── cont-finish.d │ │ │ └── 20-unmount │ │ ├── cont-init.d │ │ │ ├── 20-init │ │ │ └── 30-check │ │ └── services.d │ │ │ └── rclone-mount │ │ │ ├── finish │ │ │ └── run │ └── healthcheck.sh └── version ├── sabnzbdvpn ├── Dockerfile ├── README.md ├── openvpn │ └── start.sh └── scripts │ ├── start.sh │ ├── stop.sh │ └── userSetup.sh ├── smb-mount ├── Dockerfile ├── README.md ├── rootfs │ ├── etc │ │ ├── colors.sh │ │ ├── cont-finish.d │ │ │ └── 20-unmount │ │ ├── cont-init.d │ │ │ └── 20-config │ │ └── services.d │ │ │ └── cifs │ │ │ └── run │ └── healthcheck.sh └── start.sh └── teamspeakserver ├── Dockerfile ├── get-version.py └── start.sh /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | 49 | # VScode Files 50 | .vscode -------------------------------------------------------------------------------- /.gitlab-ci.docker.yml: -------------------------------------------------------------------------------- 1 | .docker_build_template: 2 | stage: build 3 | image: docker:latest 4 | # variables: 5 | # REGPATH: $CI_REGISTRY/$CI_PROJECT_PATH 6 | services: 7 | - docker:dind 8 | before_script: 9 | - echo "project $CI_PROJECT_PATH stage $CI_JOB_STAGE" 10 | - echo "starting new job for $CI_REGISTRY/$CI_PROJECT_PATH" 11 | script: 12 | - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY 13 | - docker pull $CI_REGISTRY/$CI_PROJECT_PATH/$ENV:$CI_COMMIT_REF_SLUG || true 14 | - docker build --pull -t $CI_REGISTRY/$CI_PROJECT_PATH/$ENV:$CI_COMMIT_SHA -t $CI_REGISTRY/$CI_PROJECT_PATH/$ENV:$CI_COMMIT_REF_SLUG ./$ENV 15 | - docker push $CI_REGISTRY/$CI_PROJECT_PATH/$ENV:$CI_COMMIT_SHA 16 | - docker push $CI_REGISTRY/$CI_PROJECT_PATH/$ENV:$CI_COMMIT_REF_SLUG 17 | rules: 18 | - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH == "dev"' 19 | changes: 20 | - '${ENV}/**/*' 21 | 22 | 23 | .docker_push_template_latest: 24 | stage: push 25 | image: docker:latest 26 | variables: 27 | DOCKER_REGISTRY: "docker.io" 28 | services: 29 | - docker:dind 30 | script: 31 | - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY 32 | - docker pull $CI_REGISTRY/$CI_PROJECT_PATH/$ENV:$CI_COMMIT_REF_SLUG || true 33 | - docker login -u $DOCKER_REGISTRY_USER -p $DOCKER_REGISTRY_TOKEN $DOCKER_REGISTRY 34 | - docker tag $CI_REGISTRY/$CI_PROJECT_PATH/$ENV:$CI_COMMIT_REF_SLUG $DOCKER_REGISTRY/$DOCKER_REGISTRY_USER/$ENV:latest 35 | - docker push $DOCKER_REGISTRY/$DOCKER_REGISTRY_USER/$ENV:latest 36 | rules: 37 | - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' 38 | changes: 39 | - '${ENV}/**/*' 40 | when: manual 41 | 42 | .docker_push_template_dev: 43 | stage: push 44 | image: docker:latest 45 | variables: 46 | DOCKER_REGISTRY: "docker.io" 47 | services: 48 | - docker:dind 49 | script: 50 | - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY 51 | - docker pull $CI_REGISTRY/$CI_PROJECT_PATH/$ENV:$CI_COMMIT_REF_SLUG || true 52 | - docker login -u $DOCKER_REGISTRY_USER -p $DOCKER_REGISTRY_TOKEN $DOCKER_REGISTRY 53 | - docker tag $CI_REGISTRY/$CI_PROJECT_PATH/$ENV:$CI_COMMIT_REF_SLUG $DOCKER_REGISTRY/$DOCKER_REGISTRY_USER/$ENV:$CI_COMMIT_REF_SLUG 54 | - docker push $DOCKER_REGISTRY/$DOCKER_REGISTRY_USER/$ENV:$CI_COMMIT_REF_SLUG 55 | rules: 56 | - if: '$CI_COMMIT_BRANCH == "dev"' 57 | changes: 58 | - '${ENV}/**/*' 59 | when: manual 60 | -------------------------------------------------------------------------------- /.gitlab-ci.kaniko.yml: -------------------------------------------------------------------------------- 1 | .kaniko_build_template: 2 | stage: build 3 | image: 4 | name: "gcr.io/kaniko-project/executor:v1.23.2-debug" 5 | entrypoint: [""] 6 | variables: 7 | VERSION_FILE: version 8 | before_script: 9 | - if [ -e "$ENV/$VERSION_FILE" ]; 10 | then ARG_IMAGE_VERSION=$(grep -E -o "(.*)" ${ENV}/${VERSION_FILE} | cut -d\" -f2); 11 | else ARG_IMAGE_VERSION="latest"; 12 | fi 13 | - echo $ARG_IMAGE_VERSION 14 | - echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json 15 | script: 16 | - if [ "$CI_COMMIT_BRANCH" == "$CI_DEFAULT_BRANCH" ]; 17 | then /kaniko/executor --context $CI_PROJECT_DIR/$ENV --dockerfile Dockerfile --build-arg IMAGE_VERSION=$ARG_IMAGE_VERSION --destination $CI_REGISTRY_IMAGE/$ENV:$ARG_IMAGE_VERSION --destination $CI_REGISTRY_IMAGE/$ENV:latest; 18 | else /kaniko/executor --context $CI_PROJECT_DIR/$ENV --dockerfile Dockerfile --build-arg IMAGE_VERSION=$ARG_IMAGE_VERSION --destination $CI_REGISTRY_IMAGE/$ENV:$CI_COMMIT_REF_SLUG; 19 | fi 20 | rules: 21 | - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH == "dev"' 22 | changes: 23 | - '${ENV}/**/*' 24 | 25 | .crane_push_docker_template: 26 | stage: push 27 | image: 28 | name: "gcr.io/go-containerregistry/crane:debug" 29 | entrypoint: [""] 30 | variables: 31 | # GIT_STRATEGY: none 32 | DOCKER_REGISTRY: "docker.io" 33 | VERSION_FILE: version 34 | before_script: 35 | - if [ -e "$ENV/$VERSION_FILE" ]; 36 | then ARG_IMAGE_VERSION=$(grep -E -o "(.*)" ${ENV}/${VERSION_FILE} | cut -d\" -f2); 37 | else ARG_IMAGE_VERSION="latest"; 38 | fi 39 | - echo $ARG_IMAGE_VERSION 40 | - crane auth login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY 41 | - crane auth login -u $DOCKER_REGISTRY_USER -p $DOCKER_REGISTRY_TOKEN $DOCKER_REGISTRY 42 | script: 43 | - if [ "$ARG_IMAGE_VERSION" == "latest" ]; 44 | then crane copy $CI_REGISTRY_IMAGE/$ENV:$ARG_IMAGE_VERSION $DOCKER_REGISTRY/$DOCKER_REGISTRY_USER/$ENV:latest; 45 | else crane copy $CI_REGISTRY_IMAGE/$ENV:$ARG_IMAGE_VERSION $DOCKER_REGISTRY/$DOCKER_REGISTRY_USER/$ENV:$ARG_IMAGE_VERSION && crane tag $DOCKER_REGISTRY/$DOCKER_REGISTRY_USER/$ENV:$ARG_IMAGE_VERSION latest; 46 | fi 47 | rules: 48 | - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' 49 | changes: 50 | - '${ENV}/**/*' 51 | when: manual 52 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | # LATEST_VER: mumie/app:latest 3 | # MAJOR_VER: mumie/app:2 4 | KUBERNETES_CPU_REQUEST: 500m 5 | KUBERNETES_CPU_LIMIT: 1500m 6 | KUBERNETES_MEMORY_REQUEST: 2048Mi 7 | KUBERNETES_MEMORY_LIMIT: 4096Mi 8 | 9 | stages: 10 | - build 11 | - push 12 | 13 | 14 | include: 15 | - '/.gitlab-ci.docker.yml' 16 | - '/.gitlab-ci.kaniko.yml' 17 | 18 | 19 | # before_script: 20 | # - echo "starting new job in $REGPATH" 21 | # - docker info 22 | #- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY 23 | 24 | 25 | # jobs ################################ 26 | build:jdownloader: 27 | extends: .kaniko_build_template 28 | variables: 29 | ENV: jdownloader 30 | 31 | build:rclone-mount: 32 | extends: .kaniko_build_template 33 | variables: 34 | ENV: rclone-mount 35 | 36 | build:sabnzbdvpn: 37 | extends: .kaniko_build_template 38 | variables: 39 | ENV: sabnzbdvpn 40 | 41 | build:smb-mount: 42 | extends: .kaniko_build_template 43 | variables: 44 | ENV: smb-mount 45 | 46 | 47 | #docker_build2: 48 | # stage: build 49 | # script: 50 | # - docker info 51 | # - docker build -t $LATEST_VER -t $MAJOR_VER . 52 | 53 | 54 | # docker_test1: 55 | # stage: test 56 | # image: docker:latest 57 | # services: 58 | # - docker:dind 59 | # script: 60 | # - echo "finished" 61 | # # do some test 62 | # #- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY 63 | # only: 64 | # refs: 65 | # - master 66 | # - dev 67 | 68 | # docker_push1: 69 | # stage: push 70 | # image: docker:latest 71 | # services: 72 | # - docker:dind 73 | # script: 74 | # - echo "manual job done" 75 | # # push image to registry 76 | # #- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY 77 | # only: 78 | # refs: 79 | # - master 80 | # - dev 81 | # when: manual 82 | 83 | push:rclone-mount: 84 | extends: .crane_push_docker_template 85 | variables: 86 | ENV: rclone-mount 87 | needs: 88 | - job: build:rclone-mount 89 | 90 | push:sabnzbdvpn: 91 | extends: .crane_push_docker_template 92 | variables: 93 | ENV: sabnzbdvpn 94 | needs: 95 | - job: build:sabnzbdvpn 96 | 97 | push:smb-mount: 98 | extends: .crane_push_docker_template 99 | variables: 100 | ENV: smb-mount 101 | needs: 102 | - job: build:smb-mount 103 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Container services - most of them based on alpine image to be lightweight. 2 | All services are build for a graceful shutdown/restart with S6 overlay or a small init script. -------------------------------------------------------------------------------- /filebot/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu 2 | 3 | MAINTAINER Mumie 4 | 5 | ENV USER_NAME="filebot" \ 6 | USER_ID=1002 \ 7 | GROUP_ID=1002 \ 8 | UMASK=0002 \ 9 | DEBIAN_FRONTEND=noninteractive \ 10 | CONFIG_DIR="/config" \ 11 | CONFIG_FILE="filebot.conf" \ 12 | MOUNT_POINT="/mnt" \ 13 | WATCH_DIR="/mnt/input" \ 14 | OUTPUT_DIR="/mnt/output" 15 | # IGNORE_EVENTS=0 16 | 17 | # Use of inotify, python3 18 | RUN set -x \ 19 | && apt-get -q update \ 20 | && apt-get install -qy inotify-tools openjdk-8-jre-headless wget python3 \ 21 | && groupadd -g ${USER_ID} ${USER_NAME} \ 22 | && useradd -u ${USER_ID} -g ${GROUP_ID} -d /home/${USER_NAME} -m -s /bin/sh ${USER_NAME} \ 23 | && mkdir -p /files /config \ 24 | && chown -R ${USER_NAME}:${USER_NAME} /files \ 25 | && wget -qO /files/filebot.deb 'https://app.filebot.net/download.php?type=deb&arch=amd64&version=4.7.7' \ 26 | && dpkg -i /files/filebot.deb && rm /files/filebot.deb \ 27 | && apt-get -y purge wget \ 28 | && apt-get clean \ 29 | && rm -rf /tmp/* /var/tmp/* /var/lib/apt/lists/* /var/cache/apt/* 30 | 31 | # Add scripts. Make sure start.sh, and filebot.sh are executable by $USER_ID 32 | ADD start.sh /start.sh 33 | ADD filebot.sh /files/filebot.sh 34 | ADD filebot.conf /files/filebot.conf 35 | ADD monitor.sh /files/monitor.sh 36 | ADD checkconfig.sh /files/checkconfig.sh 37 | ADD setuser.py /setuser.py 38 | 39 | RUN \ 40 | chmod a+x /start.sh \ 41 | && chmod a+wx /files/filebot.sh \ 42 | && chmod a+w /files/filebot.conf \ 43 | && chmod +x /files/monitor.sh \ 44 | && chmod +x /files/checkconfig.sh \ 45 | && chmod +x /setuser.py \ 46 | && chown -R ${USER_NAME}:${USER_NAME} /files \ 47 | && chown -R ${USER_NAME}:${USER_NAME} $CONFIG_DIR 48 | 49 | #VOLUME [${WATCH_DIR}, ${OUTPUT_DIR}, ${CONFIG_DIR}] 50 | 51 | ENTRYPOINT ["/start.sh"] 52 | 53 | # -v /etc/localtime:/etc/localtime:ro 54 | # -v /home/mumie/.config/filebot:/config:rw 55 | # -v /mnt/downloads:/input:rw 56 | # -v /mnt/uploads:/output:rw -------------------------------------------------------------------------------- /filebot/checkconfig.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #CONFIG_FILE=$1 4 | 5 | function ts { 6 | echo [`date '+%b %d %X'`] 7 | } 8 | 9 | #---------------------------------------------------------------- 10 | 11 | function check_config { 12 | if [[ ! -d "$WATCH_DIR" ]]; then 13 | echo "$(ts) WATCH_DIR specified in $CONFIG_FILE must be a directory." 14 | exit 1 15 | fi 16 | 17 | if [[ ! "$SETTLE_DURATION" =~ ^([0-9]{1,2}:){0,2}[0-9]{1,2}$ ]]; then 18 | echo "$(ts) SETTLE_DURATION must be defined in $CONFIG_FILE as HH:MM:SS or MM:SS or SS." 19 | exit 1 20 | fi 21 | 22 | if [[ ! "$MAX_WAIT_TIME" =~ ^([0-9]{1,2}:){0,2}[0-9]{1,2}$ ]]; then 23 | echo "$(ts) MAX_WAIT_TIME must be defined in $CONFIG_FILE as HH:MM:SS or MM:SS or SS." 24 | exit 1 25 | fi 26 | 27 | if [[ ! "$MIN_PERIOD" =~ ^([0-9]{1,2}:){0,2}[0-9]{1,2}$ ]]; then 28 | echo "$(ts) MIN_PERIOD must be defined in $CONFIG_FILE as HH:MM:SS or MM:SS or SS." 29 | exit 1 30 | fi 31 | 32 | if [[ ! "$USER_ID" =~ ^[0-9]{1,}$ ]]; then 33 | echo "$(ts) USER_ID must be defined in $CONFIG_FILE as a whole number." 34 | exit 1 35 | fi 36 | 37 | if [[ ! "$GROUP_ID" =~ ^[0-9]{1,}$ ]]; then 38 | echo "$(ts) GROUP_ID must be defined in $CONFIG_FILE as a whole number." 39 | exit 1 40 | fi 41 | echo "$(ts) $CONFIG_FILE Config checked" 42 | } 43 | 44 | #----------------------------------------------------------------------------------------- 45 | 46 | #tr -d '\r' < $CONFIG_FILE > /tmp/$NAME.conf 47 | 48 | . $CONFIG_DIR/filebot.conf 49 | 50 | check_config 51 | 52 | #SETTLE_DURATION=$(to_seconds $SETTLE_DURATION) 53 | #MAX_WAIT_TIME=$(to_seconds $MAX_WAIT_TIME) 54 | #MIN_PERIOD=$(to_seconds $MIN_PERIOD) 55 | 56 | echo "$(ts) CONFIGURATION ---------------:" 57 | echo "$(ts) WATCH_DIR=$WATCH_DIR" 58 | echo "$(ts) SETTLE_DURATION=$SETTLE_DURATION" 59 | echo "$(ts) MAX_WAIT_TIME=$MAX_WAIT_TIME" 60 | echo "$(ts) MIN_PERIOD=$MIN_PERIOD" 61 | echo "$(ts) USER_ID=$USER_ID" 62 | echo "$(ts) GROUP_ID=$GROUP_ID" 63 | echo "$(ts) UMASK=$UMASK" 64 | echo "$(ts) DEBUG=$DEBUG" 65 | echo "$(ts) IGNORE_EVENTS=$IGNORE_EVENTS" -------------------------------------------------------------------------------- /filebot/filebot.conf: -------------------------------------------------------------------------------- 1 | # If we don't see any events for $SETTLE_DURATION time, assume that it's safe to run FileBot. Format is HH:MM:SS, 2 | # with HH and MM optional. 3 | SETTLE_DURATION=10 4 | 5 | # However, if we see a stream of changes for longer than $MAX_WAIT_TIME with no break of $SETTLE_DURATION or more, then 6 | # go ahead and run FileBot. Otherwise we might be waiting forever for the directory to stop changing. Format is 7 | # HH:MM:SS, with HH and MM optional. 8 | MAX_WAIT_TIME=01:00 9 | 10 | # After running FileBot, wait at least this long before running it again, even if $SETTLE_DURATION time has passed 11 | # after change. This controls the maximum frequency of FileBot. 12 | MIN_PERIOD=05:00 13 | 14 | # Set this to 1 to log all events, for debugging purposes. WARNING! This creates copious amounts of confusing logging! 15 | DEBUG=0 16 | 17 | # Create an account at http://www.opensubtitles.org/ if you want to download subtitles 18 | OPENSUBTITLES_USER="" 19 | OPENSUBTITLES_PASSWORD="" 20 | 21 | # Set this to a language code if you want to download subtitles. e.g. Use "en" for english 22 | SUBTITLE_LANG="" 23 | -------------------------------------------------------------------------------- /filebot/filebot.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script by default uses "Automated Media Center" (AMC). See the final filebot call below. For more docs on AMC, 4 | # visit: http://www.filebot.net/forums/viewtopic.php?t=215 5 | 6 | #----------------------------------------------------------------------------------------------------------------------- 7 | 8 | # Specify the URLs of any scripts that you need. They will be downloaded into /config/scripts 9 | SCRIPTS_TO_DOWNLOAD=( 10 | # Example: 11 | # https://raw.githubusercontent.com/filebot/scripts/devel/cleaner.groovy 12 | ) 13 | 14 | #----------------------------------------------------------------------------------------------------------------------- 15 | 16 | QUOTE_FIXER='replaceAll(/[\`\u00b4\u2018\u2019\u02bb]/, "'"'"'").replaceAll(/[\u201c\u201d]/, '"'"'""'"'"')' 17 | 18 | # Customize the renaming format here. For info on formatting: https://www.filebot.net/naming.html 19 | 20 | # Music/Eric Clapton/From the Cradle/05 - It Hurts Me Too.mp3 21 | MUSIC_FORMAT="Music/{n.$QUOTE_FIXER}/{album.$QUOTE_FIXER}/{media.TrackPosition.pad(2)} - {t.$QUOTE_FIXER}" 22 | 23 | # Movies/Fight Club.mkv 24 | MOVIE_FORMAT="Filme/{n} {y}/{n.$QUOTE_FIXER} {y}.{vf}.{vc}.{' CD'+pi}" 25 | 26 | # TV Shows/Game of Thrones/Season 05/Game of Thrones - S05E08 - Hardhome.mp4 27 | # TV Shows/Game of Thrones/Special/Game of Thrones - S00E11 - A Day in the Life.mp4 28 | SERIES_FORMAT="Serien/{n}/{episode.special ? 'Special' : 'Season '+s.pad(2)}/{n} - {episode.special ? 'S00E'+special.pad(2) : s00e00} - {t.${QUOTE_FIXER}.replaceAll(/[!?.]+$/).replacePart(', Part $1')}{'.'+lang}" 29 | 30 | . $CONFIG_DIR/filebot.conf 31 | 32 | if [ "$SUBTITLE_LANG" == "" ];then 33 | SUBTITLE_OPTION="" 34 | else 35 | SUBTITLE_OPTION="subtitles=$SUBTITLE_LANG" 36 | fi 37 | 38 | #----------------------------------------------------------------------------------------------------------------------- 39 | 40 | # Used to detect old versions of this script 41 | VERSION=3 42 | 43 | # Download scripts and such. 44 | #. /files/pre-run.sh 45 | 46 | # excludeList=$CONFIG_DIR/amc-exclude-list.txt 47 | # See http://www.filebot.net/forums/viewtopic.php?t=215 for details on amc 48 | filebot -script fn:amc -no-xattr --output $OUTPUT_DIR --log-file $CONFIG_DIR/amc.log --action move --conflict auto \ 49 | -non-strict --def ut_dir=${WATCH_DIR} ut_kind=multi music=y skipExtract=y clean=y \ 50 | $SUBTITLE_OPTION movieFormat="$MOVIE_FORMAT" musicFormat="$MUSIC_FORMAT" seriesFormat="$SERIES_FORMAT" 51 | -------------------------------------------------------------------------------- /filebot/monitor.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CONFIG_FILE=$CONFIG_FILE 4 | NAME=$(basename $CONFIG_FILE .conf) 5 | 6 | #----------------------------------------------------------------------------------------------------------------------- 7 | 8 | function ts { 9 | echo [`date '+%b %d %X'`] $NAME: 10 | } 11 | 12 | #----------------------------------------------------------------------------------------------------------------------- 13 | 14 | function is_change_event { 15 | EVENT="$1" 16 | INFO="$2" 17 | 18 | # File events 19 | if [ "$EVENT" == "ATTRIB" ] 20 | then 21 | echo "$(ts) Detected file attribute change: $INFO" 22 | elif [ "$EVENT" == "CLOSE_WRITE,CLOSE" ] 23 | then 24 | EVENT=CLOSE_WRITE 25 | echo "$(ts) Detected new file: $INFO" 26 | # elif [ "$EVENT" == "MOVED_TO" ] 27 | # then 28 | # echo "$(ts) Detected file moved into dir: $INFO" 29 | # elif [ "$EVENT" == "MOVED_FROM" ] 30 | # then 31 | # echo "$(ts) Detected file moved out of dir: $INFO" 32 | elif [ "$EVENT" == "DELETE" ] 33 | then 34 | echo "$(ts) Detected deleted file: $INFO" 35 | 36 | # Directory events 37 | elif [ "$EVENT" == "ATTRIB,ISDIR" ] 38 | then 39 | echo "$(ts) Detected dir attribute change: $INFO" 40 | # elif [ "$EVENT" == "CREATE,ISDIR" ] 41 | # then 42 | # echo "$(ts) Detected new dir: $INFO" 43 | # elif [ "$EVENT" == "MOVED_TO,IS_DIR" ] 44 | # then 45 | # echo "$(ts) Detected dir moved into dir: $INFO" 46 | # elif [ "$EVENT" == "MOVED_FROM,IS_DIR" ] 47 | # then 48 | # echo "$(ts) Detected dir moved out of dir: $INFO" 49 | elif [ "$EVENT" == "DELETE,ISDIR" ] 50 | then 51 | echo "$(ts) Detected deleted dir: $INFO" 52 | 53 | else 54 | return 1 55 | fi 56 | 57 | return 0 58 | } 59 | 60 | #----------------------------------------------------------------------------------------------------------------------- 61 | 62 | function to_seconds { 63 | readarray elements < <(echo $1 | tr ':' '\n' | tac) 64 | 65 | SECONDS=0 66 | POWER=1 67 | 68 | for (( i=0 ; i<${#elements[@]}; i++ )) ; do 69 | SECONDS=$(( 10#$SECONDS + 10#${elements[i]} * 10#$POWER )) 70 | POWER=$(( 10#$POWER * 60 )) 71 | done 72 | 73 | echo "$SECONDS" 74 | } 75 | 76 | #----------------------------------------------------------------------------------------------------------------------- 77 | 78 | function wait_for_events_to_stabilize { 79 | start_time=$(date +"%s") 80 | while true 81 | do 82 | if read -t $SETTLE_DURATION RECORD 83 | then 84 | end_time=$(date +"%s") 85 | 86 | if [ $(($end_time-$start_time)) -gt $MAX_WAIT_TIME ] 87 | then 88 | echo "$(ts) Input directory didn't stabilize after $MAX_WAIT_TIME seconds. Triggering command anyway." 89 | break 90 | fi 91 | else 92 | echo "$(ts) Input directory stabilized for $SETTLE_DURATION seconds. Triggering command." 93 | break 94 | fi 95 | done 96 | } 97 | 98 | #----------------------------------------------------------------------------------------------------------------------- 99 | 100 | function wait_for_minimum_period { 101 | last_run_time=$1 102 | time_since_last_run=$(($(date +"%s")-$last_run_time)) 103 | if [ $time_since_last_run -lt $MIN_PERIOD ] 104 | then 105 | remaining_time=$(($MIN_PERIOD-$time_since_last_run)) 106 | 107 | echo "$(ts) Waiting an additional $remaining_time seconds before running command" 108 | fi 109 | 110 | # Process events while we wait for $MIN_PERIOD to expire 111 | while [ $time_since_last_run -lt $MIN_PERIOD ] 112 | do 113 | remaining_time=$(($MIN_PERIOD-$time_since_last_run)) 114 | 115 | read -t $remaining_time RECORD 116 | 117 | time_since_last_run=$(($(date +"%s")-$last_run_time)) 118 | done 119 | } 120 | 121 | #----------------------------------------------------------------------------------------------------------------------- 122 | 123 | function wait_for_command_to_complete { 124 | PID=$1 125 | 126 | while ps -p $PID > /dev/null 127 | do 128 | sleep .1 129 | 130 | if [[ "$IGNORE_EVENTS" == "1" ]] 131 | then 132 | # -t 0 didn't work for me. Seemed to return success with no RECORD 133 | while read -t 0.001 RECORD; do :; done 134 | fi 135 | done 136 | } 137 | 138 | #----------------------------------------------------------------------------------------------------------------------- 139 | 140 | echo "$(ts) Starting inotifywait monitor $CONFIG_FILE at $WATCH_DIR" 141 | 142 | tr -d '\r' < $CONFIG_FILE > /tmp/$NAME.conf 143 | . /tmp/$NAME.conf 144 | 145 | SETTLE_DURATION=$(to_seconds $SETTLE_DURATION) 146 | MAX_WAIT_TIME=$(to_seconds $MAX_WAIT_TIME) 147 | MIN_PERIOD=$(to_seconds $MIN_PERIOD) 148 | COMMAND="bash /config/filebot.sh" ###change to Monitor Config 149 | 150 | pipe=$(mktemp -u) 151 | mkfifo $pipe 152 | 153 | inotifywait -r -m -q --format 'EVENT=%e WATCHED=%w FILE=%f' $WATCH_DIR >$pipe & 154 | 155 | last_run_time=0 156 | 157 | while true 158 | do 159 | if read RECORD 160 | then 161 | #echo "$(ts) [DEBUG] $RECORD" 162 | 163 | EVENT=$(echo "$RECORD" | sed 's/EVENT=\([^ ]*\).*/\1/') 164 | INFO=$(echo "$RECORD" | sed 's/EVENT=[^ ]* //') 165 | 166 | if ! is_change_event "$EVENT" "$INFO" 167 | then 168 | continue 169 | fi 170 | 171 | # Monster up as many events as possible, until we hit the either the settle duration, or the max wait threshold. 172 | # will be removed 173 | wait_for_events_to_stabilize 174 | 175 | # Wait until it's okay to run the command again, monstering up events as we do so 176 | wait_for_minimum_period $last_run_time 177 | 178 | echo "$(ts) Running command with user ID $USER_ID and group ID $GROUP_ID" 179 | #/sbin/setuser $USER_NAME $COMMAND & 180 | $COMMAND & 181 | PID=$! 182 | last_run_time=$(date +"%s") 183 | 184 | wait_for_command_to_complete $PID 185 | fi 186 | done <$pipe -------------------------------------------------------------------------------- /filebot/setuser.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | import sys, os, pwd 3 | 4 | if len(sys.argv) < 3: 5 | sys.stderr.write("Usage: /sbin/setuser USERNAME COMMAND [args..]\n") 6 | sys.exit(1) 7 | 8 | def abort(message): 9 | sys.stderr.write("setuser: %s\n" % message) 10 | sys.exit(1) 11 | 12 | username = sys.argv[1] 13 | try: 14 | user = pwd.getpwnam(username) 15 | except KeyError: 16 | abort("user %s not found" % username) 17 | os.initgroups(username, user.pw_gid) 18 | os.setgid(user.pw_gid) 19 | os.setuid(user.pw_uid) 20 | os.environ['USER'] = username 21 | os.environ['HOME'] = user.pw_dir 22 | os.environ['UID'] = str(user.pw_uid) 23 | try: 24 | os.execvp(sys.argv[2], sys.argv[2:]) 25 | except OSError as e: 26 | abort("cannot execute %s: %s" % (sys.argv[2], str(e))) -------------------------------------------------------------------------------- /filebot/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function ts { 4 | echo [`date '+%b %d %X'`] 5 | } 6 | #---------------------------------------------------------------------------------------------------- 7 | function initialize_configuration { 8 | if [ ! -f $CONFIG_DIR/$CONFIG_FILE ] 9 | then 10 | echo "$(ts) Creating default filebot.conf in User Dir" 11 | cp /files/filebot.conf $CONFIG_DIR/$CONFIG_FILE 12 | chmod a+w $CONFIG_DIR/$CONFIG_FILE 13 | fi 14 | 15 | if [ ! -f $CONFIG_DIR/filebot.sh ] 16 | then 17 | echo "$(ts) Creating default filebot.sh in User Dir" 18 | cp /files/filebot.sh $CONFIG_DIR/filebot.sh 19 | fi 20 | } 21 | #---------------------------------------------------------------------------------------------------- 22 | function check_filebot_sh_version { 23 | USER_VERSION=$(grep '^VERSION=' $CONFIG_DIR/filebot.sh 2>/dev/null | sed 's/VERSION=//') 24 | CURRENT_VERSION=$(grep '^VERSION=' /files/filebot.sh | sed 's/VERSION=//') 25 | 26 | echo "$(ts) Comparing user's filebot.sh at version $USER_VERSION versus current version $CURRENT_VERSION" 27 | 28 | if [ -z "$USER_VERSION" ] || [ "$USER_VERSION" -lt "$CURRENT_VERSION" ] 29 | then 30 | echo "$(ts) Copying the new script to User Dir $CONFIG_DIR/filebot.sh.new" 31 | echo "$(ts) Save filebot.sh to reset its timestamp, then restart the container." 32 | cp /files/filebot.sh $CONFIG_DIR/filebot.sh.new 33 | exit 1 34 | fi 35 | } 36 | #--------------------------------------------------------------------------------------------------- 37 | function setup_opensubtitles_account { 38 | . $CONFIG_DIR/filebot.conf 39 | 40 | if [ "$OPENSUBTITLES_USER" != "" ]; then 41 | echo "$(ts) Configuring for OpenSubtitles user \"$OPENSUBTITLES_USER\"" 42 | echo -en "$OPENSUBTITLES_USER\n$OPENSUBTITLES_PASSWORD\n" | /files/runas.sh $USER_ID $GROUP_ID $UMASK filebot -script fn:configure 43 | else 44 | echo "$(ts) No OpenSubtitles user set. Skipping setup..." 45 | fi 46 | } 47 | #--------------------------------------------------------------------------------------------------- 48 | echo "$(ts) start.sh: Starting init ..." 49 | # Create User and make Premissions on Folders 50 | mkdir -p ${WATCH_DIR} ${OUTPUT_DIR} 51 | chown -R ${USER_NAME}:${USER_NAME} $WATCH_DIR $OUTPUT_DIR 52 | 53 | initialize_configuration 54 | check_filebot_sh_version 55 | #. /files/pre-run.sh # Download scripts and such. 56 | /files/checkconfig.sh 57 | #setup_opensubtitles_account 58 | chown -R ${USER_NAME}:${USER_NAME} $CONFIG_DIR 59 | 60 | #echo "$(ts) start.sh: Running FileBot on startup" 61 | #/files/runas.sh $USER_ID $GROUP_ID $UMASK /files/filebot.sh & 62 | umask $UMASK 63 | #/sbin/setuser $USER_NAME $CONFIG_DIR/filebot.sh 64 | python3 /setuser.py $USER_NAME $CONFIG_DIR/filebot.sh 65 | #su -pc "$CONFIG_DIR/filebot.sh" $USER_NAME 66 | 67 | echo "$(ts) start.sh: Starting Monitoring" 68 | #su -p $USER_NAME -c "exec /files/monitor.sh" #$CONFIG_FILE 69 | #exec /sbin/setuser $USER_NAME /files/monitor.sh 70 | exec python3 /setuser.py $USER_NAME /files/monitor.sh 71 | -------------------------------------------------------------------------------- /jdownloader/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:latest 2 | 3 | ENV USER_UID="1002" \ 4 | USER_NAME="jdownloader" \ 5 | JDOWNLOADER_LINK="http://installer.jdownloader.org/JDownloader.jar" \ 6 | JDPATH="/jdownloader" \ 7 | LANG='C.UTF-8' \ 8 | LANGUAGE='C.UTF-8' \ 9 | LC_ALL="C.UTF-8" 10 | 11 | ENV JAVA_HOME=/opt/jdk \ 12 | PATH=${PATH}:/opt/jdk/bin \ 13 | GLIBC_VERSION=2.35-r0 14 | 15 | # alpine - openjdk8-jre-base libstdc++ glibc-bin glibc-i18n gcompat 16 | # libstdc++ and glibc-i18n needed for jdownloader building 7zip package 17 | RUN set -ex \ 18 | && apk add --no-cache --update wget bash ca-certificates su-exec curl libstdc++ tar openjdk8-jre-base gcompat \ 19 | # && wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub \ 20 | # && wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_VERSION}/glibc-${GLIBC_VERSION}.apk \ 21 | # && wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_VERSION}/glibc-bin-${GLIBC_VERSION}.apk \ 22 | # && wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_VERSION}/glibc-i18n-${GLIBC_VERSION}.apk \ 23 | # && apk add glibc-${GLIBC_VERSION}.apk glibc-bin-${GLIBC_VERSION}.apk glibc-i18n-${GLIBC_VERSION}.apk \ 24 | # && ( /usr/glibc-compat/bin/localedef --force --inputfile POSIX --charmap UTF-8 C.UTF-8 || true ) \ 25 | # && echo "export $LANG" > /etc/profile.d/locale.sh \ 26 | # && /usr/glibc-compat/sbin/ldconfig /lib /usr/glibc-compat/lib \ 27 | && mkdir -p /opt \ 28 | && mkdir -p ${JDPATH} \ 29 | && echo "adding $USER_NAME as Group and User" \ 30 | && addgroup -g ${USER_UID} ${USER_NAME} \ 31 | && adduser -D -u ${USER_UID} -G ${USER_NAME} -s /bin/sh -h /${USER_NAME} ${USER_NAME} \ 32 | # && echo "Downloading jDownloader jar File" \ 33 | # && wget -O ${JDPATH}/JDownloader.jar --progress=bar:force ${JDOWNLOADER_LINK} \ 34 | && apk del wget curl tar \ 35 | && rm -rf /tmp/* /var/cache/apk/* /var/lib/apk/lists/* 36 | 37 | ADD start.sh /start.sh 38 | ADD JDownloader.jar ${JDPATH}/JDownloader.jar 39 | RUN chmod +x /start.sh 40 | 41 | #USER $USER_NAME 42 | VOLUME ${JDPATH}/cfg 43 | WORKDIR ${JDPATH} 44 | CMD ["/start.sh"] 45 | 46 | # Run Commands 47 | #-v /pathtoconfig/jdownloader:/jdownloader/cfg 48 | #-v /downloadpath/:/jdownloader/Downloads 49 | -------------------------------------------------------------------------------- /jdownloader/JDownloader.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mumie-hub/docker-services/30f4fb0f312d6e9ada8aee728f06f2a772c9590c/jdownloader/JDownloader.jar -------------------------------------------------------------------------------- /jdownloader/README.md: -------------------------------------------------------------------------------- 1 | Lightweight alpine container with jdownloader (126MB image size) with graceful shutdown/restart (java runs on PID 1 with USER_UID specified). All is working correctly especially extracting ( glibc is added for extraction to work ). 2 | 3 | # Usage Example: 4 | 5 | docker run -d -m 2g --name jdownloader \ 6 | --restart=unless-stopped \ 7 | --cap-add SYS_ADMIN \ 8 | --device /dev/fuse \ 9 | --security-opt apparmor:unconfined \ 10 | -e USER_UID=1002 \ 11 | -v /home//jdownloader:/jdownloader/cfg \ 12 | -v /host/download/path:/jdownloader/Downloads \ 13 | mumiehub/jdownloader 14 | 15 | -m 2g is used because jdownloader will eat up your memory when downloading something (caching). 16 | 17 | to edit your jdownloader config for my.jdownloader.org portal maybe, just go to the mounted folder /home/USER/data/jdownloader 18 | and edit: org.jdownloader.api.myjdownloader.MyJDownloaderSettings.json 19 | add: 20 | { 21 | "serverhost" : "api.jdownloader.org", 22 | "email" : "youremailadress", 23 | "password" : "yourpassword" 24 | } 25 | 26 | (dont forget the , on each end of the entries except the last entry) 27 | -------------------------------------------------------------------------------- /jdownloader/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | #ENV 5 | OS="" 6 | 7 | #Functions 8 | DectectOS(){ 9 | if [ -e /etc/alpine-release ]; then 10 | OS="alpine" 11 | elif [ -e /etc/os-release ]; then 12 | if /bin/grep -q "NAME=\"Ubuntu\"" /etc/os-release ; then 13 | OS="ubuntu" 14 | fi 15 | fi 16 | } 17 | 18 | AutoUpgrade(){ 19 | if [ "${OS}" == "alpine" ]; then 20 | /sbin/apk --no-cache upgrade 21 | /bin/rm -rf /var/cache/apk/* 22 | elif [ "${OS}" == "ubuntu" ]; then 23 | export DEBIAN_FRONTEND=noninteractive 24 | /usr/bin/apt-get update 25 | /usr/bin/apt-get -y --no-install-recommends dist-upgrade 26 | /usr/bin/apt-get -y autoclean 27 | /usr/bin/apt-get -y clean 28 | /usr/bin/apt-get -y autoremove 29 | /bin/rm -rf /var/lib/apt/lists/* 30 | fi 31 | } 32 | 33 | AddCredentials(){ 34 | if [ ! -f $JDPATH/cfg/org.jdownloader.api.myjdownloader.MyJDownloaderSettings.json ]; then 35 | cat << EOF > $JDPATH/cfg/org.jdownloader.api.myjdownloader.MyJDownloaderSettings.json 36 | { 37 | "autoconnectenabledv2" : true, 38 | "email" : "${DOCKJDMAIL}", 39 | "password" : "${DOCKJDPASSWD}" 40 | } 41 | EOF 42 | /bin/chown -R "${MYUSER}":"${MYUSER}" $JDPATH/cfg/org.jdownloader.api.myjdownloader.MyJDownloaderSettings.json 43 | /bin/chmod 0664 $JDPATH/cfg/org.jdownloader.api.myjdownloader.MyJDownloaderSettings.json 44 | fi 45 | } 46 | 47 | SetDownloadFolder(){ 48 | if [ -f $JDPATH/cfg/org.jdownloader.settings.GeneralSettings.json ]; then 49 | sed -i "s|\s*\"defaultdownloadfolder\"\s*:\s*\"\"|\ \ \ \ \ \ \ \ \"defaultdownloadfolder\":\ \"/downloads\"|g" $JDPATH/cfg/org.jdownloader.settings.GeneralSettings.json 50 | fi 51 | } 52 | 53 | #USER_NAME="jdownloader" 54 | echo "====================" 55 | echo "JDownloader settings" 56 | echo "====================" 57 | echo 58 | echo " User: ${USER_NAME}" 59 | echo " UID: ${USER_UID}" 60 | #echo " UID: ${JDOWNLOADER_UID}" 61 | #echo " GID: ${JDOWNLOADER_GID}" 62 | echo 63 | 64 | # Change UID / GID of JDownloader user. 65 | printf "Updating UID / GID... " 66 | #[[ $(id -u ${USER_NAME}) == ${USER_UID} ]] || usermod -o -u ${USER_UID} ${USER_NAME} 67 | #[[ $(id -g ${USER_NAME}) == ${USER_UID} ]] || groupmod -o -g ${USER_UID} ${USER_NAME} 68 | echo "[DONE]" 69 | 70 | # Set directory permissions. 71 | printf "Setting permissions... " 72 | chown -R ${USER_NAME}: /jdownloader 73 | chown ${USER_NAME}: /media 74 | echo "[DONE]" 75 | 76 | #run functions############################## 77 | DectectOS 78 | AutoUpgrade 79 | #AddCredentials 80 | #SetDownloadFolder 81 | 82 | # Finally, start JDownloader. 83 | echo "Starting JDownloader..." 84 | exec su -pc "exec java -Djava.awt.headless=true -jar ${JDPATH}/JDownloader.jar 2>&1 >/dev/null" $USER_NAME -------------------------------------------------------------------------------- /rclone-mount/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG IMAGE_VERSION="v1.69.1" 2 | ARG OVERLAY_VERSION="v2.2.0.3" 3 | ARG OVERLAY_ARCH="amd64" 4 | ARG OVERLAY_KEY="6101B2783B2FD161" 5 | 6 | 7 | # Builder 8 | FROM golang:alpine AS builder 9 | 10 | ARG IMAGE_VERSION 11 | 12 | WORKDIR /go/src/github.com/rclone/rclone/ 13 | 14 | ENV GOPATH="/go" \ 15 | GO111MODULE="on" 16 | 17 | RUN apk add --no-cache --update ca-certificates go git \ 18 | && git clone https://github.com/rclone/rclone.git \ 19 | && cd rclone \ 20 | && git checkout tags/${IMAGE_VERSION} \ 21 | && go build 22 | 23 | 24 | # Image 25 | FROM alpine:latest 26 | 27 | ARG OVERLAY_VERSION 28 | ARG OVERLAY_ARCH 29 | ARG OVERLAY_KEY 30 | 31 | ENV DEBUG="false" \ 32 | AccessFolder="/mnt" \ 33 | RemotePath="mediaefs:" \ 34 | MountPoint="/mnt/mediaefs" \ 35 | ConfigDir="/config" \ 36 | ConfigName=".rclone.conf" \ 37 | MountCommands="--allow-other --allow-non-empty" \ 38 | UnmountCommands="-u -z" 39 | 40 | COPY --from=builder /go/src/github.com/rclone/rclone/rclone/rclone /usr/local/sbin/ 41 | 42 | RUN apk --no-cache upgrade \ 43 | && apk add --no-cache --update ca-certificates fuse3 fuse fuse-dev curl gnupg \ 44 | && echo "Installing S6 Overlay" \ 45 | && curl -o /tmp/s6-overlay.tar.gz -L \ 46 | "https://github.com/just-containers/s6-overlay/releases/download/${OVERLAY_VERSION}/s6-overlay-${OVERLAY_ARCH}.tar.gz" \ 47 | && curl -o /tmp/s6-overlay.tar.gz.sig -L \ 48 | "https://github.com/just-containers/s6-overlay/releases/download/${OVERLAY_VERSION}/s6-overlay-${OVERLAY_ARCH}.tar.gz.sig" \ 49 | && gpg --keyserver pgp.surfnet.nl --recv-keys ${OVERLAY_KEY} \ 50 | && gpg --verify /tmp/s6-overlay.tar.gz.sig /tmp/s6-overlay.tar.gz \ 51 | && tar xzf /tmp/s6-overlay.tar.gz -C / \ 52 | && apk del curl gnupg \ 53 | && rm -rf /tmp/* /var/cache/apk/* /var/lib/apk/lists/* 54 | 55 | COPY rootfs/ / 56 | 57 | VOLUME ["/mnt"] 58 | 59 | ENTRYPOINT ["/init"] 60 | 61 | # Use this docker Options in run 62 | # --cap-add SYS_ADMIN --device /dev/fuse --security-opt apparmor:unconfined 63 | # -v /path/to/config/.rclone.conf:/config/.rclone.conf 64 | # -v /mnt/mediaefs:/mnt/mediaefs:shared 65 | -------------------------------------------------------------------------------- /rclone-mount/README.md: -------------------------------------------------------------------------------- 1 | [rcloneurl]: https://rclone.org 2 | 3 | [![rclone.org](https://rclone.org/img/logo_on_dark__horizontal_color.svg)][rcloneurl] 4 | 5 | ## Rclone Mount Container 6 | 7 | Lightweight and simple Container Image (`alpine:latest - 58MB`) with compiled rclone (https://github.com/ncw/rclone). Mount your cloud storage like google drive inside a container and make it available to other containers like your Plex Server or on your hostsystem (mount namespace on the host is shared). You need a working rclone.conf (from another host or create it inside the container with entrypoint /bin/sh). all rclone remotes can be used. 8 | 9 | The Container uses S6 Overlay, to handle docker stop/restart ( fusermount -uz $MountPoint is applied on app crashes also) and also preparing the mountpoint. 10 | 11 | # Usage Example: 12 | 13 | docker run -d --name rclone-mount \ 14 | --restart=unless-stopped \ 15 | --cap-add SYS_ADMIN \ 16 | --device /dev/fuse \ 17 | --security-opt apparmor:unconfined \ 18 | -e RemotePath="mediaefs:" \ 19 | -e MountCommands="--allow-other --allow-non-empty" \ 20 | -v /path/to/config:/config \ 21 | -v /host/mount/point:/mnt/mediaefs:shared \ 22 | mumiehub/rclone-mount 23 | 24 | > mandatory docker commands: 25 | 26 | - --cap-add SYS_ADMIN --device /dev/fuse --security-opt apparmor:unconfined 27 | 28 | > needed volume mappings: 29 | 30 | - -v /path/to/config:/config 31 | - -v /host/mount/point:/mnt/mediaefs:shared 32 | 33 | # Environment Variables: 34 | 35 | | Variable | | Description | 36 | | ------------------------------------------------- | --- | --------------------------------------------------------------------------------------------------------------------------------- | 37 | | `RemotePath`="mediaefs:path" | | remote name in your rclone config, can be your crypt remote: + path/foo/bar | 38 | | `MountPoint`="/mnt/mediaefs" | | #INSIDE Container: needs to match mapping -v /host/mount/point:`/mnt/mediaefs:shared` | 39 | | `ConfigDir`="/config" | | #INSIDE Container: -v /path/to/config:/config | 40 | | `ConfigName`=".rclone.conf" | | #INSIDE Container: /config/.rclone.conf | 41 | | `MountCommands`="--allow-other --allow-non-empty" | | default mount commands, (if you not parse anything, defaults will be used) | 42 | | `UnmountCommands`="-u -z" | | default unmount commands | 43 | | `AccessFolder`="/mnt" | | access with --volumes-from rclone-mount, changes of AccessFolder have no impact because its the exposed folder in the dockerfile. | 44 | 45 | ## Use your own MountCommands with: 46 | 47 | ```vim 48 | -e MountCommands="--allow-other --allow-non-empty --dir-cache-time 48h --poll-interval 5m --buffer-size 128M" 49 | ``` 50 | 51 | All Commands can be found at [https://rclone.org/commands/rclone_mount/](https://rclone.org/commands/rclone_mount/). Use `--buffer-size 256M` (dont go too high), when you encounter some "Direct Stream" problems on Plex Server for example. 52 | 53 | ## Troubleshooting: 54 | 55 | When you force remove the container, you have to `sudo fusermount -u -z /host/mount/point` on the hostsystem! 56 | 57 | ## Todo 58 | 59 | - [ ] more settings 60 | - [ ] Auto Update Function 61 | - [ ] launch with specific USER_ID 62 | -------------------------------------------------------------------------------- /rclone-mount/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | mount-rclone01: 4 | image: mumiehub/rclone-mount:latest 5 | # privileged: true 6 | cap_add: 7 | - SYS_ADMIN 8 | devices: 9 | - /dev/fuse 10 | security_opt: 11 | - apparmor:unconfined 12 | environment: 13 | RemotePath: 'mediaefs:' 14 | MountCommands: --allow-other --uid 1000 --gid 1000 --umask 022 --default-permissions --allow-non-empty --dir-cache-time 168h --poll-interval 5m --buffer-size 128M 15 | stdin_open: true 16 | tty: true 17 | volumes: 18 | - /path/to/config:/config 19 | - /host/mount/point:/mnt/mediaefs:shared 20 | -------------------------------------------------------------------------------- /rclone-mount/rootfs/etc/colors.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | Color_Off='\033[0m' # Text Reset 4 | # Regular Colors 5 | Black='\033[0;30m' # Black 6 | Red='\033[0;31m' # Red 7 | Green='\033[0;32m' # Green 8 | Yellow='\033[0;33m' # Yellow 9 | Blue='\033[0;34m' # Blue 10 | Purple='\033[0;35m' # Purple 11 | Cyan='\033[0;36m' # Cyan 12 | White='\033[0;37m' # White 13 | # Bold 14 | BBlack='\033[1;30m' # Black 15 | BRed='\033[1;31m' # Red 16 | BGreen='\033[1;32m' # Green 17 | BYellow='\033[1;33m' # Yellow 18 | BBlue='\033[1;34m' # Blue 19 | BPurple='\033[1;35m' # Purple 20 | BCyan='\033[1;36m' # Cyan 21 | BWhite='\033[1;37m' # White 22 | -------------------------------------------------------------------------------- /rclone-mount/rootfs/etc/cont-finish.d/20-unmount: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv sh 2 | 3 | source /etc/colors.sh 4 | 5 | PREFFIX="[cont-finish.d] $(s6-basename ${0}):" 6 | 7 | #s6-svc -d /var/run/s6/services/rclone-mount 8 | #s6-svc -wD /var/run/s6/services/rclone-mount 9 | 10 | echo -e "${PREFFIX} ${Yellow}waiting for shutdown of all services${Color_Off}" 11 | #wait for all services to be down 12 | s6-svwait -D /var/run/s6/services/* 13 | 14 | #awk '/efsgoogle:/ && /\'$ENVIRON["MountPoint"]'/ {print; exit 1}' /proc/mounts 15 | 16 | #check if rclone gracefully unmounted 17 | if grep -Eq ''$RemotePath'.*'$MountPoint'|'$MountPoint'.*'$RemotePath'' /proc/mounts; then 18 | echo -e "${PREFFIX} ${Red}force unmounting with fusermount $UnmountCommands at: $(date +%Y.%m.%d-%T)${Color_Off}" 19 | fusermount $UnmountCommands $MountPoint 20 | wait ${!} 21 | exit 1 22 | else 23 | #cleanup of mount namespace 24 | umount $MountPoint 25 | echo -e "${PREFFIX} ${Green}successful unmounted${Color_Off}" 26 | exit 0 27 | fi -------------------------------------------------------------------------------- /rclone-mount/rootfs/etc/cont-init.d/20-init: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv sh 2 | 3 | source /etc/colors.sh 4 | 5 | PREFFIX="[cont-init.d] $(s6-basename ${0}):" 6 | 7 | #ENV 8 | OS="" 9 | ConfigPath="" 10 | 11 | #Functions 12 | DetectOS(){ 13 | if [ -e /etc/alpine-release ]; then 14 | OS="alpine" 15 | elif [ -e /etc/os-release ]; then 16 | if /bin/grep -q "NAME=\"Ubuntu\"" /etc/os-release ; then 17 | OS="ubuntu" 18 | fi 19 | fi 20 | } 21 | 22 | AutoUpgrade(){ 23 | if [ "${OS}" == "alpine" ]; then 24 | /sbin/apk --no-cache upgrade 25 | /bin/rm -rf /var/cache/apk/* 26 | elif [ "${OS}" == "ubuntu" ]; then 27 | export DEBIAN_FRONTEND=noninteractive 28 | /usr/bin/apt-get update 29 | /usr/bin/apt-get -y --no-install-recommends dist-upgrade 30 | /usr/bin/apt-get -y autoclean 31 | /usr/bin/apt-get -y clean 32 | /usr/bin/apt-get -y autoremove 33 | /bin/rm -rf /var/lib/apt/lists/* 34 | fi 35 | } 36 | 37 | #fix Mountpoint Syntax 38 | #remove / at the end #todo 39 | 40 | #create folders 41 | mkdir -p \ 42 | $MountPoint \ 43 | $ConfigDir 44 | 45 | #export ConfigPath="$ConfigDir/$ConfigName env" 46 | printf "$ConfigDir/$ConfigName" > /var/run/s6/container_environment/ConfigPath 47 | 48 | echo -e "${PREFFIX} ${Blue}installing system updates${Color_Off}" 49 | DetectOS 50 | AutoUpgrade -------------------------------------------------------------------------------- /rclone-mount/rootfs/etc/cont-init.d/30-check: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv sh 2 | 3 | source /etc/colors.sh 4 | 5 | PREFFIX="[cont-init.d] $(s6-basename ${0}):" 6 | 7 | #check if the MountPoint is empty 8 | if [ "$(ls -A ${MountPoint})" ]; then 9 | echo -e "${PREFFIX} ${Red}MountPoint folder not empty[ERROR]${Color_Off}" 10 | #todo 11 | fi 12 | 13 | #check for other fsmounts, stop mounting if other MountPoint exists 14 | #mount | grep -c $MountPoint 15 | 16 | if grep -Eq ''$RemotePath'.*'$MountPoint'|'$MountPoint'.*'$RemotePath'' /proc/mounts; then 17 | #exit container here 18 | echo -e "${PREFFIX} ${Red}found other MountPoint in /proc/mounts${Color_Off}" 19 | #cleanup mountpoint 20 | exit 1 21 | else 22 | echo -e "${PREFFIX} ${Green}MountPoint $MountPoint is ready${Color_Off}" 23 | exit 0 24 | fi -------------------------------------------------------------------------------- /rclone-mount/rootfs/etc/services.d/rclone-mount/finish: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv sh 2 | 3 | #set -x 4 | 5 | source /etc/colors.sh 6 | 7 | PREFFIX="[services.d] [rclone-mount]-$(s6-basename ${0}):" 8 | 9 | SERVICE_DIR=/var/run/s6/services 10 | SERVICE=rclone-mount 11 | 12 | checkRclone(){ 13 | ps aux | grep '.rclon[e].*'$RemotePath'' | grep -v grep > /dev/null 14 | return $? 15 | } 16 | 17 | #s6-echo "shutdown rclone mount[DEBUG]" 18 | if checkRclone; then 19 | s6-svc -d ${SERVICE_DIR}/${SERVICE} 20 | # s6-svc -t ${SERVICE_DIR}/${SERVICE} 21 | tempPID="$(pgrep rclon[e])" 22 | kill ${tempPID} 23 | else 24 | echo -e "${PREFFIX} ${Red}rclone process not present, restarting container[ERROR]${Color_Off}" 25 | s6-svscanctl -t /var/run/s6/services 26 | fi 27 | 28 | echo -e "${PREFFIX} ${Yellow}waiting for rclone shutdown${Color_Off}" 29 | while checkRclone -eq 0; do 30 | sleep 0.1 31 | done 32 | 33 | 34 | #bring container down when rclone crashes 35 | #s6-svscanctl -t /var/run/s6/services 36 | 37 | #while $(pgrep rclon[e] > /dev/null); do 38 | # sleep 0.1 39 | #done 40 | 41 | #s6-svc -wD /var/run/s6/services/rclone-mount/ 42 | 43 | #if ps aux | grep 's6-supervise rclone-mount' | grep -v grep > /dev/null; then s6-svc -t /var/run/s6/services/rclone-mount; fi; 44 | -------------------------------------------------------------------------------- /rclone-mount/rootfs/etc/services.d/rclone-mount/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv sh 2 | 3 | #set -x 4 | 5 | source /etc/colors.sh 6 | 7 | PREFFIX="[services.d] [rclone-mount]-$(s6-basename ${0}):" 8 | 9 | echo -e "${PREFFIX} ${Green}starting rclone mount $(date +%Y.%m.%d-%T)${Color_Off}" 10 | 11 | ## ECHO DEBUG 12 | if [ "$DEBUG" = true ]; then 13 | echo -e "${PREFFIX} [DEBUG] command: /usr/local/sbin/rclone --config $ConfigPath mount $RemotePath $MountPoint $MountCommands" 14 | fi 15 | 16 | /usr/local/sbin/rclone --config $ConfigPath mount $RemotePath $MountPoint $MountCommands 17 | -------------------------------------------------------------------------------- /rclone-mount/rootfs/healthcheck.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | #/proc/mount check -------------------------------------------------------------------------------- /rclone-mount/version: -------------------------------------------------------------------------------- 1 | v1.69.1 2 | -------------------------------------------------------------------------------- /sabnzbdvpn/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:focal 2 | 3 | ARG DUMB_INIT_VERSION="1.2.5" 4 | ARG DUMB_INIT_ARCH="amd64" 5 | 6 | ENV LANG="en_US.UTF-8" \ 7 | LANGUAGE="en_US.UTF-8" \ 8 | LC_ALL="en_US.UTF-8" \ 9 | USER_NAME="abc" \ 10 | PUID=1003 \ 11 | PGID=1003 \ 12 | # OPENVPN_USERNAME="" \ 13 | # OPENVPN_PASSWORD="" \ 14 | OPENVPN_CONFIG_DIR="/etc/openvpn/custom" \ 15 | OPENVPN_CONFIG="default.ovpn" \ 16 | SABNZBD_CONFIG_DIR="/config" \ 17 | DOWNLOAD_DIR="/tmp/media/downloads" \ 18 | INCOMPLETE_DIR="/tmp/media/incomplete" \ 19 | WATCH_DIR="" 20 | 21 | RUN apt-get update \ 22 | && apt-get install -y software-properties-common sudo curl wget nano locales python3-sabyenc python3-chardet p7zip-full unzip \ 23 | && add-apt-repository ppa:jcfp/ppa \ 24 | && add-apt-repository ppa:jcfp/sab-addons \ 25 | && echo "install openvpn and sabnzbdplus packages" \ 26 | && apt-get install -y openvpn sabnzbdplus par2-tbb \ 27 | && locale-gen en_US.UTF-8 \ 28 | && curl -sLO https://github.com/Yelp/dumb-init/releases/download/v${DUMB_INIT_VERSION}/dumb-init_${DUMB_INIT_VERSION}_${DUMB_INIT_ARCH}.deb \ 29 | && dpkg -i dumb-init_*.deb \ 30 | && rm -rf dumb-init_*.deb \ 31 | && echo "cleanup tasks" \ 32 | && apt-get clean \ 33 | && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* \ 34 | && groupmod -g 1000 users \ 35 | && mkdir -p /home/${USER_NAME} \ 36 | && useradd -u ${PUID} -U -d /home/${USER_NAME} -s /bin/false ${USER_NAME} \ 37 | && usermod -G users ${USER_NAME} 38 | 39 | ADD openvpn/ /etc/openvpn/ 40 | ADD scripts/ /scripts/ 41 | RUN chmod +x /etc/openvpn/start.sh \ 42 | && chmod +x /scripts/*.sh 43 | 44 | VOLUME $DOWNLOAD_DIR $SABNZBD_CONFIG_DIR 45 | 46 | EXPOSE 8080 8090 47 | 48 | ENTRYPOINT ["/usr/bin/dumb-init", "--"] 49 | 50 | CMD ["/etc/openvpn/start.sh"] 51 | -------------------------------------------------------------------------------- /sabnzbdvpn/README.md: -------------------------------------------------------------------------------- 1 | # SABnzbd and OpenVPN 2 | 3 | Docker container which runs SABnzbd while connected to OpenVPN. 4 | 5 | ## Run container from Docker registry 6 | To run the container use this command for example: 7 | 8 | ``` 9 | docker run -d --name sabnzbdvpn \ 10 | -v /host/storage/path:/config \ 11 | -v /path/to/openvpnconfigdir:/etc/openvpn/custom 12 | -v /etc/localtime:/etc/localtime:ro \ 13 | -e "LOCAL_NETWORK=192.168.0.0/24" \ 14 | -p 8080:8080 \ 15 | mumiehub/sabnzbdvpn 16 | ``` 17 | 18 | 19 | 20 | ### Environment options passed with docker -e 21 | | Variable | Function | Notes | 22 | |----------|----------|----------| 23 | |`OPENVPN_CONFIG_DIR` |OpenVPN config dir. | Default is `"/etc/openvpn/custom"` needs to match mappings. | 24 | |`OPENVPN_CONFIG`|OpenVPN config filename | Default name is `default.ovpn`| 25 | |`SABNZBD_CONFIG_DIR`|SABnzbd data dir |#inside Container. default `"/config"`, needs to match hostmountpoint| 26 | |`DOWNLOAD_DIR`|SABnzbd download dir|#inside Container. This is where SABnzbd will store your downloads. Default `"/tmp/media/downloads"`| 27 | |`INCOMPLETE_DIR`|SABnzbd incomplete dir|inside the Container. This is where SABnzbd will store your incomplete downloads| 28 | 29 | 30 | ### Network configuration options 31 | | Variable | Function | Example | 32 | |----------|----------|---------| 33 | |`OPENVPN_OPTS` | Will be passed to OpenVPN on startup | See [OpenVPN doc](https://openvpn.net/index.php/open-source/documentation/manuals/65-openvpn-20x-manpage.html) | 34 | |`LOCAL_NETWORK` | Sets the local network that should have access to the GUI | `LOCAL_NETWORK=192.168.0.0/24`| 35 | 36 | 37 | #### User configuration options 38 | 39 | By default OpenVPN will run as the root user and SABnzbd will run as user abc `1003:1003`. You may set the following parameters to customize the user id that runs SABnzbd. 40 | 41 | | Variable | Function | Example | 42 | |----------|----------|-------| 43 | |`-e PUID` | Sets the user id who will run SABnzbd | Default = `PUID=1003`| 44 | |`-e PGID` | Sets the group id for the SABnzbd user | Default = `PGID=1003` | 45 | 46 | 47 | ## Access the WebUI of SABnzbd 48 | 49 | If you set `LOCAL_NETWORK` correctly, the WebUI of SABnzbd should be at http://containerhost:8080. If its not responding, there might be an error with your 50 | `LOCAL_NETWORK` subnet settings. 51 | 52 | ### How to fix this: 53 | The container supports the `LOCAL_NETWORK` environment variable. For instance if your local network uses the subnet 192.168.0.0/24 you should pass `-e LOCAL_NETWORK=192.168.0.0/24`. It must match your subnet, else your traffic will be "non-local" traffic and therefore be routed out through the VPN interface. 54 | 55 | Alternatively you can reverse proxy the traffic through another container, as that container would be in the docker range. 56 | Nginx with proxypass config. 57 | 58 | ``` 59 | $ docker run -d \ 60 | --link \ 61 | -p 8080:8080 \ 62 | nginx:latest 63 | ``` 64 | 65 | 66 | ## Tips and Tricks 67 | 68 | ### Using your ovpn config file 69 | 70 | Add a new volume mount to your `docker run` command that mounts your config file: 71 | 72 | -v /path/to/config.ovpn:/etc/openvpn/custom/default.ovpn 73 | 74 | If you have an separate ca.crt file your volume mount should be a folder containing both the ca.crt and the .ovpn config. 75 | 76 | #### Use Google DNS servers 77 | Some have encountered problems with DNS resolving inside the docker container. 78 | This causes trouble because OpenVPN will not be able to resolve the host to connect to. 79 | If you have this problem use dockers --dns flag to override the resolv.conf of the container. 80 | For example use googles dns servers by adding --dns 8.8.8.8 --dns 8.8.4.4 as parameters to the usual run command. 81 | 82 | #### Restart container if connection is lost 83 | If the VPN connection fails or the container for any other reason loses connectivity, you want it to recover from it. One way of doing this is to set environment variable `OPENVPN_OPTS=--inactive 3600 --ping 10 --ping-exit 60` and use the --restart=always flag when starting the container. This way OpenVPN will exit if ping fails over a period of time which will stop the container and then the Docker deamon will restart it. 84 | 85 | #### Wrong link mtu 86 | 87 | When your are using a managed network layer for example, the default link mtu of 1500 can be to big. Setting a lower mtu in OpenVPN should help: 88 | `-e OPENVPN_OPTS=--tun-mtu 1300` 89 | -------------------------------------------------------------------------------- /sabnzbdvpn/openvpn/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | #. /etc/profile 4 | 5 | # add OpenVPN user/pass deprecated 6 | #if [ "${OPENVPN_USERNAME}" = "" ] || [ "${OPENVPN_PASSWORD}" = "" ] ; then 7 | # echo "OpenVPN credentials not set. No credentials.txt will be created" 8 | #else 9 | # echo "Setting OPENVPN credentials.txt ..." 10 | # echo $OPENVPN_USERNAME > /etc/openvpn/custom/openvpn-credentials.txt 11 | # echo $OPENVPN_PASSWORD >> /etc/openvpn/custom/openvpn-credentials.txt 12 | # chmod 600 /etc/openvpn/custom/openvpn-credentials.txt 13 | #fi 14 | 15 | #set routing gateway for the container 16 | if [ -n "${LOCAL_NETWORK-}" ]; then 17 | eval $(/sbin/ip r s 0.0.0.0/0 | awk '{if($5!="tun0"){print "GW="$3"\nINT="$5; exit}}') 18 | if [ -n "${GW-}" -a -n "${INT-}" ]; then 19 | echo "adding route to local network $LOCAL_NETWORK via $GW dev $INT" 20 | /sbin/ip r a "$LOCAL_NETWORK" via "$GW" dev "$INT" 21 | fi 22 | fi 23 | 24 | . /scripts/userSetup.sh 25 | 26 | CONTROL_OPTS="--script-security 3 --route-up /scripts/start.sh --route-pre-down /scripts/stop.sh" 27 | OPENVPN_CONFIG_PATH="$OPENVPN_CONFIG_DIR/$OPENVPN_CONFIG" 28 | 29 | #printf "USER=${USER_NAME}\nHOST=0.0.0.0\nPORT=8080\nCONFIG=${SABNZBD_CONFIG_DIR}\n" > /etc/default/sabnzbdplus \ 30 | #/etc/init.d/sabnzbdplus start 31 | 32 | exec openvpn $CONTROL_OPTS $OPENVPN_OPTS --config "$OPENVPN_CONFIG_PATH" -------------------------------------------------------------------------------- /sabnzbdvpn/scripts/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | #. /etc/profile 4 | 5 | # See https://openvpn.net/index.php/open-source/documentation/manuals/65-openvpn-20x-manpage.html (--up cmd) 6 | 7 | if [ ! -e "/dev/random" ]; then 8 | # Avoid "Fatal: no entropy gathering module detected" error 9 | echo "INFO: /dev/random not found - symlink to /dev/urandom" 10 | ln -s /dev/urandom /dev/random 11 | fi 12 | 13 | echo "STARTING SABNZBD with USER ${USER_NAME}" 14 | 15 | # ENV Variables missing - fix needed 16 | exec sudo -u abc /usr/bin/sabnzbdplus --config-file /config --server 0.0.0.0:8080 & 17 | 18 | echo "Startup script SABnzbd completed." 19 | -------------------------------------------------------------------------------- /sabnzbdvpn/scripts/stop.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | #. /etc/profile 4 | 5 | #kill $(ps aux | grep sabnzbdplus | grep -v grep | awk '{print $2}') 6 | 7 | tempPID="$(pgrep sabnzbdplus)" 8 | kill ${tempPID} -------------------------------------------------------------------------------- /sabnzbdvpn/scripts/userSetup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | . /etc/profile 4 | 5 | # More/less taken from https://github.com/linuxserver/docker-baseimage-alpine/blob/3eb7146a55b7bff547905e0d3f71a26036448ae6/root/etc/cont-init.d/10-adduser 6 | 7 | USER_HOME=/home/${USER_NAME} 8 | 9 | mkdir -p ${USER_HOME} \ 10 | ${SABNZBD_CONFIG_DIR} \ 11 | ${DOWNLOAD_DIR} \ 12 | ${INCOMPLETE_DIR} \ 13 | ${WATCH_DIR} 14 | 15 | if [ -n "$PUID" ]; then 16 | if [ ! "$(id -u ${USER_NAME})" -eq "$PUID" ]; then usermod -o -u "$PUID" ${USER_NAME} ; fi 17 | if [ ! "$(id -g ${USER_NAME})" -eq "$PGID" ]; then groupmod -o -g "$PGID" ${USER_NAME} ; fi 18 | fi 19 | 20 | echo "Setting owner for Folder paths to ${PUID}:${PGID}" 21 | 22 | chown -f -R ${USER_NAME}:${USER_NAME} \ 23 | ${USER_HOME} \ 24 | ${SABNZBD_CONFIG_DIR} \ 25 | ${DOWNLOAD_DIR} \ 26 | ${INCOMPLETE_DIR} \ 27 | ${WATCH_DIR} 28 | 29 | echo " 30 | ------------------------------------- 31 | Sabnzbd will run as 32 | ------------------------------------- 33 | User name: ${USER_NAME} 34 | User uid: $(id -u ${USER_NAME}) 35 | User gid: $(id -g ${USER_NAME}) 36 | ------------------------------------- 37 | " -------------------------------------------------------------------------------- /smb-mount/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:latest 2 | 3 | ARG OVERLAY_VERSION="v2.2.0.3" 4 | ARG OVERLAY_ARCH="amd64" 5 | 6 | ENV DEBUG="false" \ 7 | SERVERPATH="//192.168.1.1/example" \ 8 | MOUNTPOINT="/mnt/smb" \ 9 | MOUNTOPTIONS="vers=3.1.1,uid=1000,gid=1000,rw,username=user,password=example" \ 10 | UMOUNTOPTIONS="-a -t cifs -l" \ 11 | AccessFolder="/mnt" 12 | 13 | RUN apk --no-cache upgrade \ 14 | && apk add --no-cache --update cifs-utils bash tar curl ca-certificates gnupg grep \ 15 | && curl -o /tmp/s6-overlay.tar.gz -L \ 16 | "https://github.com/just-containers/s6-overlay/releases/download/${OVERLAY_VERSION}/s6-overlay-${OVERLAY_ARCH}.tar.gz" \ 17 | && curl -o /tmp/s6-overlay.tar.gz.sig -L \ 18 | "https://github.com/just-containers/s6-overlay/releases/download/${OVERLAY_VERSION}/s6-overlay-${OVERLAY_ARCH}.tar.gz.sig" \ 19 | # && curl https://keybase.io/justcontainers/key.asc | gpg --import \ 20 | && gpg --keyserver pgp.surfnet.nl --recv-keys 6101B2783B2FD161 \ 21 | && gpg --verify /tmp/s6-overlay.tar.gz.sig /tmp/s6-overlay.tar.gz \ 22 | && tar xfz /tmp/s6-overlay.tar.gz -C / \ 23 | && apk del tar curl gnupg \ 24 | && rm -rf /tmp/* /var/cache/apk/* /var/lib/apk/lists/* 25 | 26 | # add local files 27 | COPY rootfs/ / 28 | 29 | #VOLUME ["/mnt"] 30 | 31 | ENTRYPOINT ["/init"] 32 | 33 | # HEALTHCHECK --interval=5s --timeout=2s --retries=20 CMD /healthcheck.sh || exit 1 34 | 35 | # Use this args in docker run 36 | # --cap-add SYS_ADMIN --cap-add DAC_READ_SEARCH --security-opt apparmor:unconfined 37 | -------------------------------------------------------------------------------- /smb-mount/README.md: -------------------------------------------------------------------------------- 1 | 2 | SMB Mount Container based on `alpine:latest` 3 | --- 4 | 5 | 6 | Lightweight and simple alpine container image with cifs-utils installed. 7 | 8 | 9 | # Usage Example: 10 | 11 | docker run -d --name smb-mount \ 12 | --restart=unless-stopped \ 13 | --cap-add SYS_ADMIN \ 14 | --cap-add DAC_READ_SEARCH \ 15 | --security-opt apparmor:unconfined \ 16 | -e SERVERPATH="//exampleserver/folder" \ 17 | -e MOUNTOPTIONS="vers=3.1.1,uid=1000,gid=1000,rw,username=user,password=example" \ 18 | -v /mnt/HostMountPoint:/mnt/smb:shared \ 19 | mumiehub/smb-mount 20 | --- 21 | docker run -d --name smb-mount --restart=unless-stopped --cap-add SYS_ADMIN --cap-add DAC_READ_SEARCH --security-opt apparmor:unconfined -e SERVERPATH="//exampleserver/folder" -e MOUNTOPTIONS="vers=3.1.1,uid=1000,gid=1000,rw,username=user,password=example" -v /mnt/HostMountPoint:/mnt/smb:shared mumiehub/smb-mount 22 | 23 | 24 | > mendatory commands: 25 | 26 | - --cap-add SYS_ADMIN --cap-add DAC_READ_SEARCH --security-opt apparmor:unconfined 27 | 28 | 29 | > needed volume mappings: 30 | 31 | - -v /mnt/HostMountPoint:/mnt/smb:shared 32 | 33 | 34 | # Environment Variables: 35 | 36 | ```vim 37 | AccessFolder="/mnt" 38 | "access test 39 | 40 | SERVERPATH="//192.168.1.1/example" 41 | "SMB Server Hostname or IP 42 | 43 | MOUNTPOINT="/mnt/smb" "INSIDE Container: needs to match volume mapping -v /mnt/HostMountPoint:/mnt/smb:shared 44 | 45 | MOUNTOPTIONS="vers=3.1.1,uid=1000,gid=1000,rw,username=user,password=example" 46 | "Mount Commands with Username and Password 47 | 48 | UMOUNTOPTIONS="-a -t cifs -l" 49 | ``` 50 | 51 | 52 | ### Set Folder Permissions: 53 | ``` 54 | MOUNTOPTIONS="vers=3.1.1,uid=1000,gid=1000,file_mode=0755,dir_mode=0755,rw,username=user,password=example" 55 | ``` 56 | 57 | ## Troubleshooting: 58 | When you force remove the container, you have to `sudo umount /mnt/smb` on the hostsystem! 59 | 60 | Mounting Windows Server 2016 SMB shares works with `MOUNTOPTIONS="vers=3.02"`! 61 | 62 | 63 | 64 | Todo 65 | ---- 66 | 67 | * [ ] more settings 68 | * [ ] more specific FAQ and Troubleshooting help 69 | * [ ] launch with specific USER_ID 70 | 71 | ## License 72 | 73 | See [LICENSE](LICENSE) -------------------------------------------------------------------------------- /smb-mount/rootfs/etc/colors.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | Color_Off='\033[0m' # Text Reset 4 | # Regular Colors 5 | Black='\033[0;30m' # Black 6 | Red='\033[0;31m' # Red 7 | Green='\033[0;32m' # Green 8 | Yellow='\033[0;33m' # Yellow 9 | Blue='\033[0;34m' # Blue 10 | Purple='\033[0;35m' # Purple 11 | Cyan='\033[0;36m' # Cyan 12 | White='\033[0;37m' # White 13 | # Bold 14 | BBlack='\033[1;30m' # Black 15 | BRed='\033[1;31m' # Red 16 | BGreen='\033[1;32m' # Green 17 | BYellow='\033[1;33m' # Yellow 18 | BBlue='\033[1;34m' # Blue 19 | BPurple='\033[1;35m' # Purple 20 | BCyan='\033[1;36m' # Cyan 21 | BWhite='\033[1;37m' # White -------------------------------------------------------------------------------- /smb-mount/rootfs/etc/cont-finish.d/20-unmount: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | 3 | source /etc/colors.sh 4 | 5 | PREFFIX="[cont-finish.d] $(s6-basename ${0}):" 6 | 7 | if grep -qs "$MOUNTPOINT" /proc/mounts; then 8 | echo -e "${PREFFIX} ${Green}unmounting $MOUNTPOINT $(date +%Y.%m.%d-%T)${Color_Off}" 9 | umount $UMOUNTOPTIONS $MOUNTPOINT 10 | wait ${!} 11 | exit 0 12 | else 13 | echo -e "${PREFFIX}nothing to unmount" 14 | exit 1 15 | fi -------------------------------------------------------------------------------- /smb-mount/rootfs/etc/cont-init.d/20-config: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | 3 | source /etc/colors.sh 4 | 5 | PREFFIX="[cont-init.d] $(s6-basename ${0}):" 6 | 7 | #fix Mountpoint Syntax 8 | #remove / at the end 9 | 10 | #create folders 11 | 12 | #create mountpoint folder 13 | if [ ! -d "${MOUNTPOINT}" ]; then \ 14 | mkdir -p \ 15 | $MOUNTPOINT 16 | fi 17 | 18 | #check if the MOUNTPOINT is empty 19 | if [ "$(ls -A ${MOUNTPOINT})" ]; then 20 | echo -e "${PREFFIX} ${Red}MountPoint folder not empty[ERROR]${Color_Off}" 21 | #todo 22 | fi 23 | 24 | #check for other fsmounts, stop mounting if other mountpoint exists 25 | #mount | grep -c $MOUNTPOINT 26 | 27 | if grep -qs "$MOUNTPOINT" /proc/mounts; then 28 | #exit container here if other mountpoint than docker volume mount is found 29 | #todo 30 | echo -e "${PREFFIX} found other mountpoint in /proc/mounts${Color_Off}" 31 | exit 1 32 | else 33 | echo "mountpoint $MOUNTPOINT is ready" 34 | fi -------------------------------------------------------------------------------- /smb-mount/rootfs/etc/services.d/cifs/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | 3 | #set -x 4 | 5 | source /etc/colors.sh 6 | 7 | PREFFIX="[services.d] [smb-mount]-$(s6-basename ${0}):" 8 | 9 | echo -e "${PREFFIX} ${Green}starting smb mount $(date +%Y.%m.%d-%T)${Color_Off}" 10 | 11 | ## ECHO DEBUG 12 | if [ "$DEBUG" = true ]; then 13 | echo -e "${PREFFIX} [DEBUG] command: mount -t cifs -o $MOUNTOPTIONS $SERVERPATH $MOUNTPOINT" 14 | fi 15 | 16 | mount -t cifs -o $MOUNTOPTIONS $SERVERPATH $MOUNTPOINT 17 | 18 | while true 19 | do 20 | sleep 100 21 | done -------------------------------------------------------------------------------- /smb-mount/rootfs/healthcheck.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | #/proc/mount check -------------------------------------------------------------------------------- /smb-mount/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | mountCheck=`mount | grep -c $MOUNTPOINT` 4 | 5 | echo "=============================================" 6 | echo "Mounting SMB $SERVERPATH to $MOUNTPOINT at $(date +%Y.%m.%d-%T)" 7 | 8 | #export EnvVariable 9 | 10 | function term_handler { 11 | unmount_smb 12 | echo "exiting container now" 13 | exit 0 14 | } 15 | 16 | function unmount_smb { 17 | echo "Unmounting: $MOUNTPOINT $(date +%Y.%m.%d-%T)" 18 | umount $UMOUNTOPTIONS $MOUNTPOINT 19 | wait ${!} 20 | #sleep 1 21 | } 22 | 23 | trap term_handler SIGHUP SIGINT SIGTERM 24 | 25 | mount -t cifs -o $MOUNTOPTIONS $SERVERPATH $MOUNTPOINT 26 | 27 | if [ $mountCheck -eq 0 ] ; then 28 | echo "Error mounting $SERVERPATH $(date +%Y.%m.%d-%T)" 29 | exit 146 30 | fi 31 | 32 | while true 33 | do 34 | sleep 100 35 | done -------------------------------------------------------------------------------- /teamspeakserver/Dockerfile: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------------- 2 | # Builds a basic docker alpine image that can run TeamSpeak from a folder 3 | # 4 | # Updated: Nov 09, 2017 5 | # ------------------------------------------------------------------------------- 6 | 7 | FROM alpine:latest 8 | 9 | ENV USER_NAME="teamspeak" \ 10 | USER_UID="1001" \ 11 | DATA_DIR="/teamspeak" \ 12 | TS_VERSION="LATEST" \ 13 | TS3ARGS="" \ 14 | GLIBC_VERSION=2.30-r0 15 | 16 | RUN apk add --no-cache --update bzip2 ca-certificates openssl python3 \ 17 | && wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub \ 18 | && wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_VERSION}/glibc-${GLIBC_VERSION}.apk \ 19 | && apk add glibc-${GLIBC_VERSION}.apk \ 20 | && adduser -D -u ${USER_UID} -s /bin/false $USER_NAME \ 21 | && apk del openssl \ 22 | && rm -rf /tmp/* /var/cache/apk/* /var/lib/apk/lists/* 23 | 24 | ADD start.sh /start.sh 25 | ADD get-version.py /get-version.py 26 | RUN chmod +x /start.sh \ 27 | && chmod +x /get-version.py 28 | 29 | #VOLUME ["/teamspeak"] 30 | EXPOSE 9987/udp 30033 10011 31 | 32 | #CMD ["/teamspeak/ts3server", "-LD_LIBRARY_PATH=/teamspeak"] 33 | 34 | USER $USER_NAME 35 | 36 | CMD ["/start.sh"] -------------------------------------------------------------------------------- /teamspeakserver/get-version.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import json 4 | from urllib.request import urlopen 5 | 6 | url = "https://www.server-residenz.com/tools/ts3versions.json" 7 | response = urlopen(url) 8 | data = json.loads(response.read().decode("utf-8")) 9 | print(data['latest']) -------------------------------------------------------------------------------- /teamspeakserver/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | case $TS_VERSION in 4 | LATEST) 5 | export TS_VERSION=`/get-version.py` 6 | ;; 7 | esac 8 | #echo "$TS_VERSION" handle Update here! 9 | echo "$TS_VERSION" > /teamspeak/ts-version.docker 10 | 11 | cd $DATA_DIR 12 | 13 | TARFILE=teamspeak3-server_linux_amd64-$TS_VERSION.tar.bz2 14 | 15 | if [ ! -e ${TARFILE} ]; then 16 | echo "Downloading $TARFILE ..." 17 | wget -q http://dl.4players.de/ts/releases/$TS_VERSION/$TARFILE #\ 18 | ##&& tar -j -x -f $TARFILE 19 | fi 20 | 21 | export LD_LIBRARY_PATH='/teamspeak' 22 | 23 | #if [ -e /$DATA_DIR/ts3server.ini ]; then 24 | # TS3ARGS="inifile=/$DATA_DIR/ts3server.ini" 25 | #else 26 | # TS3ARGS="createinifile=1" 27 | #fi 28 | 29 | exec $DATA_DIR/ts3server $TS3ARGS --------------------------------------------------------------------------------