From 027cd380898c44e318b59a6e7d1bab0e1a5dcd7c Mon Sep 17 00:00:00 2001 From: Antony Messerli Date: Mon, 6 Sep 2021 19:07:15 -0500 Subject: [PATCH] first commit --- .github/workflows/build.yml | 135 ++++++++++++++++++++++++++++++++++++ .gitignore | 1 + Dockerfile | 56 +++++++++++++++ README.md | 69 ++++++++++++++++++ root/defaults/default | 7 ++ root/defaults/nginx.conf | 26 +++++++ root/donate.txt | 1 + root/etc/supervisor.conf | 33 +++++++++ root/start.sh | 82 ++++++++++++++++++++++ 9 files changed, 410 insertions(+) create mode 100644 .github/workflows/build.yml create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 README.md create mode 100644 root/defaults/default create mode 100644 root/defaults/nginx.conf create mode 100644 root/donate.txt create mode 100644 root/etc/supervisor.conf create mode 100755 root/start.sh diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..93fe926 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,135 @@ +name: netbootxyz +on: + push: + schedule: + - cron: '0 6 * * 0' + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + fetch-depth: '0' + + - name: Set env variables + run: | + echo "GITHUB_DATE=$(date +'%Y-%m-%dT%H:%M:%S')" >> $GITHUB_ENV + echo "GITHUB_SHA=${{ github.sha }}" >> $GITHUB_ENV + + - name: Get latest Webapp release version + run: | + WEBAPP_RELEASE=$(curl -sX GET "https://api.github.com/repos/netbootxyz/webapp/releases/latest" | jq -r '. | .tag_name') + echo "WEBAPP_RELEASE=${WEBAPP_RELEASE}" >> $GITHUB_ENV + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v1 + + - name: Login to the GitHub Container Registry + uses: docker/login-action@v1 + with: + registry: ghcr.io + username: ${{ secrets.GHCR_USER }} + password: ${{ secrets.GHCR_TOKEN }} + + - name: Determine version numbers + id: version_check + continue-on-error: true + run: | + tag=latest + IMAGE=antonym/netbootxyz + TOKEN=$(curl -sX GET \ + "https://ghcr.io/token?scope=repository%3Aantonym%2Fnetbootxyz%3Apull" \ + | jq -r '.token') + MULTIDIGEST=$(curl -s \ + --header "Accept: application/vnd.docker.distribution.manifest.v2+json" \ + --header "Authorization: Bearer ${TOKEN}" \ + "https://ghcr.io/v2/${IMAGE}/manifests/${tag}" \ + | jq -r 'first(.manifests[].digest)') + DIGEST=$(curl -s \ + --header "Accept: application/vnd.docker.distribution.manifest.v2+json" \ + --header "Authorization: Bearer ${TOKEN}" \ + "https://ghcr.io/v2/${IMAGE}/manifests/${MULTIDIGEST}" \ + | jq -r '.config.digest') + IMAGE_INFO=$(curl -sL \ + --header "Authorization: Bearer ${TOKEN}" \ + "https://ghcr.io/v2/${IMAGE}/blobs/${DIGEST}" \ + | jq -r '.config') + IMAGE_RELEASE=$(echo ${IMAGE_INFO} | jq -r '.Labels.build_version' | awk '{print $3}') + IMAGE_VERSION=$(echo ${IMAGE_RELEASE} | awk -F'-nbxyz' '{print $1}') + NB_RELEASE_NUMBER=$(echo ${IMAGE_RELEASE} | awk -F'-nbxyz' '{print $2}') + TAG_SHA=$(git rev-list -n 1 ${IMAGE_RELEASE}) + if [ -z "${MULTIDIGEST}" ] || [ "${MULTIDIGEST}" == "null" ]; then + echo "**** No existing container build found, assuming first build ****" + VERSION_TAG=${WEBAPP_RELEASE}-nbxyz1 + echo "VERSION_TAG=${VERSION_TAG}" >> $GITHUB_ENV + elif [ "${WEBAPP_RELEASE}" == "${IMAGE_VERSION}" ]; then + echo "**** Version ${WEBAPP_RELEASE} unchanged, checking if there is anything to build..." + if [ "${TAG_SHA}" == "${GITHUB_SHA}" ]; then + echo "**** Nothing to do, exiting build... **** " + exit 1 + else + echo "**** Changes found... incrementing build number version... ****" + NB_RELEASE_NUMBER=$((NB_RELEASE_NUMBER + 1)) + VERSION_TAG=${IMAGE_VERSION}-nbxyz${NB_RELEASE_NUMBER} + echo "VERSION_TAG=${VERSION_TAG}" >> $GITHUB_ENV + fi + else + echo "**** New version ${WEBAPP_RELEASE} found; old version was ${IMAGE_VERSION}. Generating new webapp release... ****" + VERSION_TAG=${WEBAPP_RELEASE}-nbxyz1 + echo "VERSION_TAG=${VERSION_TAG}" >> $GITHUB_ENV + fi + + - name: Docker meta + if: steps.version_check.outcome == 'success' && steps.version_check.conclusion == 'success' + id: meta + uses: docker/metadata-action@v3 + with: + images: netbootxyz/netbootxyz + labels: | + maintainer=antonym + org.opencontainers.image.created=${{ env.GITHUB_DATE }} + org.opencontainers.image.authors=netboot.xyz + org.opencontainers.image.url=https://github.com/netbootxyz/docker-netbootxyz/packages + org.opencontainers.image.documentation=https://netboot.xyz + org.opencontainers.image.source=https://github.com/netbootxyz/docker-netbootxyz + org.opencontainers.image.version=${{ env.VERSION_TAG }} + org.opencontainers.image.revision=${{ env.GITHUB_SHA }} + org.opencontainers.image.vendor=netboot.xyz + org.opencontainers.image.licenses=Apache-2.0 + org.opencontainers.image.ref.name=${{ env.GITHUB_SHA }} + org.opencontainers.image.title=netbootxyz + org.opencontainers.image.description=netboot.xyz official docker container - Your favorite operating systems in one place. A network-based bootable operating system installer based on iPXE. + + - name: Build and push image + if: steps.version_check.outcome == 'success' && steps.version_check.conclusion == 'success' + uses: docker/build-push-action@v2 + with: + push: true + context: . + file: ./Dockerfile + platforms: linux/amd64,linux/arm64 + build-args: | + WEBAPP_VERSION=${{ env.WEBAPP_RELEASE }} + VERSION=${{ env.VERSION_TAG }} + BUILD_DATE=${{ env.GITHUB_DATE }} + tags: | + ghcr.io/antonym/${{ github.workflow }}:latest + ghcr.io/antonym/${{ github.workflow }}:${{ github.sha }} + ghcr.io/antonym/${{ github.workflow }}:${{ env.VERSION_TAG }} + labels: ${{ steps.meta.outputs.labels }} + + - name: Bump version and push tag + if: steps.version_check.outcome == 'success' && steps.version_check.conclusion == 'success' + id: tag_version + uses: anothrNick/github-tag-action@1.26.0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CUSTOM_TAG: ${{ env.VERSION_TAG }} + WITH_V: true + RELEASE_BRANCHES: main diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e879484 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +go.sh diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..cdac055 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,56 @@ +FROM alpine:3.14 + +# set version label +ARG BUILD_DATE +ARG VERSION +ARG WEBAPP_VERSION +LABEL build_version="netboot.xyz version: ${VERSION} Build-date: ${BUILD_DATE}" +LABEL maintainer="antonym" + +RUN \ + apk add --no-cache --virtual=build-dependencies \ + nodejs npm && \ + echo "**** install runtime packages ****" && \ + apk add --no-cache \ + bash \ + busybox \ + curl \ + git \ + jq \ + nghttp2-dev \ + nginx \ + nodejs \ + shadow \ + sudo \ + supervisor \ + syslog-ng \ + tar \ + tftp-hpa + +RUN \ + groupmod -g 1000 users && \ + useradd -u 911 -U -d /config -s /bin/false nbxyz && \ + usermod -G users nbxyz && \ + mkdir /app \ + /config \ + /defaults && \ + 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 + +EXPOSE 3000 + +COPY root/ / + +# default command +CMD ["sh","/start.sh"] + diff --git a/README.md b/README.md new file mode 100644 index 0000000..9c3465f --- /dev/null +++ b/README.md @@ -0,0 +1,69 @@ +# docker-netbootxyz + +## Overview + +The netboot.xyz docker image allows you to easily set up a local instance of netboot.xyz with a single command. The container is built from Alpine Linux and contains several components: + +* netboot.xyz [webapp](https://github.com/netbootxyz/webapp) +* Nginx for hosting local assets from the container +* tftp-hpa +* syslog for providing tftp activity logs + +Services are managed in the container by [supervisord](http://supervisord.org/). +## Usage + +The following snippets are examples of starting up the container. +### docker-cli + +``` +docker run -d \ + --name=netbootxyz \ + -e MENU_VERSION=2.0.47 `# optional` \ + -p 3000:3000 \ # sets webapp port + -p 69:69/udp \ # sets tftp port + -p 8080:80 `# optional` \ + -v /local/path/to/config:/config `# optional` \ + -v /local/path/to/assets:/assets `# optional` \ + --restart unless-stopped \ + ghcr.io/netbootxyz/netbootxyz +``` + +### docker-compose + +``` +--- +version: "2.1" +services: + netbootxyz: + image: ghcr.io/netbootxyz/netbootxyz + container_name: netbootxyz + environment: + - MENU_VERSION=2.0.47 # optional + volumes: + - /local/path/to/config:/config # optional + - /local/path/to/assets:/assets # optional + ports: + - 3000:3000 + - 69:69/udp + - 8080:80 #optional + restart: unless-stopped +``` + +Once the container is started, the netboot.xyz web application can be accessed by the web configuration interface at http://localhost:3000 or via the specified port. + +Downloaded web assets will be available at http://localhost:8080 or the specified port. If you have specified the assets volume, the assets will be available at http://localhost:8080. + +If you wish to start over from scratch, you can remove the local configuration folders and upon restart of the container, it will load the default configurations. + +## 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 3000` | Web configuration interface. | +| `-p 69/udp` | TFTP Port. | +| `-p 80` | NGINX server for hosting assets. | +| `-e MENU_VERSION=2.0.47` | 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) | 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..ae1d6f0 --- /dev/null +++ b/root/defaults/nginx.conf @@ -0,0 +1,26 @@ +user nbxyz; +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/donate.txt b/root/donate.txt new file mode 100644 index 0000000..17c0b46 --- /dev/null +++ b/root/donate.txt @@ -0,0 +1 @@ +netboot.xyz: https://opencollective.com/netbootxyz/donate diff --git a/root/etc/supervisor.conf b/root/etc/supervisor.conf new file mode 100644 index 0000000..694fd10 --- /dev/null +++ b/root/etc/supervisor.conf @@ -0,0 +1,33 @@ +[supervisord] +nodaemon=true +user=root + +[program:syslog-ng] +command=/usr/sbin/syslog-ng --foreground --no-caps +stdout_syslog=true +stdout_capture_maxbytes=1MB +priority = 1 + +[program:nginx] +command = /usr/sbin/nginx -c /config/nginx/nginx.conf +startretries = 2 +daemon=off +priority = 2 + +[program:webapp] +environment=NODE_ENV="production",PORT=3000 +command=/usr/bin/node app.js +user=nbxyz +directory=/app +priority = 3 + +[program:in.tftpd] +command=/usr/sbin/in.tftpd -Lvvv --user nbxyz --secure /config/menus +stdout_logfile=/config/tftpd.log +redirect_stderr=true +priority = 4 + +[program:messages-log] +command=tail -f /var/log/messages +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 diff --git a/root/start.sh b/root/start.sh new file mode 100755 index 0000000..5e1cd7a --- /dev/null +++ b/root/start.sh @@ -0,0 +1,82 @@ +#!/bin/bash + +# make our folders +mkdir -p \ + /assets \ + /config/nginx/site-confs \ + /config/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 nbxyz:nbxyz /assets +chown -R nbxyz:nbxyz /var/lib/nginx +chown -R nbxyz:nbxyz /var/log/nginx + +# 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.kpxe -sL \ + "https://github.com/netbootxyz/netboot.xyz/releases/download/${MENU_VERSION}/netboot.xyz.kpxe" + 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-snp.efi -sL \ + "https://github.com/netbootxyz/netboot.xyz/releases/download/${MENU_VERSION}/netboot.xyz-snp.efi" + curl -o \ + /config/menus/remote/netboot.xyz-snponly.efi -sL \ + "https://github.com/netbootxyz/netboot.xyz/releases/download/${MENU_VERSION}/netboot.xyz-snponly.efi" + curl -o \ + /config/menus/remote/netboot.xyz-arm64.efi -sL \ + "https://github.com/netbootxyz/netboot.xyz/releases/download/${MENU_VERSION}/netboot.xyz-arm64.efi" + curl -o \ + /config/menus/remote/netboot.xyz-arm64.efi -sL \ + "https://github.com/netbootxyz/netboot.xyz/releases/download/${MENU_VERSION}/netboot.xyz-rpi4-snp.efi" + # layer and cleanup + echo -n ${MENU_VERSION} > /config/menuversion.txt + cp -r /config/menus/remote/* /config/menus + rm -f /tmp/menus.tar.gz +fi + +# Ownership +chown -R nbxyz:nbxyz /config + +echo " _ _ _ " +echo " _ __ ___| |_| |__ ___ ___ | |_ __ ___ _ ____ " +echo "| '_ \ / _ \ __| '_ \ / _ \ / _ \| __| \ \/ / | | |_ / " +echo "| | | | __/ |_| |_) | (_) | (_) | |_ _ > <| |_| |/ / " +echo "|_| |_|\___|\__|_.__/ \___/ \___/ \__(_)_/\_\\__, /___| " +echo " |___/ " + +supervisord -c /etc/supervisor.conf