diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..cdb1a82 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,6 @@ +.git +.gitignore +.github +.gitattributes +READMETEMPLATE.md +README.md diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..bdb0cab --- /dev/null +++ b/.gitattributes @@ -0,0 +1,17 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# Custom for Visual Studio +*.cs diff=csharp + +# Standard to msysgit +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100755 index 0000000..7972213 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +open_collective: linuxserver diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..c73c33b --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,21 @@ + + +[linuxserverurl]: https://linuxserver.io +[![linuxserver.io](https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/linuxserver_medium.png)][linuxserverurl] + + + + + + + + + + + + + + + +## Thanks, team linuxserver.io + diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..f6a6381 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,15 @@ + + +[linuxserverurl]: https://linuxserver.io +[![linuxserver.io](https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/linuxserver_medium.png)][linuxserverurl] + + + + + + + + + +## Thanks, team linuxserver.io + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..96374c4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# ========================= +# Operating System Files +# ========================= + +# OSX +# ========================= + +.DS_Store +.AppleDouble +.LSOverride + +# Thumbnails +._* + +# Files that might appear on external disk +.Spotlight-V100 +.Trashes + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..0921398 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,22 @@ +FROM lsiobase/alpine:3.10 + +# set version label +ARG BUILD_DATE +ARG VERSION +LABEL build_version="Linuxserver.io version:- ${VERSION} Build-date:- ${BUILD_DATE}" +LABEL maintainer="aptalca" + +RUN \ + echo "**** install runtime packages ****" && \ + apk add --no-cache --upgrade \ + openssh-server \ + sudo && \ + echo "**** setup openssh environment ****" && \ + sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/g' /etc/ssh/sshd_config && \ + ssh-keygen -A && \ + usermod --shell /bin/bash abc && \ + rm -rf \ + /tmp/* + +# add local files +COPY /root / \ No newline at end of file diff --git a/Dockerfile.aarch64 b/Dockerfile.aarch64 new file mode 100644 index 0000000..bb97923 --- /dev/null +++ b/Dockerfile.aarch64 @@ -0,0 +1,22 @@ +FROM lsiobase/alpine:arm64v8-3.10 + +# set version label +ARG BUILD_DATE +ARG VERSION +LABEL build_version="Linuxserver.io version:- ${VERSION} Build-date:- ${BUILD_DATE}" +LABEL maintainer="aptalca" + +RUN \ + echo "**** install runtime packages ****" && \ + apk add --no-cache --upgrade \ + openssh-server \ + sudo && \ + echo "**** setup openssh environment ****" && \ + sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/g' /etc/ssh/sshd_config && \ + ssh-keygen -A && \ + usermod --shell /bin/bash abc && \ + rm -rf \ + /tmp/* + +# add local files +COPY /root / \ No newline at end of file diff --git a/Dockerfile.armhf b/Dockerfile.armhf new file mode 100644 index 0000000..e3230db --- /dev/null +++ b/Dockerfile.armhf @@ -0,0 +1,22 @@ +FROM lsiobase/alpine:arm32v7-3.10 + +# set version label +ARG BUILD_DATE +ARG VERSION +LABEL build_version="Linuxserver.io version:- ${VERSION} Build-date:- ${BUILD_DATE}" +LABEL maintainer="aptalca" + +RUN \ + echo "**** install runtime packages ****" && \ + apk add --no-cache --upgrade \ + openssh-server \ + sudo && \ + echo "**** setup openssh environment ****" && \ + sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/g' /etc/ssh/sshd_config && \ + ssh-keygen -A && \ + usermod --shell /bin/bash abc && \ + rm -rf \ + /tmp/* + +# add local files +COPY /root / \ No newline at end of file diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..af1f172 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,681 @@ +pipeline { + agent { + label 'X86-64-MULTI' + } + // Input to determine if this is a package check + parameters { + string(defaultValue: 'false', description: 'package check run', name: 'PACKAGE_CHECK') + } + // Configuration for the variables used for this specific repo + environment { + BUILDS_DISCORD=credentials('build_webhook_url') + GITHUB_TOKEN=credentials('498b4638-2d02-4ce5-832d-8a57d01d97ab') + CONTAINER_NAME = 'openssh-server' + BUILD_VERSION_ARG = 'OPENSSH_RELEASE' + LS_USER = 'linuxserver' + LS_REPO = 'docker-openssh-server' + DOCKERHUB_IMAGE = 'linuxserver/openssh-server' + DEV_DOCKERHUB_IMAGE = 'lsiodev/openssh-server' + PR_DOCKERHUB_IMAGE = 'lspipepr/openssh-server' + DIST_IMAGE = 'alpine' + MULTIARCH='true' + CI='true' + CI_WEB='false' + CI_PORT='80' + CI_SSL='false' + CI_DELAY='60' + CI_DOCKERENV='TZ=US/Pacific' + CI_AUTH='user:password' + CI_WEBPATH='' + } + stages { + // Setup all the basic environment variables needed for the build + stage("Set ENV Variables base"){ + steps{ + script{ + env.EXIT_STATUS = '' + env.LS_RELEASE = sh( + script: '''docker run --rm alexeiled/skopeo sh -c 'skopeo inspect docker://docker.io/'${DOCKERHUB_IMAGE}':latest 2>/dev/null' | jq -r '.Labels.build_version' | awk '{print $3}' | grep '\\-ls' || : ''', + returnStdout: true).trim() + env.LS_RELEASE_NOTES = sh( + script: '''cat readme-vars.yml | awk -F \\" '/date: "[0-9][0-9].[0-9][0-9].[0-9][0-9]:/ {print $4;exit;}' | sed -E ':a;N;$!ba;s/\\r{0,1}\\n/\\\\n/g' ''', + returnStdout: true).trim() + env.GITHUB_DATE = sh( + script: '''date '+%Y-%m-%dT%H:%M:%S%:z' ''', + returnStdout: true).trim() + env.COMMIT_SHA = sh( + script: '''git rev-parse HEAD''', + returnStdout: true).trim() + env.CODE_URL = 'https://github.com/' + env.LS_USER + '/' + env.LS_REPO + '/commit/' + env.GIT_COMMIT + env.DOCKERHUB_LINK = 'https://hub.docker.com/r/' + env.DOCKERHUB_IMAGE + '/tags/' + env.PULL_REQUEST = env.CHANGE_ID + env.LICENSE_TAG = sh( + script: '''#!/bin/bash + if [ -e LICENSE ] ; then + cat LICENSE | md5sum | cut -c1-8 + else + echo none + fi''', + returnStdout: true).trim() + env.FUNDING_TAG = sh( + script: '''#!/bin/bash + if [ -e ./.github/FUNDING.yml ] ; then + cat ./.github/FUNDING.yml | md5sum | cut -c1-8 + else + echo none + fi''', + returnStdout: true).trim() + } + script{ + env.LS_RELEASE_NUMBER = sh( + script: '''echo ${LS_RELEASE} |sed 's/^.*-ls//g' ''', + returnStdout: true).trim() + } + script{ + env.LS_TAG_NUMBER = sh( + script: '''#! /bin/bash + tagsha=$(git rev-list -n 1 ${LS_RELEASE} 2>/dev/null) + if [ "${tagsha}" == "${COMMIT_SHA}" ]; then + echo ${LS_RELEASE_NUMBER} + elif [ -z "${GIT_COMMIT}" ]; then + echo ${LS_RELEASE_NUMBER} + else + echo $((${LS_RELEASE_NUMBER} + 1)) + fi''', + returnStdout: true).trim() + } + } + } + /* ####################### + Package Version Tagging + ####################### */ + // Grab the current package versions in Git to determine package tag + stage("Set Package tag"){ + steps{ + script{ + env.PACKAGE_TAG = sh( + script: '''#!/bin/bash + if [ -e package_versions.txt ] ; then + cat package_versions.txt | md5sum | cut -c1-8 + else + echo none + fi''', + returnStdout: true).trim() + } + } + } + /* ######################## + External Release Tagging + ######################## */ + // If this is a custom command to determine version use that command + stage("Set tag custom bash"){ + steps{ + script{ + env.EXT_RELEASE = sh( + script: ''' curl -s http://dl-cdn.alpinelinux.org/alpine/v3.10/main/x86_64/ |awk -F '(openssh-server-|.apk)' '/openssh-server.*.apk/ {print $2; exit}' ''', + returnStdout: true).trim() + env.RELEASE_LINK = 'custom_command' + } + } + } + // Sanitize the release tag and strip illegal docker or github characters + stage("Sanitize tag"){ + steps{ + script{ + env.EXT_RELEASE_CLEAN = sh( + script: '''echo ${EXT_RELEASE} | sed 's/[~,%@+;:/]//g' ''', + returnStdout: true).trim() + } + } + } + // If this is a master build use live docker endpoints + stage("Set ENV live build"){ + when { + branch "master" + environment name: 'CHANGE_ID', value: '' + } + steps { + script{ + env.IMAGE = env.DOCKERHUB_IMAGE + if (env.MULTIARCH == 'true') { + env.CI_TAGS = 'amd64-' + env.EXT_RELEASE_CLEAN + '-ls' + env.LS_TAG_NUMBER + '|arm32v7-' + env.EXT_RELEASE_CLEAN + '-ls' + env.LS_TAG_NUMBER + '|arm64v8-' + env.EXT_RELEASE_CLEAN + '-ls' + env.LS_TAG_NUMBER + } else { + env.CI_TAGS = env.EXT_RELEASE_CLEAN + '-ls' + env.LS_TAG_NUMBER + } + env.META_TAG = env.EXT_RELEASE_CLEAN + '-ls' + env.LS_TAG_NUMBER + } + } + } + // If this is a dev build use dev docker endpoints + stage("Set ENV dev build"){ + when { + not {branch "master"} + environment name: 'CHANGE_ID', value: '' + } + steps { + script{ + env.IMAGE = env.DEV_DOCKERHUB_IMAGE + if (env.MULTIARCH == 'true') { + env.CI_TAGS = 'amd64-' + env.EXT_RELEASE_CLEAN + '-pkg-' + env.PACKAGE_TAG + '-dev-' + env.COMMIT_SHA + '|arm32v7-' + env.EXT_RELEASE_CLEAN + '-pkg-' + env.PACKAGE_TAG + '-dev-' + env.COMMIT_SHA + '|arm64v8-' + env.EXT_RELEASE_CLEAN + '-pkg-' + env.PACKAGE_TAG + '-dev-' + env.COMMIT_SHA + } else { + env.CI_TAGS = env.EXT_RELEASE_CLEAN + '-pkg-' + env.PACKAGE_TAG + '-dev-' + env.COMMIT_SHA + } + env.META_TAG = env.EXT_RELEASE_CLEAN + '-pkg-' + env.PACKAGE_TAG + '-dev-' + env.COMMIT_SHA + env.DOCKERHUB_LINK = 'https://hub.docker.com/r/' + env.DEV_DOCKERHUB_IMAGE + '/tags/' + } + } + } + // If this is a pull request build use dev docker endpoints + stage("Set ENV PR build"){ + when { + not {environment name: 'CHANGE_ID', value: ''} + } + steps { + script{ + env.IMAGE = env.PR_DOCKERHUB_IMAGE + if (env.MULTIARCH == 'true') { + env.CI_TAGS = 'amd64-' + env.EXT_RELEASE_CLEAN + '-pkg-' + env.PACKAGE_TAG + '-pr-' + env.PULL_REQUEST + '|arm32v7-' + env.EXT_RELEASE_CLEAN + '-pkg-' + env.PACKAGE_TAG + '-pr-' + env.PULL_REQUEST + '|arm64v8-' + env.EXT_RELEASE_CLEAN + '-pkg-' + env.PACKAGE_TAG + '-pr-' + env.PULL_REQUEST + } else { + env.CI_TAGS = env.EXT_RELEASE_CLEAN + '-pkg-' + env.PACKAGE_TAG + '-pr-' + env.PULL_REQUEST + } + env.META_TAG = env.EXT_RELEASE_CLEAN + '-pkg-' + env.PACKAGE_TAG + '-pr-' + env.PULL_REQUEST + env.CODE_URL = 'https://github.com/' + env.LS_USER + '/' + env.LS_REPO + '/pull/' + env.PULL_REQUEST + env.DOCKERHUB_LINK = 'https://hub.docker.com/r/' + env.PR_DOCKERHUB_IMAGE + '/tags/' + } + } + } + // Run ShellCheck + stage('ShellCheck') { + when { + environment name: 'CI', value: 'true' + } + steps { + withCredentials([ + string(credentialsId: 'spaces-key', variable: 'DO_KEY'), + string(credentialsId: 'spaces-secret', variable: 'DO_SECRET') + ]) { + script{ + env.SHELLCHECK_URL = 'https://lsio-ci.ams3.digitaloceanspaces.com/' + env.IMAGE + '/' + env.META_TAG + '/shellcheck-result.xml' + } + sh '''curl -sL https://raw.githubusercontent.com/linuxserver/docker-shellcheck/master/checkrun.sh | /bin/bash''' + sh '''#! /bin/bash + set -e + docker pull lsiodev/spaces-file-upload:latest + docker run --rm \ + -e DESTINATION=\"${IMAGE}/${META_TAG}/shellcheck-result.xml\" \ + -e FILE_NAME="shellcheck-result.xml" \ + -e MIMETYPE="text/xml" \ + -v ${WORKSPACE}:/mnt \ + -e SECRET_KEY=\"${DO_SECRET}\" \ + -e ACCESS_KEY=\"${DO_KEY}\" \ + -t lsiodev/spaces-file-upload:latest \ + python /upload.py''' + } + } + } + // Use helper containers to render templated files + stage('Update-Templates') { + when { + branch "master" + environment name: 'CHANGE_ID', value: '' + expression { + env.CONTAINER_NAME != null + } + } + steps { + sh '''#! /bin/bash + set -e + TEMPDIR=$(mktemp -d) + docker pull linuxserver/jenkins-builder:latest + docker run --rm -e CONTAINER_NAME=${CONTAINER_NAME} -e GITHUB_BRANCH=master -v ${TEMPDIR}:/ansible/jenkins linuxserver/jenkins-builder:latest + docker pull linuxserver/doc-builder:latest + docker run --rm -e CONTAINER_NAME=${CONTAINER_NAME} -e GITHUB_BRANCH=master -v ${TEMPDIR}:/ansible/readme linuxserver/doc-builder:latest + if [ "$(md5sum ${TEMPDIR}/${LS_REPO}/Jenkinsfile | awk '{ print $1 }')" != "$(md5sum Jenkinsfile | awk '{ print $1 }')" ] || \ + [ "$(md5sum ${TEMPDIR}/${CONTAINER_NAME}/README.md | awk '{ print $1 }')" != "$(md5sum README.md | awk '{ print $1 }')" ] || \ + [ "$(cat ${TEMPDIR}/${LS_REPO}/LICENSE | md5sum | cut -c1-8)" != "${LICENSE_TAG}" ] || \ + [ "$(cat ${TEMPDIR}/${LS_REPO}/.github/FUNDING.yml | md5sum | cut -c1-8)" != "${FUNDING_TAG}" ]; then + mkdir -p ${TEMPDIR}/repo + git clone https://github.com/${LS_USER}/${LS_REPO}.git ${TEMPDIR}/repo/${LS_REPO} + git --git-dir ${TEMPDIR}/repo/${LS_REPO}/.git checkout -f master + cp ${TEMPDIR}/${CONTAINER_NAME}/README.md ${TEMPDIR}/repo/${LS_REPO}/ + cp ${TEMPDIR}/docker-${CONTAINER_NAME}/Jenkinsfile ${TEMPDIR}/repo/${LS_REPO}/ + cp ${TEMPDIR}/docker-${CONTAINER_NAME}/LICENSE ${TEMPDIR}/repo/${LS_REPO}/ + mkdir -p ${TEMPDIR}/repo/${LS_REPO}/.github + cp ${TEMPDIR}/docker-${CONTAINER_NAME}/.github/FUNDING.yml ${TEMPDIR}/repo/${LS_REPO}/.github/FUNDING.yml + cd ${TEMPDIR}/repo/${LS_REPO}/ + git --git-dir ${TEMPDIR}/repo/${LS_REPO}/.git add Jenkinsfile README.md LICENSE ./.github/FUNDING.yml + git --git-dir ${TEMPDIR}/repo/${LS_REPO}/.git commit -m 'Bot Updating Templated Files' + git --git-dir ${TEMPDIR}/repo/${LS_REPO}/.git push https://LinuxServer-CI:${GITHUB_TOKEN}@github.com/${LS_USER}/${LS_REPO}.git --all + echo "true" > /tmp/${COMMIT_SHA}-${BUILD_NUMBER} + else + echo "false" > /tmp/${COMMIT_SHA}-${BUILD_NUMBER} + fi + mkdir -p ${TEMPDIR}/gitbook + git clone https://github.com/linuxserver/docker-documentation.git ${TEMPDIR}/gitbook/docker-documentation + if [[ "${BRANCH_NAME}" == "master" ]] && [[ (! -f ${TEMPDIR}/gitbook/docker-documentation/images/docker-${CONTAINER_NAME}.md) || ("$(md5sum ${TEMPDIR}/gitbook/docker-documentation/images/docker-${CONTAINER_NAME}.md | awk '{ print $1 }')" != "$(md5sum ${TEMPDIR}/${CONTAINER_NAME}/docker-${CONTAINER_NAME}.md | awk '{ print $1 }')") ]]; then + cp ${TEMPDIR}/${CONTAINER_NAME}/docker-${CONTAINER_NAME}.md ${TEMPDIR}/gitbook/docker-documentation/images/ + cd ${TEMPDIR}/gitbook/docker-documentation/ + git add images/docker-${CONTAINER_NAME}.md + git commit -m 'Bot Updating Templated Files' + git push https://LinuxServer-CI:${GITHUB_TOKEN}@github.com/linuxserver/docker-documentation.git --all + fi + rm -Rf ${TEMPDIR}''' + script{ + env.FILES_UPDATED = sh( + script: '''cat /tmp/${COMMIT_SHA}-${BUILD_NUMBER}''', + returnStdout: true).trim() + } + } + } + // Exit the build if the Templated files were just updated + stage('Template-exit') { + when { + branch "master" + environment name: 'CHANGE_ID', value: '' + environment name: 'FILES_UPDATED', value: 'true' + expression { + env.CONTAINER_NAME != null + } + } + steps { + script{ + env.EXIT_STATUS = 'ABORTED' + } + } + } + /* ############### + Build Container + ############### */ + // Build Docker container for push to LS Repo + stage('Build-Single') { + when { + environment name: 'MULTIARCH', value: 'false' + environment name: 'EXIT_STATUS', value: '' + } + steps { + sh "docker build --no-cache --pull -t ${IMAGE}:${META_TAG} \ + --build-arg ${BUILD_VERSION_ARG}=${EXT_RELEASE} --build-arg VERSION=\"${META_TAG}\" --build-arg BUILD_DATE=${GITHUB_DATE} ." + } + } + // Build MultiArch Docker containers for push to LS Repo + stage('Build-Multi') { + when { + environment name: 'MULTIARCH', value: 'true' + environment name: 'EXIT_STATUS', value: '' + } + parallel { + stage('Build X86') { + steps { + sh "docker build --no-cache --pull -t ${IMAGE}:amd64-${META_TAG} \ + --build-arg ${BUILD_VERSION_ARG}=${EXT_RELEASE} --build-arg VERSION=\"${META_TAG}\" --build-arg BUILD_DATE=${GITHUB_DATE} ." + } + } + stage('Build ARMHF') { + agent { + label 'ARMHF' + } + steps { + withCredentials([ + [ + $class: 'UsernamePasswordMultiBinding', + credentialsId: '3f9ba4d5-100d-45b0-a3c4-633fd6061207', + usernameVariable: 'DOCKERUSER', + passwordVariable: 'DOCKERPASS' + ] + ]) { + echo 'Logging into DockerHub' + sh '''#! /bin/bash + echo $DOCKERPASS | docker login -u $DOCKERUSER --password-stdin + ''' + sh "docker build --no-cache --pull -f Dockerfile.armhf -t ${IMAGE}:arm32v7-${META_TAG} \ + --build-arg ${BUILD_VERSION_ARG}=${EXT_RELEASE} --build-arg VERSION=\"${META_TAG}\" --build-arg BUILD_DATE=${GITHUB_DATE} ." + sh "docker tag ${IMAGE}:arm32v7-${META_TAG} lsiodev/buildcache:arm32v7-${COMMIT_SHA}-${BUILD_NUMBER}" + sh "docker push lsiodev/buildcache:arm32v7-${COMMIT_SHA}-${BUILD_NUMBER}" + sh '''docker rmi \ + ${IMAGE}:arm32v7-${META_TAG} \ + lsiodev/buildcache:arm32v7-${COMMIT_SHA}-${BUILD_NUMBER} || :''' + } + } + } + stage('Build ARM64') { + agent { + label 'ARM64' + } + steps { + withCredentials([ + [ + $class: 'UsernamePasswordMultiBinding', + credentialsId: '3f9ba4d5-100d-45b0-a3c4-633fd6061207', + usernameVariable: 'DOCKERUSER', + passwordVariable: 'DOCKERPASS' + ] + ]) { + echo 'Logging into DockerHub' + sh '''#! /bin/bash + echo $DOCKERPASS | docker login -u $DOCKERUSER --password-stdin + ''' + sh "docker build --no-cache --pull -f Dockerfile.aarch64 -t ${IMAGE}:arm64v8-${META_TAG} \ + --build-arg ${BUILD_VERSION_ARG}=${EXT_RELEASE} --build-arg VERSION=\"${META_TAG}\" --build-arg BUILD_DATE=${GITHUB_DATE} ." + sh "docker tag ${IMAGE}:arm64v8-${META_TAG} lsiodev/buildcache:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER}" + sh "docker push lsiodev/buildcache:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER}" + sh '''docker rmi \ + ${IMAGE}:arm64v8-${META_TAG} \ + lsiodev/buildcache:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} || :''' + } + } + } + } + } + // Take the image we just built and dump package versions for comparison + stage('Update-packages') { + when { + branch "master" + environment name: 'CHANGE_ID', value: '' + environment name: 'EXIT_STATUS', value: '' + } + steps { + sh '''#! /bin/bash + set -e + TEMPDIR=$(mktemp -d) + if [ "${MULTIARCH}" == "true" ]; then + LOCAL_CONTAINER=${IMAGE}:amd64-${META_TAG} + else + LOCAL_CONTAINER=${IMAGE}:${META_TAG} + fi + if [ "${DIST_IMAGE}" == "alpine" ]; then + docker run --rm --entrypoint '/bin/sh' -v ${TEMPDIR}:/tmp ${LOCAL_CONTAINER} -c '\ + apk info -v > /tmp/package_versions.txt && \ + sort -o /tmp/package_versions.txt /tmp/package_versions.txt && \ + chmod 777 /tmp/package_versions.txt' + elif [ "${DIST_IMAGE}" == "ubuntu" ]; then + docker run --rm --entrypoint '/bin/sh' -v ${TEMPDIR}:/tmp ${LOCAL_CONTAINER} -c '\ + apt list -qq --installed | sed "s#/.*now ##g" | cut -d" " -f1 > /tmp/package_versions.txt && \ + sort -o /tmp/package_versions.txt /tmp/package_versions.txt && \ + chmod 777 /tmp/package_versions.txt' + fi + NEW_PACKAGE_TAG=$(md5sum ${TEMPDIR}/package_versions.txt | cut -c1-8 ) + echo "Package tag sha from current packages in buit container is ${NEW_PACKAGE_TAG} comparing to old ${PACKAGE_TAG} from github" + if [ "${NEW_PACKAGE_TAG}" != "${PACKAGE_TAG}" ]; then + git clone https://github.com/${LS_USER}/${LS_REPO}.git ${TEMPDIR}/${LS_REPO} + git --git-dir ${TEMPDIR}/${LS_REPO}/.git checkout -f master + cp ${TEMPDIR}/package_versions.txt ${TEMPDIR}/${LS_REPO}/ + cd ${TEMPDIR}/${LS_REPO}/ + wait + git add package_versions.txt + git commit -m 'Bot Updating Package Versions' + git push https://LinuxServer-CI:${GITHUB_TOKEN}@github.com/${LS_USER}/${LS_REPO}.git --all + echo "true" > /tmp/packages-${COMMIT_SHA}-${BUILD_NUMBER} + echo "Package tag updated, stopping build process" + else + echo "false" > /tmp/packages-${COMMIT_SHA}-${BUILD_NUMBER} + echo "Package tag is same as previous continue with build process" + fi + rm -Rf ${TEMPDIR}''' + script{ + env.PACKAGE_UPDATED = sh( + script: '''cat /tmp/packages-${COMMIT_SHA}-${BUILD_NUMBER}''', + returnStdout: true).trim() + } + } + } + // Exit the build if the package file was just updated + stage('PACKAGE-exit') { + when { + branch "master" + environment name: 'CHANGE_ID', value: '' + environment name: 'PACKAGE_UPDATED', value: 'true' + environment name: 'EXIT_STATUS', value: '' + } + steps { + script{ + env.EXIT_STATUS = 'ABORTED' + } + } + } + // Exit the build if this is just a package check and there are no changes to push + stage('PACKAGECHECK-exit') { + when { + branch "master" + environment name: 'CHANGE_ID', value: '' + environment name: 'PACKAGE_UPDATED', value: 'false' + environment name: 'EXIT_STATUS', value: '' + expression { + params.PACKAGE_CHECK == 'true' + } + } + steps { + script{ + env.EXIT_STATUS = 'ABORTED' + } + } + } + /* ####### + Testing + ####### */ + // Run Container tests + stage('Test') { + when { + environment name: 'CI', value: 'true' + environment name: 'EXIT_STATUS', value: '' + } + steps { + withCredentials([ + string(credentialsId: 'spaces-key', variable: 'DO_KEY'), + string(credentialsId: 'spaces-secret', variable: 'DO_SECRET') + ]) { + script{ + env.CI_URL = 'https://lsio-ci.ams3.digitaloceanspaces.com/' + env.IMAGE + '/' + env.META_TAG + '/index.html' + } + sh '''#! /bin/bash + set -e + docker pull lsiodev/ci:latest + if [ "${MULTIARCH}" == "true" ]; then + docker pull lsiodev/buildcache:arm32v7-${COMMIT_SHA}-${BUILD_NUMBER} + docker pull lsiodev/buildcache:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} + docker tag lsiodev/buildcache:arm32v7-${COMMIT_SHA}-${BUILD_NUMBER} ${IMAGE}:arm32v7-${META_TAG} + docker tag lsiodev/buildcache:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} ${IMAGE}:arm64v8-${META_TAG} + fi + docker run --rm \ + --shm-size=1gb \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -e IMAGE=\"${IMAGE}\" \ + -e DELAY_START=\"${CI_DELAY}\" \ + -e TAGS=\"${CI_TAGS}\" \ + -e META_TAG=\"${META_TAG}\" \ + -e PORT=\"${CI_PORT}\" \ + -e SSL=\"${CI_SSL}\" \ + -e BASE=\"${DIST_IMAGE}\" \ + -e SECRET_KEY=\"${DO_SECRET}\" \ + -e ACCESS_KEY=\"${DO_KEY}\" \ + -e DOCKER_ENV=\"${CI_DOCKERENV}\" \ + -e WEB_SCREENSHOT=\"${CI_WEB}\" \ + -e WEB_AUTH=\"${CI_AUTH}\" \ + -e WEB_PATH=\"${CI_WEBPATH}\" \ + -e DO_REGION="ams3" \ + -e DO_BUCKET="lsio-ci" \ + -t lsiodev/ci:latest \ + python /ci/ci.py''' + } + } + } + /* ################## + Release Logic + ################## */ + // If this is an amd64 only image only push a single image + stage('Docker-Push-Single') { + when { + environment name: 'MULTIARCH', value: 'false' + environment name: 'EXIT_STATUS', value: '' + } + steps { + withCredentials([ + [ + $class: 'UsernamePasswordMultiBinding', + credentialsId: '3f9ba4d5-100d-45b0-a3c4-633fd6061207', + usernameVariable: 'DOCKERUSER', + passwordVariable: 'DOCKERPASS' + ] + ]) { + echo 'Logging into DockerHub' + sh '''#! /bin/bash + echo $DOCKERPASS | docker login -u $DOCKERUSER --password-stdin + ''' + sh "docker tag ${IMAGE}:${META_TAG} ${IMAGE}:latest" + sh "docker push ${IMAGE}:latest" + sh "docker push ${IMAGE}:${META_TAG}" + sh '''docker rmi \ + ${IMAGE}:${META_TAG} \ + ${IMAGE}:latest || :''' + + } + } + } + // If this is a multi arch release push all images and define the manifest + stage('Docker-Push-Multi') { + when { + environment name: 'MULTIARCH', value: 'true' + environment name: 'EXIT_STATUS', value: '' + } + steps { + withCredentials([ + [ + $class: 'UsernamePasswordMultiBinding', + credentialsId: '3f9ba4d5-100d-45b0-a3c4-633fd6061207', + usernameVariable: 'DOCKERUSER', + passwordVariable: 'DOCKERPASS' + ] + ]) { + sh '''#! /bin/bash + echo $DOCKERPASS | docker login -u $DOCKERUSER --password-stdin + ''' + sh '''#! /bin/bash + if [ "${CI}" == "false" ]; then + docker pull lsiodev/buildcache:arm32v7-${COMMIT_SHA}-${BUILD_NUMBER} + docker pull lsiodev/buildcache:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} + docker tag lsiodev/buildcache:arm32v7-${COMMIT_SHA}-${BUILD_NUMBER} ${IMAGE}:arm32v7-${META_TAG} + docker tag lsiodev/buildcache:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} ${IMAGE}:arm64v8-${META_TAG} + fi''' + sh "docker tag ${IMAGE}:amd64-${META_TAG} ${IMAGE}:amd64-latest" + sh "docker tag ${IMAGE}:arm32v7-${META_TAG} ${IMAGE}:arm32v7-latest" + sh "docker tag ${IMAGE}:arm64v8-${META_TAG} ${IMAGE}:arm64v8-latest" + sh "docker push ${IMAGE}:amd64-${META_TAG}" + sh "docker push ${IMAGE}:arm32v7-${META_TAG}" + sh "docker push ${IMAGE}:arm64v8-${META_TAG}" + sh "docker push ${IMAGE}:amd64-latest" + sh "docker push ${IMAGE}:arm32v7-latest" + sh "docker push ${IMAGE}:arm64v8-latest" + sh "docker manifest push --purge ${IMAGE}:latest || :" + sh "docker manifest create ${IMAGE}:latest ${IMAGE}:amd64-latest ${IMAGE}:arm32v7-latest ${IMAGE}:arm64v8-latest" + sh "docker manifest annotate ${IMAGE}:latest ${IMAGE}:arm32v7-latest --os linux --arch arm" + sh "docker manifest annotate ${IMAGE}:latest ${IMAGE}:arm64v8-latest --os linux --arch arm64 --variant v8" + sh "docker manifest push --purge ${IMAGE}:${META_TAG} || :" + sh "docker manifest create ${IMAGE}:${META_TAG} ${IMAGE}:amd64-${META_TAG} ${IMAGE}:arm32v7-${META_TAG} ${IMAGE}:arm64v8-${META_TAG}" + sh "docker manifest annotate ${IMAGE}:${META_TAG} ${IMAGE}:arm32v7-${META_TAG} --os linux --arch arm" + sh "docker manifest annotate ${IMAGE}:${META_TAG} ${IMAGE}:arm64v8-${META_TAG} --os linux --arch arm64 --variant v8" + sh "docker manifest push --purge ${IMAGE}:latest" + sh "docker manifest push --purge ${IMAGE}:${META_TAG}" + sh '''docker rmi \ + ${IMAGE}:amd64-${META_TAG} \ + ${IMAGE}:amd64-latest \ + ${IMAGE}:arm32v7-${META_TAG} \ + ${IMAGE}:arm32v7-latest \ + ${IMAGE}:arm64v8-${META_TAG} \ + ${IMAGE}:arm64v8-latest \ + lsiodev/buildcache:arm32v7-${COMMIT_SHA}-${BUILD_NUMBER} \ + lsiodev/buildcache:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} || :''' + } + } + } + // If this is a public release tag it in the LS Github + stage('Github-Tag-Push-Release') { + when { + branch "master" + expression { + env.LS_RELEASE != env.EXT_RELEASE_CLEAN + '-ls' + env.LS_TAG_NUMBER + } + environment name: 'CHANGE_ID', value: '' + environment name: 'EXIT_STATUS', value: '' + } + steps { + echo "Pushing New tag for current commit ${EXT_RELEASE_CLEAN}-ls${LS_TAG_NUMBER}" + sh '''curl -H "Authorization: token ${GITHUB_TOKEN}" -X POST https://api.github.com/repos/${LS_USER}/${LS_REPO}/git/tags \ + -d '{"tag":"'${EXT_RELEASE_CLEAN}'-ls'${LS_TAG_NUMBER}'",\ + "object": "'${COMMIT_SHA}'",\ + "message": "Tagging Release '${EXT_RELEASE_CLEAN}'-ls'${LS_TAG_NUMBER}' to master",\ + "type": "commit",\ + "tagger": {"name": "LinuxServer Jenkins","email": "jenkins@linuxserver.io","date": "'${GITHUB_DATE}'"}}' ''' + echo "Pushing New release for Tag" + sh '''#! /bin/bash + echo "Updating to ${EXT_RELEASE_CLEAN}" > releasebody.json + echo '{"tag_name":"'${EXT_RELEASE_CLEAN}'-ls'${LS_TAG_NUMBER}'",\ + "target_commitish": "master",\ + "name": "'${EXT_RELEASE_CLEAN}'-ls'${LS_TAG_NUMBER}'",\ + "body": "**LinuxServer Changes:**\\n\\n'${LS_RELEASE_NOTES}'\\n**Remote Changes:**\\n\\n' > start + printf '","draft": false,"prerelease": false}' >> releasebody.json + paste -d'\\0' start releasebody.json > releasebody.json.done + curl -H "Authorization: token ${GITHUB_TOKEN}" -X POST https://api.github.com/repos/${LS_USER}/${LS_REPO}/releases -d @releasebody.json.done''' + } + } + // Use helper container to sync the current README on master to the dockerhub endpoint + stage('Sync-README') { + when { + environment name: 'CHANGE_ID', value: '' + environment name: 'EXIT_STATUS', value: '' + } + steps { + withCredentials([ + [ + $class: 'UsernamePasswordMultiBinding', + credentialsId: '3f9ba4d5-100d-45b0-a3c4-633fd6061207', + usernameVariable: 'DOCKERUSER', + passwordVariable: 'DOCKERPASS' + ] + ]) { + sh '''#! /bin/bash + docker pull lsiodev/readme-sync + docker run --rm=true \ + -e DOCKERHUB_USERNAME=$DOCKERUSER \ + -e DOCKERHUB_PASSWORD=$DOCKERPASS \ + -e GIT_REPOSITORY=${LS_USER}/${LS_REPO} \ + -e DOCKER_REPOSITORY=${IMAGE} \ + -e GIT_BRANCH=master \ + lsiodev/readme-sync bash -c 'node sync' ''' + } + } + } + // If this is a Pull request send the CI link as a comment on it + stage('Pull Request Comment') { + when { + not {environment name: 'CHANGE_ID', value: ''} + environment name: 'CI', value: 'true' + environment name: 'EXIT_STATUS', value: '' + } + steps { + sh '''curl -H "Authorization: token ${GITHUB_TOKEN}" -X POST https://api.github.com/repos/${LS_USER}/${LS_REPO}/issues/${PULL_REQUEST}/comments \ + -d '{"body": "I am a bot, here are the test results for this PR: \\n'${CI_URL}' \\n'${SHELLCHECK_URL}'"}' ''' + } + } + } + /* ###################### + Send status to Discord + ###################### */ + post { + always { + script{ + if (env.EXIT_STATUS == "ABORTED"){ + sh 'echo "build aborted"' + } + else if (currentBuild.currentResult == "SUCCESS"){ + sh ''' curl -X POST --data '{"avatar_url": "https://wiki.jenkins-ci.org/download/attachments/2916393/headshot.png","embeds": [{"color": 1681177,\ + "description": "**Build:** '${BUILD_NUMBER}'\\n**CI Results:** '${CI_URL}'\\n**ShellCheck Results:** '${SHELLCHECK_URL}'\\n**Status:** Success\\n**Job:** '${RUN_DISPLAY_URL}'\\n**Change:** '${CODE_URL}'\\n**External Release:**: '${RELEASE_LINK}'\\n**DockerHub:** '${DOCKERHUB_LINK}'\\n"}],\ + "username": "Jenkins"}' ${BUILDS_DISCORD} ''' + } + else { + sh ''' curl -X POST --data '{"avatar_url": "https://wiki.jenkins-ci.org/download/attachments/2916393/headshot.png","embeds": [{"color": 16711680,\ + "description": "**Build:** '${BUILD_NUMBER}'\\n**CI Results:** '${CI_URL}'\\n**ShellCheck Results:** '${SHELLCHECK_URL}'\\n**Status:** failure\\n**Job:** '${RUN_DISPLAY_URL}'\\n**Change:** '${CODE_URL}'\\n**External Release:**: '${RELEASE_LINK}'\\n**DockerHub:** '${DOCKERHUB_LINK}'\\n"}],\ + "username": "Jenkins"}' ${BUILDS_DISCORD} ''' + } + } + } + } +} diff --git a/LICENSE b/LICENSE old mode 100644 new mode 100755 diff --git a/README.md b/README.md index 63964ae..6f0d88f 100644 --- a/README.md +++ b/README.md @@ -1 +1,220 @@ -# docker-openssh-server \ No newline at end of file +[![linuxserver.io](https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/linuxserver_medium.png)](https://linuxserver.io) + +[![Blog](https://img.shields.io/static/v1.svg?style=flat-square&color=E68523&label=linuxserver.io&message=Blog)](https://blog.linuxserver.io "all the things you can do with our containers including How-To guides, opinions and much more!") +[![Discord](https://img.shields.io/discord/354974912613449730.svg?style=flat-square&color=E68523&label=Discord&logo=discord&logoColor=FFFFFF)](https://discord.gg/YWrKVTn "realtime support / chat with the community and the team.") +[![Discourse](https://img.shields.io/discourse/https/discourse.linuxserver.io/topics.svg?style=flat-square&color=E68523&logo=discourse&logoColor=FFFFFF)](https://discourse.linuxserver.io "post on our community forum.") +[![Fleet](https://img.shields.io/static/v1.svg?style=flat-square&color=E68523&label=linuxserver.io&message=Fleet)](https://fleet.linuxserver.io "an online web interface which displays all of our maintained images.") +[![Podcast](https://img.shields.io/static/v1.svg?style=flat-square&color=E68523&label=linuxserver.io&message=Podcast)](https://anchor.fm/linuxserverio "on hiatus. Coming back soon (late 2018).") +[![Open Collective](https://img.shields.io/opencollective/all/linuxserver.svg?style=flat-square&color=E68523&label=Open%20Collective%20Supporters)](https://opencollective.com/linuxserver "please consider helping us by either donating or contributing to our budget") + +The [LinuxServer.io](https://linuxserver.io) team brings you another container release featuring :- + + * regular and timely application updates + * easy user mappings (PGID, PUID) + * custom base image with s6 overlay + * weekly base OS updates with common layers across the entire LinuxServer.io ecosystem to minimise space usage, down time and bandwidth + * regular security updates + +Find us at: +* [Blog](https://blog.linuxserver.io) - all the things you can do with our containers including How-To guides, opinions and much more! +* [Discord](https://discord.gg/YWrKVTn) - realtime support / chat with the community and the team. +* [Discourse](https://discourse.linuxserver.io) - post on our community forum. +* [Fleet](https://fleet.linuxserver.io) - an online web interface which displays all of our maintained images. +* [Podcast](https://anchor.fm/linuxserverio) - on hiatus. Coming back soon (late 2018). +* [Open Collective](https://opencollective.com/linuxserver) - please consider helping us by either donating or contributing to our budget + +# [linuxserver/openssh-server](https://github.com/linuxserver/docker-openssh-server) +[![GitHub Release](https://img.shields.io/github/release/linuxserver/docker-openssh-server.svg?style=flat-square&color=E68523)](https://github.com/linuxserver/docker-openssh-server/releases) +[![MicroBadger Layers](https://img.shields.io/microbadger/layers/linuxserver/openssh-server.svg?style=flat-square&color=E68523)](https://microbadger.com/images/linuxserver/openssh-server "Get your own version badge on microbadger.com") +[![MicroBadger Size](https://img.shields.io/microbadger/image-size/linuxserver/openssh-server.svg?style=flat-square&color=E68523)](https://microbadger.com/images/linuxserver/openssh-server "Get your own version badge on microbadger.com") +[![Docker Pulls](https://img.shields.io/docker/pulls/linuxserver/openssh-server.svg?style=flat-square&color=E68523)](https://hub.docker.com/r/linuxserver/openssh-server) +[![Docker Stars](https://img.shields.io/docker/stars/linuxserver/openssh-server.svg?style=flat-square&color=E68523)](https://hub.docker.com/r/linuxserver/openssh-server) +[![Build Status](https://ci.linuxserver.io/view/all/job/Docker-Pipeline-Builders/job/docker-openssh-server/job/master/badge/icon?style=flat-square)](https://ci.linuxserver.io/job/Docker-Pipeline-Builders/job/docker-openssh-server/job/master/) +[![](https://lsio-ci.ams3.digitaloceanspaces.com/linuxserver/openssh-server/latest/badge.svg)](https://lsio-ci.ams3.digitaloceanspaces.com/linuxserver/openssh-server/latest/index.html) + +[Openssh-server](https://www.openssh.com/) is a sandboxed environment that allows ssh access without giving keys to the entire server. +Giving ssh access via private key often means giving full access to the server. This container creates a limited and sandboxed environment that others can ssh into. +The users only have access to the folders mapped and the processes running inside this container. + +[![openssh-server](https://upload.wikimedia.org/wikipedia/en/6/65/OpenSSH_logo.png)](https://www.openssh.com/) + +## Supported Architectures + +Our images support multiple architectures such as `x86-64`, `arm64` and `armhf`. We utilise the docker manifest for multi-platform awareness. More information is available from docker [here](https://github.com/docker/distribution/blob/master/docs/spec/manifest-v2-2.md#manifest-list) and our announcement [here](https://blog.linuxserver.io/2019/02/21/the-lsio-pipeline-project/). + +Simply pulling `linuxserver/openssh-server` should retrieve the correct image for your arch, but you can also pull specific arch images via tags. + +The architectures supported by this image are: + +| Architecture | Tag | +| :----: | --- | +| x86-64 | amd64-latest | +| arm64 | arm64v8-latest | +| armhf | arm32v7-latest | + + +## Usage + +Here are some example snippets to help you get started creating a container. + +### docker + +``` +docker create \ + --name=openssh-server \ + -e PUID=1000 \ + -e PGID=1000 \ + -e TZ=Europe/London \ + -e PUBLIC_KEY=yourpublickey `#optional` \ + -e SUDO_ACCESS=false `#optional` \ + -e SUDO_PASSWORD=password `#optional` \ + -e USER_NAME=abc `#optional` \ + -p 22:22 \ + -v /path/to/appdata/config:/config \ + --restart unless-stopped \ + linuxserver/openssh-server +``` + + +### docker-compose + +Compatible with docker-compose v2 schemas. + +``` +--- +version: "2" +services: + openssh-server: + image: linuxserver/openssh-server + container_name: openssh-server + environment: + - PUID=1000 + - PGID=1000 + - TZ=Europe/London + - PUBLIC_KEY=yourpublickey #optional + - SUDO_ACCESS=false #optional + - SUDO_PASSWORD=password #optional + - USER_NAME=abc #optional + volumes: + - /path/to/appdata/config:/config + ports: + - 22:22 + restart: unless-stopped +``` + +## Parameters + +Container images are configured using parameters passed at runtime (such as those above). These parameters are separated by a colon and indicate `:` respectively. For example, `-p 8080:80` would expose port `80` from inside the container to be accessible from the host's IP on port `8080` outside the container. + +| Parameter | Function | +| :----: | --- | +| `-p 22` | ssh port | +| `-e PUID=1000` | for UserID - see below for explanation | +| `-e PGID=1000` | for GroupID - see below for explanation | +| `-e TZ=Europe/London` | Specify a timezone to use EG Europe/London | +| `-e PUBLIC_KEY=yourpublickey` | Optional ssh public key, which will automatically be added to authorized_keys. | +| `-e SUDO_ACCESS=false` | Set to `true` to allow `abc`, the ssh user, sudo access. Without `SUDO_PASSWORD` set, this will allow passwordless sudo access. | +| `-e SUDO_PASSWORD=password` | Optionally set a sudo password for `abc`, the ssh user. If this is not set but `SUDO_ACCESS` is set to true, the user will have passwordless sudo access. | +| `-e USER_NAME=abc` | Optionally specify a user name (Default:`abc`) | +| `-v /config` | Contains all relevant configuration files. | + +## User / Group Identifiers + +When using volumes (`-v` flags) permissions issues can arise between the host OS and the container, we avoid this issue by allowing you to specify the user `PUID` and group `PGID`. + +Ensure any volume directories on the host are owned by the same user you specify and any permissions issues will vanish like magic. + +In this instance `PUID=1000` and `PGID=1000`, to find yours use `id user` as below: + +``` + $ id username + uid=1000(dockeruser) gid=1000(dockergroup) groups=1000(dockergroup) +``` + + +  +## Application Setup + +If `PUBLIC_KEY` variable is set, it will automatically be added to `authorized_keys`. If not, the keys can manually be added to `/config/.ssh/authorized_keys` and the container should be restarted. +Removing `PUBLIC_KEY` variable from docker run environment variables will not remove the key from `authorized_keys`. + +Connect to server via `ssh -i /path/to/private/key -p PORT USER_NAME@SERVERIP` + +Setting `SUDO_ACCESS` to `true` by itself will allow passwordless sudo. `SUDO_PASSWORD` allows setting an optional sudo password. + +The users only have access to the folders mapped and the processes running inside this container. +Add any volume mappings you like for the users to have access to. +To install packages or services for users to access, use the LinuxServer container customization methods described [in this blog article](https://blog.linuxserver.io/2019/09/14/customizing-our-containers/). + +Sample use case is when a server admin would like to have automated incoming backups from a remote server to the local server, but they might not want all the other admins of the remote server to have full access to the local server. +This container can be set up with a mounted folder for incoming backups, and rsync installed via LinuxServer container customization described above, so that the incoming backups can proceed, but remote server and its admins' access would be limited to the backup folder. + +It is also possible to run multiple copies of this container with different ports mapped, different folders mounted and access to different private keys for compartmentalized access. + + + +## Support Info + +* Shell access whilst the container is running: `docker exec -it openssh-server /bin/bash` +* To monitor the logs of the container in realtime: `docker logs -f openssh-server` +* container version number + * `docker inspect -f '{{ index .Config.Labels "build_version" }}' openssh-server` +* image version number + * `docker inspect -f '{{ index .Config.Labels "build_version" }}' linuxserver/openssh-server` + +## Updating Info + +Most of our images are static, versioned, and require an image update and container recreation to update the app inside. With some exceptions (ie. nextcloud, plex), we do not recommend or support updating apps inside the container. Please consult the [Application Setup](#application-setup) section above to see if it is recommended for the image. + +Below are the instructions for updating containers: + +### Via Docker Run/Create +* Update the image: `docker pull linuxserver/openssh-server` +* Stop the running container: `docker stop openssh-server` +* Delete the container: `docker rm openssh-server` +* Recreate a new container with the same docker create parameters as instructed above (if mapped correctly to a host folder, your `/config` folder and settings will be preserved) +* Start the new container: `docker start openssh-server` +* You can also remove the old dangling images: `docker image prune` + +### Via Docker Compose +* Update all images: `docker-compose pull` + * or update a single image: `docker-compose pull openssh-server` +* Let compose update all containers as necessary: `docker-compose up -d` + * or update a single container: `docker-compose up -d openssh-server` +* You can also remove the old dangling images: `docker image prune` + +### Via Watchtower auto-updater (especially useful if you don't remember the original parameters) +* Pull the latest image at its tag and replace it with the same env variables in one run: + ``` + docker run --rm \ + -v /var/run/docker.sock:/var/run/docker.sock \ + containrrr/watchtower \ + --run-once openssh-server + ``` + +**Note:** We do not endorse the use of Watchtower as a solution to automated updates of existing Docker containers. In fact we generally discourage automated updates. However, this is a useful tool for one-time manual updates of containers where you have forgotten the original parameters. In the long term, we highly recommend using Docker Compose. + +* You can also remove the old dangling images: `docker image prune` + +## Building locally + +If you want to make local modifications to these images for development purposes or just to customize the logic: +``` +git clone https://github.com/linuxserver/docker-openssh-server.git +cd docker-openssh-server +docker build \ + --no-cache \ + --pull \ + -t linuxserver/openssh-server:latest . +``` + +The ARM variants can be built on x86_64 hardware using `multiarch/qemu-user-static` +``` +docker run --rm --privileged multiarch/qemu-user-static:register --reset +``` + +Once registered you can define the dockerfile to use with `-f Dockerfile.aarch64`. + +## Versions + +* **04.10.19:** - Initial Release. diff --git a/jenkins-vars.yml b/jenkins-vars.yml new file mode 100644 index 0000000..55781b2 --- /dev/null +++ b/jenkins-vars.yml @@ -0,0 +1,27 @@ +--- + +# jenkins variables +project_name: docker-openssh-server +external_type: na +custom_version_command: "curl -s http://dl-cdn.alpinelinux.org/alpine/v3.10/main/x86_64/ |awk -F '(openssh-server-|.apk)' '/openssh-server.*.apk/ {print $2; exit}'" +release_type: stable +release_tag: latest +ls_branch: master +repo_vars: + - CONTAINER_NAME = 'openssh-server' + - BUILD_VERSION_ARG = 'OPENSSH_RELEASE' + - LS_USER = 'linuxserver' + - LS_REPO = 'docker-openssh-server' + - DOCKERHUB_IMAGE = 'linuxserver/openssh-server' + - DEV_DOCKERHUB_IMAGE = 'lsiodev/openssh-server' + - PR_DOCKERHUB_IMAGE = 'lspipepr/openssh-server' + - DIST_IMAGE = 'alpine' + - MULTIARCH='true' + - CI='true' + - CI_WEB='false' + - CI_PORT='80' + - CI_SSL='false' + - CI_DELAY='60' + - CI_DOCKERENV='TZ=US/Pacific' + - CI_AUTH='user:password' + - CI_WEBPATH='' diff --git a/readme-vars.yml b/readme-vars.yml new file mode 100644 index 0000000..6dd00ee --- /dev/null +++ b/readme-vars.yml @@ -0,0 +1,71 @@ +--- + +# project information +project_name: openssh-server +project_url: "https://www.openssh.com/" +project_logo: "https://upload.wikimedia.org/wikipedia/en/6/65/OpenSSH_logo.png" +project_blurb: "[{{ project_name|capitalize }}]({{ project_url }}) is a sandboxed environment that allows ssh access without giving keys to the entire server. + +Giving ssh access via private key often means giving full access to the server. This container creates a limited and sandboxed environment that others can ssh into. + +The users only have access to the folders mapped and the processes running inside this container." +project_lsio_github_repo_url: "https://github.com/linuxserver/docker-{{ project_name }}" + +# supported architectures +available_architectures: + - { arch: "{{ arch_x86_64 }}", tag: "amd64-latest"} + - { arch: "{{ arch_arm64 }}", tag: "arm64v8-latest"} + - { arch: "{{ arch_armhf }}", tag: "arm32v7-latest"} + +# development version +development_versions: false +development_versions_items: + - { tag: "latest", desc: "Stable releases" } + +# container parameters +common_param_env_vars_enabled: true +param_container_name: "{{ project_name }}" +param_usage_include_vols: true +param_volumes: + - { vol_path: "/config", vol_host_path: "/path/to/appdata/config", desc: "Contains all relevant configuration files." } +param_usage_include_ports: true +param_ports: + - { external_port: "22", internal_port: "22", port_desc: "ssh port" } +param_usage_include_env: true +param_env_vars: + - { env_var: "TZ", env_value: "Europe/London", desc: "Specify a timezone to use EG Europe/London"} + +# optional container parameters +opt_param_usage_include_env: true +opt_param_env_vars: + - { env_var: "PUBLIC_KEY", env_value: "yourpublickey", desc: "Optional ssh public key, which will automatically be added to authorized_keys."} + - { env_var: "SUDO_ACCESS", env_value: "false", desc: "Set to `true` to allow `abc`, the ssh user, sudo access. Without `SUDO_PASSWORD` set, this will allow passwordless sudo access."} + - { env_var: "SUDO_PASSWORD", env_value: "password", desc: "Optionally set a sudo password for `abc`, the ssh user. If this is not set but `SUDO_ACCESS` is set to true, the user will have passwordless sudo access."} + - { env_var: "USER_NAME", env_value: "abc", desc: "Optionally specify a user name (Default:`abc`)"} + +optional_block_1: false +optional_block_1_items: "" + +# application setup block +app_setup_block_enabled: true +app_setup_block: | + If `PUBLIC_KEY` variable is set, it will automatically be added to `authorized_keys`. If not, the keys can manually be added to `/config/.ssh/authorized_keys` and the container should be restarted. + Removing `PUBLIC_KEY` variable from docker run environment variables will not remove the key from `authorized_keys`. + + Connect to server via `ssh -i /path/to/private/key -p PORT USER_NAME@SERVERIP` + + Setting `SUDO_ACCESS` to `true` by itself will allow passwordless sudo. `SUDO_PASSWORD` allows setting an optional sudo password. + + The users only have access to the folders mapped and the processes running inside this container. + Add any volume mappings you like for the users to have access to. + To install packages or services for users to access, use the LinuxServer container customization methods described [in this blog article](https://blog.linuxserver.io/2019/09/14/customizing-our-containers/). + + Sample use case is when a server admin would like to have automated incoming backups from a remote server to the local server, but they might not want all the other admins of the remote server to have full access to the local server. + This container can be set up with a mounted folder for incoming backups, and rsync installed via LinuxServer container customization described above, so that the incoming backups can proceed, but remote server and its admins' access would be limited to the backup folder. + + It is also possible to run multiple copies of this container with different ports mapped, different folders mounted and access to different private keys for compartmentalized access. + + +# changelog +changelogs: + - { date: "04.10.19:", desc: "Initial Release." } diff --git a/root/etc/cont-init.d/10-adduser b/root/etc/cont-init.d/10-adduser new file mode 100644 index 0000000..eca366f --- /dev/null +++ b/root/etc/cont-init.d/10-adduser @@ -0,0 +1,37 @@ +#!/usr/bin/with-contenv bash + +USER_NAME=${USER_NAME:-abc} + +PUID=${PUID:-911} +PGID=${PGID:-911} + +[[ ! "$USER_NAME" == "abc" ]] && \ + usermod -l "$USER_NAME" abc && \ + groupmod -n "$USER_NAME" abc + +groupmod -o -g "$PGID" "$USER_NAME" +usermod -o -u "$PUID" "$USER_NAME" + +echo ' +------------------------------------- + _ () + | | ___ _ __ + | | / __| | | / \ + | | \__ \ | | | () | + |_| |___/ |_| \__/ + + +Brought to you by linuxserver.io +We gratefully accept donations at: +https://www.linuxserver.io/donate/ +------------------------------------- +GID/UID +-------------------------------------' +echo " +User uid: $(id -u "$USER_NAME") +User gid: $(id -g "$USER_NAME") +------------------------------------- +" +chown "$USER_NAME":"$USER_NAME" /app +chown "$USER_NAME":"$USER_NAME" /config +chown "$USER_NAME":"$USER_NAME" /defaults \ No newline at end of file diff --git a/root/etc/cont-init.d/50-config b/root/etc/cont-init.d/50-config new file mode 100644 index 0000000..0ebc0d7 --- /dev/null +++ b/root/etc/cont-init.d/50-config @@ -0,0 +1,44 @@ +#!/usr/bin/with-contenv bash + +# create folders +mkdir -p \ + /config/.ssh + +USER_NAME=${USER_NAME:-abc} + +# set password for abc to unlock it and set sudo access +sed -i "/${USER_NAME} ALL.*/d" /etc/sudoers +if [ "$SUDO_ACCESS" == "true" ]; then + if [ -n "$SUDO_PASSWORD" ]; then + echo "${USER_NAME} ALL=(ALL) ALL" >> /etc/sudoers + else + echo "${USER_NAME} ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers + fi +fi +SUDO_PASSWORD=${SUDO_PASSWORD:-$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c${1:-8};echo;)} +echo "${USER_NAME}:${SUDO_PASSWORD}" | chpasswd + +if [ ! -d /config/ssh_host_keys ];then + cp -R /etc/ssh /config/ssh_host_keys +fi + +if [ ! -f /config/.ssh/authorized_keys ];then + touch /config/.ssh/authorized_keys +fi + +[[ -n "$PUBLIC_KEY" ]] && \ + [[ ! $(grep "$PUBLIC_KEY" /config/.ssh/authorized_keys) ]] && \ + echo "$PUBLIC_KEY" >> /config/.ssh/authorized_keys + +rm -rf /etc/ssh +cp -R /config/ssh_host_keys /etc/ssh + +# permissions +chown -R "${USER_NAME}":"${USER_NAME}" \ + /config +chown -R root:root \ + /etc/ssh +chmod 700 \ + /config/.ssh +chmod 600 \ + /config/.ssh/authorized_keys \ No newline at end of file diff --git a/root/etc/services.d/openssh-server/run b/root/etc/services.d/openssh-server/run new file mode 100644 index 0000000..aba779d --- /dev/null +++ b/root/etc/services.d/openssh-server/run @@ -0,0 +1,4 @@ +#!/usr/bin/with-contenv bash + +exec \ + /usr/sbin/sshd -D -e \ No newline at end of file