diff --git a/Dockerfile b/Dockerfile index d2cf57e..1c9d6b6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,26 +3,42 @@ FROM lsiobase/alpine:3.10 # set version label ARG BUILD_DATE ARG VERSION +ARG WEBAPP_VERSION LABEL build_version="Linuxserver.io version:- ${VERSION} Build-date:- ${BUILD_DATE}" LABEL maintainer="thelamer" -# build args -ARG DOWNURL="https://boot.netboot.xyz/ipxe" - RUN \ + echo "**** install build packages ****" && \ + apk add --no-cache --virtual=build-dependencies \ + nodejs-npm && \ echo "**** install runtime packages ****" && \ apk add --no-cache \ + curl \ + jq \ + nginx \ + nodejs \ tftp-hpa && \ - echo "**** download netboot payloads ****" && \ - wget -O \ - /config/netboot.xyz.kpxe \ - ${DOWNURL}/netboot.xyz.kpxe && \ - wget -O \ - /config/netboot.xyz.efi \ - ${DOWNURL}/netboot.xyz.efi && \ - echo "**** Permissions ****" && \ - chown -R abc:abc \ - /config + echo "**** install WebApp ****" && \ + if [ -z ${WEBAPP_VERSION+x} ]; then \ + WEBAPP_VERSION=$(curl -sX GET "https://api.github.com/repos/netbootxyz/webapp/releases/latest" \ + | awk '/tag_name/{print $4;exit}' FS='[""]'); \ + fi && \ + curl -o \ + /tmp/webapp.tar.gz -L \ + "https://github.com/netbootxyz/webapp/archive/${WEBAPP_VERSION}.tar.gz" && \ + tar xf \ + /tmp/webapp.tar.gz -C \ + /app/ --strip-components=1 && \ + npm config set unsafe-perm true && \ + npm install --prefix /app && \ + echo "**** cleanup ****" && \ + apk del --purge \ + build-dependencies && \ + rm -rf \ + /tmp/* + +# copy local files +COPY root/ / -# add local files -COPY /root / +# app runs on port 3000 +EXPOSE 3000 diff --git a/Dockerfile.aarch64 b/Dockerfile.aarch64 index a0397e0..884b6ec 100644 --- a/Dockerfile.aarch64 +++ b/Dockerfile.aarch64 @@ -3,26 +3,42 @@ FROM lsiobase/alpine:arm64v8-3.10 # set version label ARG BUILD_DATE ARG VERSION +ARG WEBAPP_VERSION LABEL build_version="Linuxserver.io version:- ${VERSION} Build-date:- ${BUILD_DATE}" LABEL maintainer="thelamer" -# build args -ARG DOWNURL="https://boot.netboot.xyz/ipxe" - RUN \ + echo "**** install build packages ****" && \ + apk add --no-cache --virtual=build-dependencies \ + nodejs-npm && \ echo "**** install runtime packages ****" && \ apk add --no-cache \ + curl \ + jq \ + nginx \ + nodejs \ tftp-hpa && \ - echo "**** download netboot payloads ****" && \ - wget -O \ - /config/netboot.xyz.kpxe \ - ${DOWNURL}/netboot.xyz.kpxe && \ - wget -O \ - /config/netboot.xyz.efi \ - ${DOWNURL}/netboot.xyz.efi && \ - echo "**** Permissions ****" && \ - chown -R abc:abc \ - /config + echo "**** install WebApp ****" && \ + if [ -z ${WEBAPP_VERSION+x} ]; then \ + WEBAPP_VERSION=$(curl -sX GET "https://api.github.com/repos/netbootxyz/webapp/releases/latest" \ + | awk '/tag_name/{print $4;exit}' FS='[""]'); \ + fi && \ + curl -o \ + /tmp/webapp.tar.gz -L \ + "https://github.com/netbootxyz/webapp/archive/${WEBAPP_VERSION}.tar.gz" && \ + tar xf \ + /tmp/webapp.tar.gz -C \ + /app/ --strip-components=1 && \ + npm config set unsafe-perm true && \ + npm install --prefix /app && \ + echo "**** cleanup ****" && \ + apk del --purge \ + build-dependencies && \ + rm -rf \ + /tmp/* + +# copy local files +COPY root/ / -# add local files -COPY /root / +# app runs on port 3000 +EXPOSE 3000 diff --git a/Dockerfile.armhf b/Dockerfile.armhf index 4df8b18..16fbcbd 100644 --- a/Dockerfile.armhf +++ b/Dockerfile.armhf @@ -3,26 +3,42 @@ FROM lsiobase/alpine:arm32v7-3.10 # set version label ARG BUILD_DATE ARG VERSION +ARG WEBAPP_VERSION LABEL build_version="Linuxserver.io version:- ${VERSION} Build-date:- ${BUILD_DATE}" LABEL maintainer="thelamer" -# build args -ARG DOWNURL="https://boot.netboot.xyz/ipxe" - RUN \ + echo "**** install build packages ****" && \ + apk add --no-cache --virtual=build-dependencies \ + nodejs-npm && \ echo "**** install runtime packages ****" && \ apk add --no-cache \ + curl \ + jq \ + nginx \ + nodejs \ tftp-hpa && \ - echo "**** download netboot payloads ****" && \ - wget -O \ - /config/netboot.xyz.kpxe \ - ${DOWNURL}/netboot.xyz.kpxe && \ - wget -O \ - /config/netboot.xyz.efi \ - ${DOWNURL}/netboot.xyz.efi && \ - echo "**** Permissions ****" && \ - chown -R abc:abc \ - /config + echo "**** install WebApp ****" && \ + if [ -z ${WEBAPP_VERSION+x} ]; then \ + WEBAPP_VERSION=$(curl -sX GET "https://api.github.com/repos/netbootxyz/webapp/releases/latest" \ + | awk '/tag_name/{print $4;exit}' FS='[""]'); \ + fi && \ + curl -o \ + /tmp/webapp.tar.gz -L \ + "https://github.com/netbootxyz/webapp/archive/${WEBAPP_VERSION}.tar.gz" && \ + tar xf \ + /tmp/webapp.tar.gz -C \ + /app/ --strip-components=1 && \ + npm config set unsafe-perm true && \ + npm install --prefix /app && \ + echo "**** cleanup ****" && \ + apk del --purge \ + build-dependencies && \ + rm -rf \ + /tmp/* + +# copy local files +COPY root/ / -# add local files -COPY /root / +# app runs on port 3000 +EXPOSE 3000 diff --git a/Jenkinsfile b/Jenkinsfile index 3376234..30c4e9b 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -16,8 +16,11 @@ pipeline { GITHUB_TOKEN=credentials('498b4638-2d02-4ce5-832d-8a57d01d97ab') GITLAB_TOKEN=credentials('b6f0f1dd-6952-4cf6-95d1-9c06380283f0') GITLAB_NAMESPACE=credentials('gitlab-namespace-id') + EXT_GIT_BRANCH = 'master' + EXT_USER = 'netbootxyz' + EXT_REPO = 'webapp' CONTAINER_NAME = 'netbootxyz' - BUILD_VERSION_ARG = 'NETBOOTXYZ_SHA' + BUILD_VERSION_ARG = 'WEBAPP_VERSION' LS_USER = 'linuxserver' LS_REPO = 'docker-netbootxyz' DOCKERHUB_IMAGE = 'linuxserver/netbootxyz' @@ -26,10 +29,10 @@ pipeline { DIST_IMAGE = 'alpine' MULTIARCH='true' CI='true' - CI_WEB='false' - CI_PORT='69' + CI_WEB='true' + CI_PORT='3000' CI_SSL='false' - CI_DELAY='60' + CI_DELAY='120' CI_DOCKERENV='TZ=US/Pacific' CI_AUTH='user:password' CI_WEBPATH='' @@ -98,16 +101,23 @@ pipeline { /* ######################## 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 -sL https://boot.netboot.xyz/ipxe/netboot.xyz-sha256-checksums.txt | grep 'netboot.xyz.kpxe' | cut -c1-8 ''', - returnStdout: true).trim() - env.RELEASE_LINK = 'custom_command' - } - } + // If this is a stable github release use the latest endpoint from github to determine the ext tag + stage("Set ENV github_stable"){ + steps{ + script{ + env.EXT_RELEASE = sh( + script: '''curl -s https://api.github.com/repos/${EXT_USER}/${EXT_REPO}/releases/latest | jq -r '. | .tag_name' ''', + returnStdout: true).trim() + } + } + } + // If this is a stable or devel github release generate the link for the build message + stage("Set ENV github_link"){ + steps{ + script{ + env.RELEASE_LINK = 'https://github.com/' + env.EXT_USER + '/' + env.EXT_REPO + '/releases/tag/' + env.EXT_RELEASE + } + } } // Sanitize the release tag and strip illegal docker or github characters stage("Sanitize tag"){ @@ -671,11 +681,11 @@ pipeline { "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 + curl -s https://api.github.com/repos/${EXT_USER}/${EXT_REPO}/releases/latest | jq '. |.body' | sed 's:^.\\(.*\\).$:\\1:' > 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 + "body": "**LinuxServer Changes:**\\n\\n'${LS_RELEASE_NOTES}'\\n**'${EXT_REPO}' 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''' diff --git a/README.md b/README.md index 43a4529..a210bdd 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,14 @@ The architectures supported by this image are: | arm64 | arm64v8-latest | | armhf | arm32v7-latest | +## Version Tags + +This image provides various versions that are available via tags. `latest` tag usually provides the latest stable version. Others are considered under development and caution must be exercised when using them. + +| Tag | Description | +| :----: | --- | +| latest | Web application for full self hosting | +| tftp | TFTP server only with NETBOOT.XYZ boot files | ## Usage @@ -64,7 +72,14 @@ Here are some example snippets to help you get started creating a container. ``` docker create \ --name=netbootxyz \ + -e PUID=1000 \ + -e PGID=1000 \ + -e MENU_VERSION=1.9.9 `#optional` \ + -p 3000:3000 \ -p 69:69/udp \ + -p 8080:80 `#optional` \ + -v /path/to/config:/config \ + -v /path/to/assets:/assets `#optional` \ --restart unless-stopped \ linuxserver/netbootxyz ``` @@ -81,8 +96,17 @@ services: netbootxyz: image: linuxserver/netbootxyz container_name: netbootxyz + environment: + - PUID=1000 + - PGID=1000 + - MENU_VERSION=1.9.9 #optional + volumes: + - /path/to/config:/config + - /path/to/assets:/assets #optional ports: + - 3000:3000 - 69:69/udp + - 8080:80 #optional restart: unless-stopped ``` @@ -92,7 +116,14 @@ Container images are configured using parameters passed at runtime (such as thos | Parameter | Function | | :----: | --- | +| `-p 3000` | Web configuration interface. | | `-p 69/udp` | TFTP Port. | +| `-p 80` | NGINX server for hosting assets. | +| `-e PUID=1000` | for UserID - see below for explanation | +| `-e PGID=1000` | for GroupID - see below for explanation | +| `-e MENU_VERSION=1.9.9` | Specify a specific version of boot files you want to use from NETBOOT.XYZ (unset pulls latest) | +| `-v /config` | Storage for boot menu files and web application config | +| `-v /assets` | Storage for NETBOOT.XYZ bootable assets (live CDs and other files) | ## Environment variables from files (Docker secrets) @@ -106,6 +137,19 @@ As an example: Will set the environment variable `PASSWORD` based on the contents of the `/run/secrets/mysecretpassword` file. +## 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 @@ -246,4 +290,6 @@ Once registered you can define the dockerfile to use with `-f Dockerfile.aarch64 ## Versions +* **13.12.19:** - Swapping latest tag over to webapp stack for management. +* **10.12.19:** - Adding tftp branch to provide tftp only option to latest users. * **22.10.19:** - Initial release. diff --git a/jenkins-vars.yml b/jenkins-vars.yml index 4547d38..008cc2b 100644 --- a/jenkins-vars.yml +++ b/jenkins-vars.yml @@ -2,14 +2,16 @@ # jenkins variables project_name: docker-netbootxyz -external_type: na -custom_version_command: "curl -sL https://boot.netboot.xyz/ipxe/netboot.xyz-sha256-checksums.txt | grep 'netboot.xyz.kpxe' | cut -c1-8" +external_type: github_stable release_type: stable release_tag: latest ls_branch: master repo_vars: + - EXT_GIT_BRANCH = 'master' + - EXT_USER = 'netbootxyz' + - EXT_REPO = 'webapp' - CONTAINER_NAME = 'netbootxyz' - - BUILD_VERSION_ARG = 'NETBOOTXYZ_SHA' + - BUILD_VERSION_ARG = 'WEBAPP_VERSION' - LS_USER = 'linuxserver' - LS_REPO = 'docker-netbootxyz' - DOCKERHUB_IMAGE = 'linuxserver/netbootxyz' @@ -18,10 +20,10 @@ repo_vars: - DIST_IMAGE = 'alpine' - MULTIARCH='true' - CI='true' - - CI_WEB='false' - - CI_PORT='69' + - CI_WEB='true' + - CI_PORT='3000' - CI_SSL='false' - - CI_DELAY='60' + - CI_DELAY='120' - CI_DOCKERENV='TZ=US/Pacific' - CI_AUTH='user:password' - CI_WEBPATH='' diff --git a/readme-vars.yml b/readme-vars.yml index c036c49..5b0902e 100644 --- a/readme-vars.yml +++ b/readme-vars.yml @@ -13,15 +13,35 @@ available_architectures: - { arch: "{{ arch_arm64 }}", tag: "arm64v8-latest"} - { arch: "{{ arch_armhf }}", tag: "arm32v7-latest"} +# development version +development_versions: true +development_versions_items: + - { tag: "latest", desc: "Web application for full self hosting" } + - { tag: "tftp", desc: "TFTP server only with NETBOOT.XYZ boot files" } + # container parameters -common_param_env_vars_enabled: false +common_param_env_vars_enabled: true param_container_name: "{{ project_name }}" -param_usage_include_vols: false +param_usage_include_vols: true +param_volumes: + - { vol_path: "/config", vol_host_path: "/path/to/config", desc: "Storage for boot menu files and web application config" } param_usage_include_ports: true param_ports: + - { external_port: "3000", internal_port: "3000", port_desc: "Web configuration interface." } - { external_port: "69", internal_port: "69/udp", port_desc: "TFTP Port." } param_usage_include_env: false +# optional env variables +opt_param_usage_include_env: true +opt_param_env_vars: + - { env_var: "MENU_VERSION", env_value: "1.9.9", desc: "Specify a specific version of boot files you want to use from NETBOOT.XYZ (unset pulls latest)"} +opt_param_usage_include_ports: true +opt_param_ports: + - { external_port: "8080", internal_port: "80", port_desc: "NGINX server for hosting assets." } +opt_param_usage_include_vols: true +opt_param_volumes: + - { vol_path: "/assets", vol_host_path: "/path/to/assets", desc: "Storage for NETBOOT.XYZ bootable assets (live CDs and other files)" } + # application setup block app_setup_block_enabled: true app_setup_block: | @@ -97,4 +117,6 @@ app_setup_block: | # changelog changelogs: + - { date: "13.12.19:", desc: "Swapping latest tag over to webapp stack for management." } + - { date: "10.12.19:", desc: "Adding tftp branch to provide tftp only option to latest users." } - { date: "22.10.19:", desc: "Initial release." } diff --git a/root/defaults/default b/root/defaults/default new file mode 100644 index 0000000..a5a0a08 --- /dev/null +++ b/root/defaults/default @@ -0,0 +1,7 @@ +server { + listen 80; + location / { + root /assets; + autoindex on; + } +} diff --git a/root/defaults/nginx.conf b/root/defaults/nginx.conf new file mode 100644 index 0000000..7649f6d --- /dev/null +++ b/root/defaults/nginx.conf @@ -0,0 +1,26 @@ +user abc; +worker_processes 4; +pid /run/nginx.pid; +include /etc/nginx/modules/*.conf; + +events { + worker_connections 768; +} + +http { + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + client_max_body_size 0; + include /etc/nginx/mime.types; + default_type application/octet-stream; + access_log /config/log/nginx/access.log; + error_log /config/log/nginx/error.log; + gzip on; + gzip_disable "msie6"; + include /config/nginx/site-confs/*; + +} +daemon off; diff --git a/root/etc/cont-init.d/20-nginx-config b/root/etc/cont-init.d/20-nginx-config new file mode 100644 index 0000000..ab2991a --- /dev/null +++ b/root/etc/cont-init.d/20-nginx-config @@ -0,0 +1,18 @@ +#!/usr/bin/with-contenv bash + +# make our folders +mkdir -p \ + /assets \ + /config/{nginx/site-confs,log/nginx} \ + /run \ + /var/lib/nginx/tmp/client_body \ + /var/tmp/nginx + +# copy config files +[[ ! -f /config/nginx/nginx.conf ]] && \ + cp /defaults/nginx.conf /config/nginx/nginx.conf +[[ ! -f /config/nginx/site-confs/default ]] && \ + cp /defaults/default /config/nginx/site-confs/default + +# Ownership +chown -R abc:abc /assets \ No newline at end of file diff --git a/root/etc/cont-init.d/36-download-menus b/root/etc/cont-init.d/36-download-menus new file mode 100644 index 0000000..738e8dc --- /dev/null +++ b/root/etc/cont-init.d/36-download-menus @@ -0,0 +1,41 @@ +#!/usr/bin/with-contenv bash + +# create local logs dir +mkdir -p \ + /config/menus/remote \ + /config/menus/local + +# download menus if not found +if [[ ! -f /config/menus/remote/menu.ipxe ]]; then + if [[ -z ${MENU_VERSION+x} ]]; then \ + MENU_VERSION=$(curl -sL "https://api.github.com/repos/netbootxyz/netboot.xyz/releases/latest" | jq -r '.tag_name') + fi + echo "[netbootxyz-init] Downloading Netboot.xyz at ${MENU_VERSION}" + # menu files + curl -o \ + /config/endpoints.yml -sL \ + "https://raw.githubusercontent.com/netbootxyz/netboot.xyz/${MENU_VERSION}/endpoints.yml" + curl -o \ + /tmp/menus.tar.gz -sL \ + "https://github.com/netbootxyz/netboot.xyz/releases/download/${MENU_VERSION}/menus.tar.gz" + tar xf \ + /tmp/menus.tar.gz -C \ + /config/menus/remote + # boot files + curl -o \ + /config/menus/remote/netboot.xyz-undionly.kpxe -sL \ + "https://github.com/netbootxyz/netboot.xyz/releases/download/${MENU_VERSION}/netboot.xyz-undionly.kpxe" + curl -o \ + /config/menus/remote/netboot.xyz.efi -sL \ + "https://github.com/netbootxyz/netboot.xyz/releases/download/${MENU_VERSION}/netboot.xyz.efi" + curl -o \ + /config/menus/remote/netboot.xyz.kpxe -sL \ + "https://github.com/netbootxyz/netboot.xyz/releases/download/${MENU_VERSION}/netboot.xyz.kpxe" + # layer and cleanup + echo -n ${MENU_VERSION} > /config/menuversion.txt + cp /config/menus/remote/* /config/menus + rm -f /tmp/menus.tar.gz +fi + +# Ownership +chown -R abc:abc /config diff --git a/root/etc/services.d/nginx/run b/root/etc/services.d/nginx/run new file mode 100644 index 0000000..daf42ab --- /dev/null +++ b/root/etc/services.d/nginx/run @@ -0,0 +1,2 @@ +#!/usr/bin/with-contenv bash +exec /usr/sbin/nginx -c /config/nginx/nginx.conf \ No newline at end of file diff --git a/root/etc/services.d/tftp/run b/root/etc/services.d/tftp/run index a4eb229..35b39e2 100644 --- a/root/etc/services.d/tftp/run +++ b/root/etc/services.d/tftp/run @@ -1,4 +1,4 @@ #!/usr/bin/with-contenv bash /usr/sbin/in.tftpd \ - --foreground --listen --user abc --secure /config + --foreground --listen --user abc --secure /config/menus \ No newline at end of file diff --git a/root/etc/services.d/webapp/run b/root/etc/services.d/webapp/run new file mode 100644 index 0000000..0404ef6 --- /dev/null +++ b/root/etc/services.d/webapp/run @@ -0,0 +1,6 @@ +#!/usr/bin/with-contenv bash + +# Run App +cd /app +exec \ +s6-setuidgid abc /usr/bin/node app.js