From 7c0ba55c362847ddf2ba386bb52ae8540d1442b4 Mon Sep 17 00:00:00 2001 From: thespad Date: Sun, 5 Jan 2025 18:13:43 +0000 Subject: [PATCH 01/20] Support multi-host operation --- README.md | 40 ++++++++++++++++++++++++++++++++++++++++ readme-vars.yml | 40 ++++++++++++++++++++++++++++++++++++++++ root/app/update-mods.sh | 38 +++++++++++++++++++++++++++++++------- 3 files changed, 111 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 03a6840..3124d36 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,43 @@ If a mod requires additional packages to be installed, each container will still Note that the Modmanager container itself does not support applying mods *or* custom files/services. +### Multiple Hosts + +>[!WARNING] +>Make sure you fully understand what you're doing before you try and set this up as there are lots of ways it can go wrong. + +Modmanager can query & download mods for remote hosts, as well as the one on which it is installed. At a very basic level if you're just using the DOCKER_MODS env and not the docker integration, simply mount the `/modcache` folder on your remote host(s), ensuring it is writeable by all participating containers. + +If you are using the docker integration, our only supported means for connecting to remote hosts is [our socket proxy container](). Run an instance on each remote host: + +>[!WARNING] +>DO NOT expose a socket proxy to your LAN that allows any write operations (`POST=1`, `ALLOW_RESTART=1`, etc) or that exposes any more information than is absolutely necessary. NEVER expose a socket proxy to your WAN. + +```yml + modmanager-dockerproxy: + image: lscr.io/linuxserver/socket-proxy:latest + container_name: modmanager-dockerproxy + environment: + - CONTAINERS=1 + - POST=0 + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + tmpfs: + - /run:exec + ports: + - 2375:2375 + restart: unless-stopped + read_only: true +``` + +And then add it to the `DOCKER_MODS_EXTRA_HOSTS` env using the full protocol and port, e.g. + +```yaml + - DOCKER_MODS_EXTRA_HOSTS=tcp://host1.example.com:2375|tcp://host2.example.com:2375|tcp://192.168.0.5:2375 +``` + +As above you will need to mount the `/modcache` folder on your remote host(s), ensuring it is writeable by all participating containers. + ### Security considerations Mapping `docker.sock` is a potential security liability because docker has root access on the host and any process that has full access to `docker.sock` would also have root access on the host. Docker api has no built-in way to set limitations on access, however, you can use a proxy for the `docker.sock` via a solution like [our docker socket proxy](https://github.com/linuxserver/docker-socket-proxy), which adds the ability to limit access. Then you would just set `DOCKER_HOST=` environment variable to point to the proxy address. @@ -84,6 +121,7 @@ services: environment: - DOCKER_MODS= `#optional` - DOCKER_HOST= `#optional` + - DOCKER_MODS_EXTRA_HOSTS= `#optional` volumes: - /path/to/modcache:/modcache - /var/run/docker.sock:/var/run/docker.sock:ro `#optional` @@ -97,6 +135,7 @@ docker run -d \ --name=modmanager \ -e DOCKER_MODS= `#optional` \ -e DOCKER_HOST= `#optional` \ + -e DOCKER_MODS_EXTRA_HOSTS= `#optional` \ -v /path/to/modcache:/modcache \ -v /var/run/docker.sock:/var/run/docker.sock:ro `#optional` \ --restart unless-stopped \ @@ -111,6 +150,7 @@ Containers are configured using parameters passed at runtime (such as those abov | :----: | --- | | `-e DOCKER_MODS=` | Pipe-delimited (`\|`) list of mods to download | | `-e DOCKER_HOST=` | Specify the docker endpoint to use if not using the docker.sock | +| `-e DOCKER_MODS_EXTRA_HOSTS=` | Pipe-delimited (`\|`) list of additional hosts to query & download mods for. See app setup section for details. | | `-v /modcache` | Modmanager mod storage. | | `-v /var/run/docker.sock:ro` | Mount the host docker socket into the container. | diff --git a/readme-vars.yml b/readme-vars.yml index 7feb711..f1d1925 100644 --- a/readme-vars.yml +++ b/readme-vars.yml @@ -66,6 +66,43 @@ full_custom_readme: | Note that the Modmanager container itself does not support applying mods *or* custom files/services. + ### Multiple Hosts + + >[!WARNING] + >Make sure you fully understand what you're doing before you try and set this up as there are lots of ways it can go wrong. + + Modmanager can query & download mods for remote hosts, as well as the one on which it is installed. At a very basic level if you're just using the DOCKER_MODS env and not the docker integration, simply mount the `/modcache` folder on your remote host(s), ensuring it is writeable by all participating containers. + + If you are using the docker integration, our only supported means for connecting to remote hosts is [our socket proxy container](). Run an instance on each remote host: + + >[!WARNING] + >DO NOT expose a socket proxy to your LAN that allows any write operations (`POST=1`, `ALLOW_RESTART=1`, etc) or that exposes any more information than is absolutely necessary. NEVER expose a socket proxy to your WAN. + + ```yml + modmanager-dockerproxy: + image: lscr.io/linuxserver/socket-proxy:latest + container_name: modmanager-dockerproxy + environment: + - CONTAINERS=1 + - POST=0 + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + tmpfs: + - /run:exec + ports: + - 2375:2375 + restart: unless-stopped + read_only: true + ``` + + And then add it to the `DOCKER_MODS_EXTRA_HOSTS` env using the full protocol and port, e.g. + + ```yaml + - DOCKER_MODS_EXTRA_HOSTS=tcp://host1.example.com:2375|tcp://host2.example.com:2375|tcp://192.168.0.5:2375 + ``` + + As above you will need to mount the `/modcache` folder on your remote host(s), ensuring it is writeable by all participating containers. + ### Security considerations Mapping `docker.sock` is a potential security liability because docker has root access on the host and any process that has full access to `docker.sock` would also have root access on the host. Docker api has no built-in way to set limitations on access, however, you can use a proxy for the `docker.sock` via a solution like [our docker socket proxy](https://github.com/linuxserver/docker-socket-proxy), which adds the ability to limit access. Then you would just set `DOCKER_HOST=` environment variable to point to the proxy address. @@ -88,6 +125,7 @@ full_custom_readme: | environment: - DOCKER_MODS= `#optional` - DOCKER_HOST= `#optional` + - DOCKER_MODS_EXTRA_HOSTS= `#optional` volumes: - /path/to/modcache:/modcache - /var/run/docker.sock:/var/run/docker.sock:ro `#optional` @@ -101,6 +139,7 @@ full_custom_readme: | --name=modmanager \ -e DOCKER_MODS= `#optional` \ -e DOCKER_HOST= `#optional` \ + -e DOCKER_MODS_EXTRA_HOSTS= `#optional` \ -v /path/to/modcache:/modcache \ -v /var/run/docker.sock:/var/run/docker.sock:ro `#optional` \ --restart unless-stopped \ @@ -115,6 +154,7 @@ full_custom_readme: | | :----: | --- | | `-e DOCKER_MODS=` | Pipe-delimited (`\|`) list of mods to download | | `-e DOCKER_HOST=` | Specify the docker endpoint to use if not using the docker.sock | + | `-e DOCKER_MODS_EXTRA_HOSTS=` | Pipe-delimited (`\|`) list of additional hosts to query & download mods for. See app setup section for details. | | `-v /modcache` | Modmanager mod storage. | | `-v /var/run/docker.sock:ro` | Mount the host docker socket into the container. | diff --git a/root/app/update-mods.sh b/root/app/update-mods.sh index 9de7e93..ba5929f 100755 --- a/root/app/update-mods.sh +++ b/root/app/update-mods.sh @@ -1,26 +1,50 @@ #!/usr/bin/with-contenv bash # shellcheck shell=bash -# Main script loop -if [[ -e "/var/run/docker.sock" ]] || [[ -n "${DOCKER_HOST}" ]]; then +find_docker_mods() { # Mods provided via Docker - echo -e "[mod-init] Searching all containers for DOCKER_MODS..." - for CONTAINER in $(docker ps -q); do - CONTAINER_MODS=$(docker inspect "${CONTAINER}" | jq -r '.[].Config.Env | to_entries | map(select(.value | match("DOCKER_MODS="))) | .[].value') - CONTAINER_NAME=$(docker inspect "${CONTAINER}" | jq -r .[].Name | cut -d '/' -f2) + if [[ "${2}" != "default" ]]; then + docker context create "${2}" --docker "host=${1}" >/dev/null 2>&1 + fi + docker --context "${2}" ps -q >/dev/null 2>&1 || DOCKER_MOD_CONTEXT_FAIL=true + if [[ "${DOCKER_MOD_CONTEXT_FAIL}" == "true" ]]; then + unset DOCKER_MOD_CONTEXT_FAIL + echo "[mod-init] (ERROR) Cannot connect to the Docker daemon at ${2}, skipping host" + return + fi + echo -e "[mod-init] Searching all containers in the ${2} context for DOCKER_MODS..." + for CONTAINER in $(docker --context "${2}" ps -q); do + CONTAINER_MODS=$(docker --context "${2}" inspect "${CONTAINER}" | jq -r '.[].Config.Env | to_entries | map(select(.value | match("DOCKER_MODS="))) | .[].value') + CONTAINER_NAME=$(docker --context "${2}" inspect "${CONTAINER}" | jq -r .[].Name | cut -d '/' -f2) if [[ -n ${CONTAINER_MODS} ]]; then CONTAINER_MODS=$(awk -F '=' '{print $2}' <<< "${CONTAINER_MODS}") for CONTAINER_MOD in $(tr '|' '\n' <<< "${CONTAINER_MODS}"); do if [[ "${DOCKER_MODS}" =~ ${CONTAINER_MOD} ]]; then echo -e "[mod-init] ${CONTAINER_MOD} already in mod list, skipping" else - echo -e "[mod-init] Found new mod ${CONTAINER_MODS} for container ${CONTAINER_NAME}" + echo -e "[mod-init] Found new mod ${CONTAINER_MOD} for container ${CONTAINER_NAME}" DOCKER_MODS="${DOCKER_MODS}|${CONTAINER_MOD}" DOCKER_MODS="${DOCKER_MODS#|}" fi done fi done + if [[ "${2}" != "default" ]]; then + docker context rm "${2}" >/dev/null + fi +} + +# Main script loop +if [[ -e "/var/run/docker.sock" ]] || [[ -n "${DOCKER_HOST}" ]]; then + find_docker_mods "${DOCKER_HOST:-docker.sock}" "default" +fi + +if [[ -n "${DOCKER_MODS_EXTRA_HOSTS}" ]]; then + for DOCKER_MOD_CONTEXT in $(echo "${DOCKER_MODS_EXTRA_HOSTS}" | tr '|' '\n'); do + DOCKER_MOD_CONTEXT_NAME="${DOCKER_MOD_CONTEXT##*//}" + DOCKER_MOD_CONTEXT_NAME="${DOCKER_MOD_CONTEXT_NAME%%:*}" + find_docker_mods "${DOCKER_MOD_CONTEXT}" "${DOCKER_MOD_CONTEXT_NAME}" + done fi if [[ -n "${DOCKER_MODS}" ]]; then From c835949fedda51c5cc3694b710bff5685b4c05ae Mon Sep 17 00:00:00 2001 From: thespad Date: Sun, 5 Jan 2025 18:20:35 +0000 Subject: [PATCH 02/20] Update changelog --- README.md | 1 + readme-vars.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/README.md b/README.md index 3124d36..2c0c042 100644 --- a/README.md +++ b/README.md @@ -274,4 +274,5 @@ Once registered you can define the dockerfile to use with `-f Dockerfile.aarch64 ## Versions +* **05.01.25:** - Support multiple hosts. * **22.12.24:** - Initial Release. diff --git a/readme-vars.yml b/readme-vars.yml index f1d1925..1b6486a 100644 --- a/readme-vars.yml +++ b/readme-vars.yml @@ -278,6 +278,7 @@ full_custom_readme: | ## Versions + * **05.01.25:** - Support multiple hosts. * **22.12.24:** - Initial Release. {%- endraw %} From aee533419274546e5bb5555127288a538296bf97 Mon Sep 17 00:00:00 2001 From: thespad Date: Sun, 5 Jan 2025 18:31:42 +0000 Subject: [PATCH 03/20] Scope var instead of unsetting --- root/app/update-mods.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/root/app/update-mods.sh b/root/app/update-mods.sh index ba5929f..cd912e1 100755 --- a/root/app/update-mods.sh +++ b/root/app/update-mods.sh @@ -6,9 +6,8 @@ find_docker_mods() { if [[ "${2}" != "default" ]]; then docker context create "${2}" --docker "host=${1}" >/dev/null 2>&1 fi - docker --context "${2}" ps -q >/dev/null 2>&1 || DOCKER_MOD_CONTEXT_FAIL=true + docker --context "${2}" ps -q >/dev/null 2>&1 || local DOCKER_MOD_CONTEXT_FAIL=true if [[ "${DOCKER_MOD_CONTEXT_FAIL}" == "true" ]]; then - unset DOCKER_MOD_CONTEXT_FAIL echo "[mod-init] (ERROR) Cannot connect to the Docker daemon at ${2}, skipping host" return fi From 2b909ece6d15467ef6c954c8528b5a849610b848 Mon Sep 17 00:00:00 2001 From: thespad Date: Sun, 5 Jan 2025 20:11:36 +0000 Subject: [PATCH 04/20] Include context in log output --- root/app/update-mods.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/root/app/update-mods.sh b/root/app/update-mods.sh index cd912e1..b7bc2ab 100755 --- a/root/app/update-mods.sh +++ b/root/app/update-mods.sh @@ -4,6 +4,7 @@ find_docker_mods() { # Mods provided via Docker if [[ "${2}" != "default" ]]; then + MOD_STATE="(${2})" docker context create "${2}" --docker "host=${1}" >/dev/null 2>&1 fi docker --context "${2}" ps -q >/dev/null 2>&1 || local DOCKER_MOD_CONTEXT_FAIL=true @@ -11,7 +12,7 @@ find_docker_mods() { echo "[mod-init] (ERROR) Cannot connect to the Docker daemon at ${2}, skipping host" return fi - echo -e "[mod-init] Searching all containers in the ${2} context for DOCKER_MODS..." + echo -e "[mod-init] ${MOD_STATE:+${MOD_STATE} }Searching all containers in the ${2} context for DOCKER_MODS..." for CONTAINER in $(docker --context "${2}" ps -q); do CONTAINER_MODS=$(docker --context "${2}" inspect "${CONTAINER}" | jq -r '.[].Config.Env | to_entries | map(select(.value | match("DOCKER_MODS="))) | .[].value') CONTAINER_NAME=$(docker --context "${2}" inspect "${CONTAINER}" | jq -r .[].Name | cut -d '/' -f2) @@ -19,9 +20,9 @@ find_docker_mods() { CONTAINER_MODS=$(awk -F '=' '{print $2}' <<< "${CONTAINER_MODS}") for CONTAINER_MOD in $(tr '|' '\n' <<< "${CONTAINER_MODS}"); do if [[ "${DOCKER_MODS}" =~ ${CONTAINER_MOD} ]]; then - echo -e "[mod-init] ${CONTAINER_MOD} already in mod list, skipping" + echo -e "[mod-init] ${MOD_STATE:+${MOD_STATE} }${CONTAINER_MOD} already in mod list, skipping" else - echo -e "[mod-init] Found new mod ${CONTAINER_MOD} for container ${CONTAINER_NAME}" + echo -e "[mod-init] ${MOD_STATE:+${MOD_STATE} }Found new mod ${CONTAINER_MOD} for container ${CONTAINER_NAME}" DOCKER_MODS="${DOCKER_MODS}|${CONTAINER_MOD}" DOCKER_MODS="${DOCKER_MODS#|}" fi From 36797a39169f8f40780500c9a309d03c2fd400b7 Mon Sep 17 00:00:00 2001 From: thespad Date: Sun, 5 Jan 2025 20:15:07 +0000 Subject: [PATCH 05/20] Include next run time in init output --- .../s6-overlay/s6-rc.d/init-modmanager-config/run | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/root/etc/s6-overlay/s6-rc.d/init-modmanager-config/run b/root/etc/s6-overlay/s6-rc.d/init-modmanager-config/run index db4b43e..fe28fd1 100755 --- a/root/etc/s6-overlay/s6-rc.d/init-modmanager-config/run +++ b/root/etc/s6-overlay/s6-rc.d/init-modmanager-config/run @@ -5,6 +5,16 @@ CRON_MINS=$((0 + RANDOM % 59)) sed -i "s/@@MINUTES@@/${CRON_MINS}/" /etc/crontabs/root -echo "[mod-init] Mod updates will run every 6 hours at ${CRON_MINS} minutes past the hour" +if [[ $(date "+%H") -gt 0 && $(date "+%H") -lt 6 ]]; then + NEXT_HOUR=6 +elif [[ $(date "+%H") -gt 6 && $(date "+%H") -lt 12 ]]; then + NEXT_HOUR=12 +elif [[ $(date "+%H") -gt 12 && $(date "+%H") -lt 18 ]]; then + NEXT_HOUR=18 +else [[ $(date "+%H") -gt 18 && $(date "+%H") -le 23 ]]; + NEXT_HOUR=0 +fi + +echo "[mod-init] Mod updates will run every 6 hours at ${CRON_MINS} minutes past the hour. Next update will be at ${NEXT_HOUR}:${CRON_MINS}." /app/update-mods.sh From 9f958ff12f919499fef201b1a90af2b89a0a809c Mon Sep 17 00:00:00 2001 From: thespad Date: Sun, 5 Jan 2025 20:17:09 +0000 Subject: [PATCH 06/20] Reorder readme sections --- README.md | 12 ++++++------ readme-vars.yml | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 2c0c042..5517563 100644 --- a/README.md +++ b/README.md @@ -62,12 +62,16 @@ If a mod requires additional packages to be installed, each container will still Note that the Modmanager container itself does not support applying mods *or* custom files/services. +### Security considerations + +Mapping `docker.sock` is a potential security liability because docker has root access on the host and any process that has full access to `docker.sock` would also have root access on the host. Docker api has no built-in way to set limitations on access, however, you can use a proxy for the `docker.sock` via a solution like [our docker socket proxy](https://github.com/linuxserver/docker-socket-proxy), which adds the ability to limit access. Then you would just set `DOCKER_HOST=` environment variable to point to the proxy address. + ### Multiple Hosts >[!WARNING] >Make sure you fully understand what you're doing before you try and set this up as there are lots of ways it can go wrong. -Modmanager can query & download mods for remote hosts, as well as the one on which it is installed. At a very basic level if you're just using the DOCKER_MODS env and not the docker integration, simply mount the `/modcache` folder on your remote host(s), ensuring it is writeable by all participating containers. +Modmanager can query & download mods for remote hosts, as well as the one on which it is installed. At a very basic level if you're just using the DOCKER_MODS env and not the docker integration, simply mount the `/modcache` folder on your remote host(s), ensuring it is mapped for all participating containers. If you are using the docker integration, our only supported means for connecting to remote hosts is [our socket proxy container](). Run an instance on each remote host: @@ -97,11 +101,7 @@ And then add it to the `DOCKER_MODS_EXTRA_HOSTS` env using the full protocol and - DOCKER_MODS_EXTRA_HOSTS=tcp://host1.example.com:2375|tcp://host2.example.com:2375|tcp://192.168.0.5:2375 ``` -As above you will need to mount the `/modcache` folder on your remote host(s), ensuring it is writeable by all participating containers. - -### Security considerations - -Mapping `docker.sock` is a potential security liability because docker has root access on the host and any process that has full access to `docker.sock` would also have root access on the host. Docker api has no built-in way to set limitations on access, however, you can use a proxy for the `docker.sock` via a solution like [our docker socket proxy](https://github.com/linuxserver/docker-socket-proxy), which adds the ability to limit access. Then you would just set `DOCKER_HOST=` environment variable to point to the proxy address. +As above you will need to mount the `/modcache` folder on your remote host(s), ensuring it is mapped for all participating containers. ## Usage diff --git a/readme-vars.yml b/readme-vars.yml index 1b6486a..7d913af 100644 --- a/readme-vars.yml +++ b/readme-vars.yml @@ -66,12 +66,16 @@ full_custom_readme: | Note that the Modmanager container itself does not support applying mods *or* custom files/services. + ### Security considerations + + Mapping `docker.sock` is a potential security liability because docker has root access on the host and any process that has full access to `docker.sock` would also have root access on the host. Docker api has no built-in way to set limitations on access, however, you can use a proxy for the `docker.sock` via a solution like [our docker socket proxy](https://github.com/linuxserver/docker-socket-proxy), which adds the ability to limit access. Then you would just set `DOCKER_HOST=` environment variable to point to the proxy address. + ### Multiple Hosts >[!WARNING] >Make sure you fully understand what you're doing before you try and set this up as there are lots of ways it can go wrong. - Modmanager can query & download mods for remote hosts, as well as the one on which it is installed. At a very basic level if you're just using the DOCKER_MODS env and not the docker integration, simply mount the `/modcache` folder on your remote host(s), ensuring it is writeable by all participating containers. + Modmanager can query & download mods for remote hosts, as well as the one on which it is installed. At a very basic level if you're just using the DOCKER_MODS env and not the docker integration, simply mount the `/modcache` folder on your remote host(s), ensuring it is mapped for all participating containers. If you are using the docker integration, our only supported means for connecting to remote hosts is [our socket proxy container](). Run an instance on each remote host: @@ -101,11 +105,7 @@ full_custom_readme: | - DOCKER_MODS_EXTRA_HOSTS=tcp://host1.example.com:2375|tcp://host2.example.com:2375|tcp://192.168.0.5:2375 ``` - As above you will need to mount the `/modcache` folder on your remote host(s), ensuring it is writeable by all participating containers. - - ### Security considerations - - Mapping `docker.sock` is a potential security liability because docker has root access on the host and any process that has full access to `docker.sock` would also have root access on the host. Docker api has no built-in way to set limitations on access, however, you can use a proxy for the `docker.sock` via a solution like [our docker socket proxy](https://github.com/linuxserver/docker-socket-proxy), which adds the ability to limit access. Then you would just set `DOCKER_HOST=` environment variable to point to the proxy address. + As above you will need to mount the `/modcache` folder on your remote host(s), ensuring it is mapped for all participating containers. ## Usage From 78cdd38493fc635413ba736d13e84a3e7f6d830b Mon Sep 17 00:00:00 2001 From: thespad Date: Sun, 5 Jan 2025 22:59:43 +0000 Subject: [PATCH 07/20] Make warning a note --- README.md | 4 ++-- readme-vars.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 5517563..e890abc 100644 --- a/README.md +++ b/README.md @@ -68,8 +68,8 @@ Mapping `docker.sock` is a potential security liability because docker has root ### Multiple Hosts ->[!WARNING] ->Make sure you fully understand what you're doing before you try and set this up as there are lots of ways it can go wrong. +>[!NOTE] +>Make sure you fully understand what you're doing before you try and set this up as there are lots of ways it can go wrong if you're just guessing. Modmanager can query & download mods for remote hosts, as well as the one on which it is installed. At a very basic level if you're just using the DOCKER_MODS env and not the docker integration, simply mount the `/modcache` folder on your remote host(s), ensuring it is mapped for all participating containers. diff --git a/readme-vars.yml b/readme-vars.yml index 7d913af..6dc5bd8 100644 --- a/readme-vars.yml +++ b/readme-vars.yml @@ -72,8 +72,8 @@ full_custom_readme: | ### Multiple Hosts - >[!WARNING] - >Make sure you fully understand what you're doing before you try and set this up as there are lots of ways it can go wrong. + >[!NOTE] + >Make sure you fully understand what you're doing before you try and set this up as there are lots of ways it can go wrong if you're just guessing. Modmanager can query & download mods for remote hosts, as well as the one on which it is installed. At a very basic level if you're just using the DOCKER_MODS env and not the docker integration, simply mount the `/modcache` folder on your remote host(s), ensuring it is mapped for all participating containers. From ce4c462e6a4d7710ca196057868c822a645c98a7 Mon Sep 17 00:00:00 2001 From: thespad Date: Sun, 5 Jan 2025 23:08:02 +0000 Subject: [PATCH 08/20] Lots of formatting and content tweaks --- README.md | 38 +++++++++++++++++++------------------- readme-vars.yml | 38 +++++++++++++++++++------------------- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index e890abc..e3cf728 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ The architectures supported by this image are: ## Application Setup -You can specify mods to download via the `DOCKER_MODS` environment variable like any other container, or allow discovery through docker by mounting the docker socket into the container (or configuring a suitable alternative endpoint via DOCKER_HOST). +You can specify mods to download via the `DOCKER_MODS` environment variable like any other container, or allow discovery through docker by mounting the docker socket into the container (or configuring a suitable alternative endpoint via the built-in `DOCKER_HOST` environment variable). The Modmanager container will download all needed mods on startup and then check for updates every 6 hours; if you're using docker discovery it will automatically pick up any new mods. @@ -64,38 +64,38 @@ Note that the Modmanager container itself does not support applying mods *or* cu ### Security considerations -Mapping `docker.sock` is a potential security liability because docker has root access on the host and any process that has full access to `docker.sock` would also have root access on the host. Docker api has no built-in way to set limitations on access, however, you can use a proxy for the `docker.sock` via a solution like [our docker socket proxy](https://github.com/linuxserver/docker-socket-proxy), which adds the ability to limit access. Then you would just set `DOCKER_HOST=` environment variable to point to the proxy address. +Mapping `docker.sock` is a potential security liability because docker has root access on the host and any process that has full access to `docker.sock` would therefore also have root access on the host. The docker API has no built-in way to set limitations on access, however, you can use a proxy for `docker.sock` via a solution like [our docker socket proxy](https://github.com/linuxserver/docker-socket-proxy), which adds the ability to limit API access to specific endpoints. ### Multiple Hosts >[!NOTE] >Make sure you fully understand what you're doing before you try and set this up as there are lots of ways it can go wrong if you're just guessing. -Modmanager can query & download mods for remote hosts, as well as the one on which it is installed. At a very basic level if you're just using the DOCKER_MODS env and not the docker integration, simply mount the `/modcache` folder on your remote host(s), ensuring it is mapped for all participating containers. +Modmanager can query & download mods for remote hosts, as well as the one on which it is installed. At a very basic level if you're just using the `DOCKER_MODS` env and not the docker integration, simply mount the `/modcache` folder on your remote host(s), ensuring it is mapped for all participating containers. -If you are using the docker integration, our only supported means for connecting to remote hosts is [our socket proxy container](). Run an instance on each remote host: +If you are using the docker integration, our only supported means for connecting to remote hosts is [our socket proxy container](https://github.com/linuxserver/docker-socket-proxy/). Run an instance on each remote host: >[!WARNING] ->DO NOT expose a socket proxy to your LAN that allows any write operations (`POST=1`, `ALLOW_RESTART=1`, etc) or that exposes any more information than is absolutely necessary. NEVER expose a socket proxy to your WAN. +>DO NOT expose a socket proxy to your LAN if it allows any write operations (`POST=1`, `ALLOW_RESTART=1`, etc) or exposes any API elements that are not absolutely necessary. NEVER expose a socket proxy to your WAN. ```yml modmanager-dockerproxy: - image: lscr.io/linuxserver/socket-proxy:latest - container_name: modmanager-dockerproxy - environment: - - CONTAINERS=1 - - POST=0 - volumes: - - /var/run/docker.sock:/var/run/docker.sock:ro - tmpfs: - - /run:exec - ports: - - 2375:2375 - restart: unless-stopped - read_only: true + image: lscr.io/linuxserver/socket-proxy:latest + container_name: modmanager-dockerproxy + environment: + - CONTAINERS=1 + - POST=0 + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + tmpfs: + - /run:exec + ports: + - 2375:2375 + restart: unless-stopped + read_only: true ``` -And then add it to the `DOCKER_MODS_EXTRA_HOSTS` env using the full protocol and port, e.g. +And then add it to the `DOCKER_MODS_EXTRA_HOSTS` env using the full protocol and port, separating multiple servers with a pipe (`\|`), e.g. ```yaml - DOCKER_MODS_EXTRA_HOSTS=tcp://host1.example.com:2375|tcp://host2.example.com:2375|tcp://192.168.0.5:2375 diff --git a/readme-vars.yml b/readme-vars.yml index 6dc5bd8..acae805 100644 --- a/readme-vars.yml +++ b/readme-vars.yml @@ -56,7 +56,7 @@ full_custom_readme: | ## Application Setup - You can specify mods to download via the `DOCKER_MODS` environment variable like any other container, or allow discovery through docker by mounting the docker socket into the container (or configuring a suitable alternative endpoint via DOCKER_HOST). + You can specify mods to download via the `DOCKER_MODS` environment variable like any other container, or allow discovery through docker by mounting the docker socket into the container (or configuring a suitable alternative endpoint via the built-in `DOCKER_HOST` environment variable). The Modmanager container will download all needed mods on startup and then check for updates every 6 hours; if you're using docker discovery it will automatically pick up any new mods. @@ -68,38 +68,38 @@ full_custom_readme: | ### Security considerations - Mapping `docker.sock` is a potential security liability because docker has root access on the host and any process that has full access to `docker.sock` would also have root access on the host. Docker api has no built-in way to set limitations on access, however, you can use a proxy for the `docker.sock` via a solution like [our docker socket proxy](https://github.com/linuxserver/docker-socket-proxy), which adds the ability to limit access. Then you would just set `DOCKER_HOST=` environment variable to point to the proxy address. + Mapping `docker.sock` is a potential security liability because docker has root access on the host and any process that has full access to `docker.sock` would therefore also have root access on the host. The docker API has no built-in way to set limitations on access, however, you can use a proxy for `docker.sock` via a solution like [our docker socket proxy](https://github.com/linuxserver/docker-socket-proxy), which adds the ability to limit API access to specific endpoints. ### Multiple Hosts >[!NOTE] >Make sure you fully understand what you're doing before you try and set this up as there are lots of ways it can go wrong if you're just guessing. - Modmanager can query & download mods for remote hosts, as well as the one on which it is installed. At a very basic level if you're just using the DOCKER_MODS env and not the docker integration, simply mount the `/modcache` folder on your remote host(s), ensuring it is mapped for all participating containers. + Modmanager can query & download mods for remote hosts, as well as the one on which it is installed. At a very basic level if you're just using the `DOCKER_MODS` env and not the docker integration, simply mount the `/modcache` folder on your remote host(s), ensuring it is mapped for all participating containers. - If you are using the docker integration, our only supported means for connecting to remote hosts is [our socket proxy container](). Run an instance on each remote host: + If you are using the docker integration, our only supported means for connecting to remote hosts is [our socket proxy container](https://github.com/linuxserver/docker-socket-proxy/). Run an instance on each remote host: >[!WARNING] - >DO NOT expose a socket proxy to your LAN that allows any write operations (`POST=1`, `ALLOW_RESTART=1`, etc) or that exposes any more information than is absolutely necessary. NEVER expose a socket proxy to your WAN. + >DO NOT expose a socket proxy to your LAN if it allows any write operations (`POST=1`, `ALLOW_RESTART=1`, etc) or exposes any API elements that are not absolutely necessary. NEVER expose a socket proxy to your WAN. ```yml modmanager-dockerproxy: - image: lscr.io/linuxserver/socket-proxy:latest - container_name: modmanager-dockerproxy - environment: - - CONTAINERS=1 - - POST=0 - volumes: - - /var/run/docker.sock:/var/run/docker.sock:ro - tmpfs: - - /run:exec - ports: - - 2375:2375 - restart: unless-stopped - read_only: true + image: lscr.io/linuxserver/socket-proxy:latest + container_name: modmanager-dockerproxy + environment: + - CONTAINERS=1 + - POST=0 + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + tmpfs: + - /run:exec + ports: + - 2375:2375 + restart: unless-stopped + read_only: true ``` - And then add it to the `DOCKER_MODS_EXTRA_HOSTS` env using the full protocol and port, e.g. + And then add it to the `DOCKER_MODS_EXTRA_HOSTS` env using the full protocol and port, separating multiple servers with a pipe (`\|`), e.g. ```yaml - DOCKER_MODS_EXTRA_HOSTS=tcp://host1.example.com:2375|tcp://host2.example.com:2375|tcp://192.168.0.5:2375 From d7b9d037943d01b077524ecf02cd0526e0925874 Mon Sep 17 00:00:00 2001 From: thespad Date: Sun, 5 Jan 2025 23:10:35 +0000 Subject: [PATCH 09/20] Pipe doesn't need escaping outside of a table --- README.md | 2 +- readme-vars.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e3cf728..6b22fc3 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ If you are using the docker integration, our only supported means for connecting read_only: true ``` -And then add it to the `DOCKER_MODS_EXTRA_HOSTS` env using the full protocol and port, separating multiple servers with a pipe (`\|`), e.g. +And then add it to the `DOCKER_MODS_EXTRA_HOSTS` env using the full protocol and port, separating multiple servers with a pipe (`|`), e.g. ```yaml - DOCKER_MODS_EXTRA_HOSTS=tcp://host1.example.com:2375|tcp://host2.example.com:2375|tcp://192.168.0.5:2375 diff --git a/readme-vars.yml b/readme-vars.yml index acae805..fcbbcf3 100644 --- a/readme-vars.yml +++ b/readme-vars.yml @@ -99,7 +99,7 @@ full_custom_readme: | read_only: true ``` - And then add it to the `DOCKER_MODS_EXTRA_HOSTS` env using the full protocol and port, separating multiple servers with a pipe (`\|`), e.g. + And then add it to the `DOCKER_MODS_EXTRA_HOSTS` env using the full protocol and port, separating multiple servers with a pipe (`|`), e.g. ```yaml - DOCKER_MODS_EXTRA_HOSTS=tcp://host1.example.com:2375|tcp://host2.example.com:2375|tcp://192.168.0.5:2375 From 4b06cea7f0056a48e38eeea352e81173b792b8f4 Mon Sep 17 00:00:00 2001 From: thespad Date: Mon, 6 Jan 2025 20:42:40 +0000 Subject: [PATCH 10/20] Use date to format time properly --- root/etc/s6-overlay/s6-rc.d/init-modmanager-config/run | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/root/etc/s6-overlay/s6-rc.d/init-modmanager-config/run b/root/etc/s6-overlay/s6-rc.d/init-modmanager-config/run index fe28fd1..84b9c64 100755 --- a/root/etc/s6-overlay/s6-rc.d/init-modmanager-config/run +++ b/root/etc/s6-overlay/s6-rc.d/init-modmanager-config/run @@ -15,6 +15,6 @@ else [[ $(date "+%H") -gt 18 && $(date "+%H") -le 23 ]]; NEXT_HOUR=0 fi -echo "[mod-init] Mod updates will run every 6 hours at ${CRON_MINS} minutes past the hour. Next update will be at ${NEXT_HOUR}:${CRON_MINS}." +echo "[mod-init] Mod updates will run every 6 hours at ${CRON_MINS} minutes past the hour. Next update will be at $(date -d${NEXT_HOUR}:${CRON_MINS} '+%H:%m')." /app/update-mods.sh From 475e27002fbfd847ade9b2dd80d3a63433c7e828 Mon Sep 17 00:00:00 2001 From: thespad Date: Tue, 7 Jan 2025 10:29:01 +0000 Subject: [PATCH 11/20] Use consistent language --- README.md | 4 ++-- readme-vars.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6b22fc3..db8359c 100644 --- a/README.md +++ b/README.md @@ -71,9 +71,9 @@ Mapping `docker.sock` is a potential security liability because docker has root >[!NOTE] >Make sure you fully understand what you're doing before you try and set this up as there are lots of ways it can go wrong if you're just guessing. -Modmanager can query & download mods for remote hosts, as well as the one on which it is installed. At a very basic level if you're just using the `DOCKER_MODS` env and not the docker integration, simply mount the `/modcache` folder on your remote host(s), ensuring it is mapped for all participating containers. +Modmanager can query & download mods for remote hosts, as well as the one on which it is installed. At a very basic level if you're just using the `DOCKER_MODS` env and not docker discovery, simply mount the `/modcache` folder on your remote host(s), ensuring it is mapped for all participating containers. -If you are using the docker integration, our only supported means for connecting to remote hosts is [our socket proxy container](https://github.com/linuxserver/docker-socket-proxy/). Run an instance on each remote host: +If you are using docker discovery, our only supported means for connecting to remote hosts is [our socket proxy container](https://github.com/linuxserver/docker-socket-proxy/). Run an instance on each remote host: >[!WARNING] >DO NOT expose a socket proxy to your LAN if it allows any write operations (`POST=1`, `ALLOW_RESTART=1`, etc) or exposes any API elements that are not absolutely necessary. NEVER expose a socket proxy to your WAN. diff --git a/readme-vars.yml b/readme-vars.yml index fcbbcf3..b0c167c 100644 --- a/readme-vars.yml +++ b/readme-vars.yml @@ -75,9 +75,9 @@ full_custom_readme: | >[!NOTE] >Make sure you fully understand what you're doing before you try and set this up as there are lots of ways it can go wrong if you're just guessing. - Modmanager can query & download mods for remote hosts, as well as the one on which it is installed. At a very basic level if you're just using the `DOCKER_MODS` env and not the docker integration, simply mount the `/modcache` folder on your remote host(s), ensuring it is mapped for all participating containers. + Modmanager can query & download mods for remote hosts, as well as the one on which it is installed. At a very basic level if you're just using the `DOCKER_MODS` env and not docker discovery, simply mount the `/modcache` folder on your remote host(s), ensuring it is mapped for all participating containers. - If you are using the docker integration, our only supported means for connecting to remote hosts is [our socket proxy container](https://github.com/linuxserver/docker-socket-proxy/). Run an instance on each remote host: + If you are using docker discovery, our only supported means for connecting to remote hosts is [our socket proxy container](https://github.com/linuxserver/docker-socket-proxy/). Run an instance on each remote host: >[!WARNING] >DO NOT expose a socket proxy to your LAN if it allows any write operations (`POST=1`, `ALLOW_RESTART=1`, etc) or exposes any API elements that are not absolutely necessary. NEVER expose a socket proxy to your WAN. From 0e271350f612f2a64a91d64b5efc9b3d0d0a09b0 Mon Sep 17 00:00:00 2001 From: thespad Date: Wed, 8 Jan 2025 11:43:21 +0000 Subject: [PATCH 12/20] Don't persist DOCKER_MODS between runs --- root/app/update-mods.sh | 4 ++++ root/etc/s6-overlay/s6-rc.d/init-modmanager-config/run | 2 ++ 2 files changed, 6 insertions(+) diff --git a/root/app/update-mods.sh b/root/app/update-mods.sh index b7bc2ab..dc5987f 100755 --- a/root/app/update-mods.sh +++ b/root/app/update-mods.sh @@ -35,6 +35,10 @@ find_docker_mods() { } # Main script loop + +# Reset DOCKER_MODS to whatever value the user passed into the container at creation time +DOCKER_MODS="${DOCKER_MODS_STATIC}" + if [[ -e "/var/run/docker.sock" ]] || [[ -n "${DOCKER_HOST}" ]]; then find_docker_mods "${DOCKER_HOST:-docker.sock}" "default" fi diff --git a/root/etc/s6-overlay/s6-rc.d/init-modmanager-config/run b/root/etc/s6-overlay/s6-rc.d/init-modmanager-config/run index 84b9c64..33989a1 100755 --- a/root/etc/s6-overlay/s6-rc.d/init-modmanager-config/run +++ b/root/etc/s6-overlay/s6-rc.d/init-modmanager-config/run @@ -17,4 +17,6 @@ fi echo "[mod-init] Mod updates will run every 6 hours at ${CRON_MINS} minutes past the hour. Next update will be at $(date -d${NEXT_HOUR}:${CRON_MINS} '+%H:%m')." +printf %s "${DOCKER_MODS}" > /run/s6/container_environment/DOCKER_MODS_STATIC + /app/update-mods.sh From 95bad6ae2d38d4caa48516c0c17250b6a99f9642 Mon Sep 17 00:00:00 2001 From: thespad Date: Wed, 8 Jan 2025 12:05:17 +0000 Subject: [PATCH 13/20] Improve time check --- .../s6-rc.d/init-modmanager-config/run | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/root/etc/s6-overlay/s6-rc.d/init-modmanager-config/run b/root/etc/s6-overlay/s6-rc.d/init-modmanager-config/run index 33989a1..b27a4c2 100755 --- a/root/etc/s6-overlay/s6-rc.d/init-modmanager-config/run +++ b/root/etc/s6-overlay/s6-rc.d/init-modmanager-config/run @@ -5,13 +5,21 @@ CRON_MINS=$((0 + RANDOM % 59)) sed -i "s/@@MINUTES@@/${CRON_MINS}/" /etc/crontabs/root -if [[ $(date "+%H") -gt 0 && $(date "+%H") -lt 6 ]]; then +if [[ $(date "+%H") == 0 && $(date "+%m") -lt ${CRON_MINS} ]]; then + NEXT_HOUR=0 +elif [[ $(date "+%H") == 6 && $(date "+%m") -lt ${CRON_MINS} ]]; then + NEXT_HOUR=6 +elif [[ $(date "+%H") == 12 && $(date "+%m") -lt ${CRON_MINS} ]]; then + NEXT_HOUR=12 +elif [[ $(date "+%H") == 18 && $(date "+%m") -le ${CRON_MINS} ]]; then + NEXT_HOUR=18 +elif [[ $(date "+%H") -ge 0 && $(date "+%H") -lt 6 ]]; then NEXT_HOUR=6 -elif [[ $(date "+%H") -gt 6 && $(date "+%H") -lt 12 ]]; then +elif [[ $(date "+%H") -ge 6 && $(date "+%H") -lt 12 ]]; then NEXT_HOUR=12 -elif [[ $(date "+%H") -gt 12 && $(date "+%H") -lt 18 ]]; then +elif [[ $(date "+%H") -ge 12 && $(date "+%H") -lt 18 ]]; then NEXT_HOUR=18 -else [[ $(date "+%H") -gt 18 && $(date "+%H") -le 23 ]]; +elif [[ $(date "+%H") -ge 18 && $(date "+%H") -le 23 ]]; then NEXT_HOUR=0 fi From 220ecd28f3c92ad87ac3a53914d45dfd3457cd07 Mon Sep 17 00:00:00 2001 From: thespad Date: Wed, 8 Jan 2025 12:07:14 +0000 Subject: [PATCH 14/20] Correct comparisons --- root/etc/s6-overlay/s6-rc.d/init-modmanager-config/run | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/root/etc/s6-overlay/s6-rc.d/init-modmanager-config/run b/root/etc/s6-overlay/s6-rc.d/init-modmanager-config/run index b27a4c2..622dc47 100755 --- a/root/etc/s6-overlay/s6-rc.d/init-modmanager-config/run +++ b/root/etc/s6-overlay/s6-rc.d/init-modmanager-config/run @@ -11,13 +11,13 @@ elif [[ $(date "+%H") == 6 && $(date "+%m") -lt ${CRON_MINS} ]]; then NEXT_HOUR=6 elif [[ $(date "+%H") == 12 && $(date "+%m") -lt ${CRON_MINS} ]]; then NEXT_HOUR=12 -elif [[ $(date "+%H") == 18 && $(date "+%m") -le ${CRON_MINS} ]]; then +elif [[ $(date "+%H") == 18 && $(date "+%m") -lt ${CRON_MINS} ]]; then NEXT_HOUR=18 -elif [[ $(date "+%H") -ge 0 && $(date "+%H") -lt 6 ]]; then +elif [[ $(date "+%H") -ge 0 && $(date "+%H") -le 5 ]]; then NEXT_HOUR=6 -elif [[ $(date "+%H") -ge 6 && $(date "+%H") -lt 12 ]]; then +elif [[ $(date "+%H") -ge 6 && $(date "+%H") -le 11 ]]; then NEXT_HOUR=12 -elif [[ $(date "+%H") -ge 12 && $(date "+%H") -lt 18 ]]; then +elif [[ $(date "+%H") -ge 12 && $(date "+%H") -le 17 ]]; then NEXT_HOUR=18 elif [[ $(date "+%H") -ge 18 && $(date "+%H") -le 23 ]]; then NEXT_HOUR=0 From ce501e66723214b6c0de485f3f86f693c7bfded4 Mon Sep 17 00:00:00 2001 From: thespad Date: Thu, 9 Jan 2025 09:18:32 +0000 Subject: [PATCH 15/20] Delineate new runs in logs --- root/app/update-mods.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/root/app/update-mods.sh b/root/app/update-mods.sh index dc5987f..f53ebec 100755 --- a/root/app/update-mods.sh +++ b/root/app/update-mods.sh @@ -39,6 +39,9 @@ find_docker_mods() { # Reset DOCKER_MODS to whatever value the user passed into the container at creation time DOCKER_MODS="${DOCKER_MODS_STATIC}" +echo -e "" +echo -e "[mod-init] Running check for new mods and updates." + if [[ -e "/var/run/docker.sock" ]] || [[ -n "${DOCKER_HOST}" ]]; then find_docker_mods "${DOCKER_HOST:-docker.sock}" "default" fi From 777322b2a1420bda47bf4cc9af8ee2488febf165 Mon Sep 17 00:00:00 2001 From: thespad Date: Thu, 9 Jan 2025 11:47:59 +0000 Subject: [PATCH 16/20] Strip leading zeroes --- .../s6-rc.d/init-modmanager-config/run | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/root/etc/s6-overlay/s6-rc.d/init-modmanager-config/run b/root/etc/s6-overlay/s6-rc.d/init-modmanager-config/run index 622dc47..4fd3c90 100755 --- a/root/etc/s6-overlay/s6-rc.d/init-modmanager-config/run +++ b/root/etc/s6-overlay/s6-rc.d/init-modmanager-config/run @@ -5,21 +5,21 @@ CRON_MINS=$((0 + RANDOM % 59)) sed -i "s/@@MINUTES@@/${CRON_MINS}/" /etc/crontabs/root -if [[ $(date "+%H") == 0 && $(date "+%m") -lt ${CRON_MINS} ]]; then +if [[ $(date "+%-H") == 0 && $(date "+%-m") -lt ${CRON_MINS} ]]; then NEXT_HOUR=0 -elif [[ $(date "+%H") == 6 && $(date "+%m") -lt ${CRON_MINS} ]]; then +elif [[ $(date "+%-H") == 6 && $(date "+%-m") -lt ${CRON_MINS} ]]; then NEXT_HOUR=6 -elif [[ $(date "+%H") == 12 && $(date "+%m") -lt ${CRON_MINS} ]]; then +elif [[ $(date "+%-H") == 12 && $(date "+%-m") -lt ${CRON_MINS} ]]; then NEXT_HOUR=12 -elif [[ $(date "+%H") == 18 && $(date "+%m") -lt ${CRON_MINS} ]]; then +elif [[ $(date "+%-H") == 18 && $(date "+%-m") -lt ${CRON_MINS} ]]; then NEXT_HOUR=18 -elif [[ $(date "+%H") -ge 0 && $(date "+%H") -le 5 ]]; then +elif [[ $(date "+%-H") -ge 0 && $(date "+%-H") -le 5 ]]; then NEXT_HOUR=6 -elif [[ $(date "+%H") -ge 6 && $(date "+%H") -le 11 ]]; then +elif [[ $(date "+%-H") -ge 6 && $(date "+%-H") -le 11 ]]; then NEXT_HOUR=12 -elif [[ $(date "+%H") -ge 12 && $(date "+%H") -le 17 ]]; then +elif [[ $(date "+%-H") -ge 12 && $(date "+%-H") -le 17 ]]; then NEXT_HOUR=18 -elif [[ $(date "+%H") -ge 18 && $(date "+%H") -le 23 ]]; then +elif [[ $(date "+%-H") -ge 18 && $(date "+%-H") -le 23 ]]; then NEXT_HOUR=0 fi From 5a5f4cdada89c89f0770893d0f262331a744f3a4 Mon Sep 17 00:00:00 2001 From: thespad Date: Thu, 9 Jan 2025 18:03:00 +0000 Subject: [PATCH 17/20] Log if no mods are found in a context --- root/app/update-mods.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/root/app/update-mods.sh b/root/app/update-mods.sh index f53ebec..f32eada 100755 --- a/root/app/update-mods.sh +++ b/root/app/update-mods.sh @@ -4,7 +4,7 @@ find_docker_mods() { # Mods provided via Docker if [[ "${2}" != "default" ]]; then - MOD_STATE="(${2})" + local MOD_STATE="(${2})" docker context create "${2}" --docker "host=${1}" >/dev/null 2>&1 fi docker --context "${2}" ps -q >/dev/null 2>&1 || local DOCKER_MOD_CONTEXT_FAIL=true @@ -27,6 +27,8 @@ find_docker_mods() { DOCKER_MODS="${DOCKER_MODS#|}" fi done + else + echo -e "[mod-init] ${MOD_STATE:+${MOD_STATE} }No mods found in the ${2} context" fi done if [[ "${2}" != "default" ]]; then From 02cb08c389b2f08024735b42661d1939818b2ced Mon Sep 17 00:00:00 2001 From: thespad Date: Thu, 9 Jan 2025 20:40:55 +0000 Subject: [PATCH 18/20] Add support notice, clarify DOCKER_MODS env --- README.md | 4 +++- readme-vars.yml | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index db8359c..14c0082 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ The architectures supported by this image are: ## Application Setup -You can specify mods to download via the `DOCKER_MODS` environment variable like any other container, or allow discovery through docker by mounting the docker socket into the container (or configuring a suitable alternative endpoint via the built-in `DOCKER_HOST` environment variable). +You can specify mods to download via the `DOCKER_MODS` environment variable like any other container, or allow discovery through docker by mounting the docker socket into the container (or configuring a suitable alternative endpoint via the built-in `DOCKER_HOST` environment variable). Whichever option you choose the appropriate `DOCKER_MODS` environment variable must still be present on the containers that need to install them. The Modmanager container will download all needed mods on startup and then check for updates every 6 hours; if you're using docker discovery it will automatically pick up any new mods. @@ -62,6 +62,8 @@ If a mod requires additional packages to be installed, each container will still Note that the Modmanager container itself does not support applying mods *or* custom files/services. +**Modmanager is only supported for use with Linuxserver images built after 2025-01-01, while it may work with 3rd party containers using our images as a base we will not provide support for them.** + ### Security considerations Mapping `docker.sock` is a potential security liability because docker has root access on the host and any process that has full access to `docker.sock` would therefore also have root access on the host. The docker API has no built-in way to set limitations on access, however, you can use a proxy for `docker.sock` via a solution like [our docker socket proxy](https://github.com/linuxserver/docker-socket-proxy), which adds the ability to limit API access to specific endpoints. diff --git a/readme-vars.yml b/readme-vars.yml index b0c167c..0c94283 100644 --- a/readme-vars.yml +++ b/readme-vars.yml @@ -56,7 +56,7 @@ full_custom_readme: | ## Application Setup - You can specify mods to download via the `DOCKER_MODS` environment variable like any other container, or allow discovery through docker by mounting the docker socket into the container (or configuring a suitable alternative endpoint via the built-in `DOCKER_HOST` environment variable). + You can specify mods to download via the `DOCKER_MODS` environment variable like any other container, or allow discovery through docker by mounting the docker socket into the container (or configuring a suitable alternative endpoint via the built-in `DOCKER_HOST` environment variable). Whichever option you choose the appropriate `DOCKER_MODS` environment variable must still be present on the containers that need to install them. The Modmanager container will download all needed mods on startup and then check for updates every 6 hours; if you're using docker discovery it will automatically pick up any new mods. @@ -66,6 +66,8 @@ full_custom_readme: | Note that the Modmanager container itself does not support applying mods *or* custom files/services. + **Modmanager is only supported for use with Linuxserver images built after 2025-01-01, while it may work with 3rd party containers using our images as a base we will not provide support for them.** + ### Security considerations Mapping `docker.sock` is a potential security liability because docker has root access on the host and any process that has full access to `docker.sock` would therefore also have root access on the host. The docker API has no built-in way to set limitations on access, however, you can use a proxy for `docker.sock` via a solution like [our docker socket proxy](https://github.com/linuxserver/docker-socket-proxy), which adds the ability to limit API access to specific endpoints. From 49be79923df7e80bcf77cc57fda8970f0dc128f1 Mon Sep 17 00:00:00 2001 From: thespad Date: Thu, 9 Jan 2025 22:47:55 +0000 Subject: [PATCH 19/20] Don't spam logs --- root/app/update-mods.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/root/app/update-mods.sh b/root/app/update-mods.sh index f32eada..0bf2dc6 100755 --- a/root/app/update-mods.sh +++ b/root/app/update-mods.sh @@ -27,8 +27,6 @@ find_docker_mods() { DOCKER_MODS="${DOCKER_MODS#|}" fi done - else - echo -e "[mod-init] ${MOD_STATE:+${MOD_STATE} }No mods found in the ${2} context" fi done if [[ "${2}" != "default" ]]; then From 13607015a69e59ce3749599a8b60a05779fae9aa Mon Sep 17 00:00:00 2001 From: thespad Date: Thu, 9 Jan 2025 23:14:01 +0000 Subject: [PATCH 20/20] Try using minutes instead of months --- root/etc/s6-overlay/s6-rc.d/init-modmanager-config/run | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/root/etc/s6-overlay/s6-rc.d/init-modmanager-config/run b/root/etc/s6-overlay/s6-rc.d/init-modmanager-config/run index 4fd3c90..276b6b2 100755 --- a/root/etc/s6-overlay/s6-rc.d/init-modmanager-config/run +++ b/root/etc/s6-overlay/s6-rc.d/init-modmanager-config/run @@ -5,13 +5,13 @@ CRON_MINS=$((0 + RANDOM % 59)) sed -i "s/@@MINUTES@@/${CRON_MINS}/" /etc/crontabs/root -if [[ $(date "+%-H") == 0 && $(date "+%-m") -lt ${CRON_MINS} ]]; then +if [[ $(date "+%-H") == 0 && $(date "+%-M") -lt ${CRON_MINS} ]]; then NEXT_HOUR=0 -elif [[ $(date "+%-H") == 6 && $(date "+%-m") -lt ${CRON_MINS} ]]; then +elif [[ $(date "+%-H") == 6 && $(date "+%-M") -lt ${CRON_MINS} ]]; then NEXT_HOUR=6 -elif [[ $(date "+%-H") == 12 && $(date "+%-m") -lt ${CRON_MINS} ]]; then +elif [[ $(date "+%-H") == 12 && $(date "+%-M") -lt ${CRON_MINS} ]]; then NEXT_HOUR=12 -elif [[ $(date "+%-H") == 18 && $(date "+%-m") -lt ${CRON_MINS} ]]; then +elif [[ $(date "+%-H") == 18 && $(date "+%-M") -lt ${CRON_MINS} ]]; then NEXT_HOUR=18 elif [[ $(date "+%-H") -ge 0 && $(date "+%-H") -le 5 ]]; then NEXT_HOUR=6 @@ -23,7 +23,7 @@ elif [[ $(date "+%-H") -ge 18 && $(date "+%-H") -le 23 ]]; then NEXT_HOUR=0 fi -echo "[mod-init] Mod updates will run every 6 hours at ${CRON_MINS} minutes past the hour. Next update will be at $(date -d${NEXT_HOUR}:${CRON_MINS} '+%H:%m')." +echo "[mod-init] Mod updates will run every 6 hours at ${CRON_MINS} minutes past the hour. Next update will be at $(date -d${NEXT_HOUR}:${CRON_MINS} '+%H:%M')." printf %s "${DOCKER_MODS}" > /run/s6/container_environment/DOCKER_MODS_STATIC