diff --git a/.github/workflows/external_trigger.yml b/.github/workflows/external_trigger.yml index a38aae4..e007939 100644 --- a/.github/workflows/external_trigger.yml +++ b/.github/workflows/external_trigger.yml @@ -20,7 +20,8 @@ jobs: echo "**** External trigger running off of main branch. To disable this trigger, set a Github secret named \"PAUSE_EXTERNAL_TRIGGER_SOCKET_PROXY_MAIN\". ****" echo "External trigger running off of main branch. To disable this trigger, set a Github secret named \`PAUSE_EXTERNAL_TRIGGER_SOCKET_PROXY_MAIN\`" >> $GITHUB_STEP_SUMMARY echo "**** Retrieving external version ****" - EXT_RELEASE=$(docker run --rm quay.io/skopeo/stable:v1 inspect docker://docker.io/haproxy:lts-alpine | jq -r '.Env[] | select(startswith("HAPROXY_VERSION")) | split("=")[1]') + EXT_RELEASE=$(curl -sL "http://dl-cdn.alpinelinux.org/alpine/v3.19/main/x86_64/APKINDEX.tar.gz" | tar -xz -C /tmp \ + && awk '/^P:'"nginx"'$/,/V:/' /tmp/APKINDEX | sed -n 2p | sed 's/^V://') if [ -z "${EXT_RELEASE}" ] || [ "${EXT_RELEASE}" == "null" ]; then echo "**** Can't retrieve external version, exiting ****" FAILURE_REASON="Can't retrieve external version for socket-proxy branch main" @@ -73,6 +74,14 @@ jobs: echo "**** Version ${EXT_RELEASE} already pushed, exiting ****" echo "Version ${EXT_RELEASE} already pushed, exiting" >> $GITHUB_STEP_SUMMARY exit 0 + elif [[ $(curl -sL "http://dl-cdn.alpinelinux.org/alpine/v3.19/main/aarch64/APKINDEX.tar.gz" | tar -xz -C /tmp && awk '/^P:'"nginx"'$/,/V:/' /tmp/APKINDEX | sed -n 2p | sed 's/^V://') != "${EXT_RELEASE}" ]]; then + echo "**** New version ${EXT_RELEASE} found; but not all arch repos updated yet; exiting ****" + echo "New version ${EXT_RELEASE} found; but not all arch repos updated yet; exiting" >> $GITHUB_STEP_SUMMARY + FAILURE_REASON="New version ${EXT_RELEASE} for socket-proxy tag latest is detected, however not all arch repos are updated yet. Will try again later." + curl -X POST -H "Content-Type: application/json" --data '{"avatar_url": "https://cdn.discordapp.com/avatars/354986384542662657/df91181b3f1cf0ef1592fbe18e0962d7.png","embeds": [{"color": 9802903, + "description": "**Trigger Failed** \n**Reason:** '"${FAILURE_REASON}"' \n"}], + "username": "Github Actions"}' ${{ secrets.DISCORD_WEBHOOK }} + exit 0 elif [ $(curl -s https://ci.linuxserver.io/job/Docker-Pipeline-Builders/job/docker-socket-proxy/job/main/lastBuild/api/json | jq -r '.building') == "true" ]; then echo "**** New version ${EXT_RELEASE} found; but there already seems to be an active build on Jenkins; exiting ****" echo "New version ${EXT_RELEASE} found; but there already seems to be an active build on Jenkins; exiting" >> $GITHUB_STEP_SUMMARY diff --git a/Dockerfile b/Dockerfile index 632a8f2..5933d3d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,12 +1,11 @@ # syntax=docker/dockerfile:1 -ARG HAPROXY_VERSION - -FROM haproxy:${HAPROXY_VERSION:-lts}-alpine +FROM docker.io/alpine:3.19 # set version label ARG BUILD_DATE ARG VERSION +ARG NGINX_VERSION LABEL build_version="Linuxserver.io version:- ${VERSION} Build-date:- ${BUILD_DATE}" LABEL maintainer="thespad" @@ -18,13 +17,11 @@ ENV ALLOW_RESTARTS=0 \ COMMIT=0 \ CONFIGS=0 \ CONTAINERS=0 \ - DISABLE_IPV6=0 \ DISTRIBUTION=0 \ EVENTS=1 \ EXEC=0 \ IMAGES=0 \ INFO=0 \ - LOG_LEVEL=info \ NETWORKS=0 \ NODES=0 \ PING=1 \ @@ -40,8 +37,26 @@ ENV ALLOW_RESTARTS=0 \ VERSION=1 \ VOLUMES=0 -USER root +# install packages +RUN \ + echo "**** install build packages ****" && \ + apk add --no-cache \ + alpine-release \ + bash \ + curl \ + envsubst && \ + if [ -z ${NGINX_VERSION+x} ]; then \ + NGINX_VERSION=$(curl -sL "http://dl-cdn.alpinelinux.org/alpine/v3.19/main/x86_64/APKINDEX.tar.gz" | tar -xz -C /tmp \ + && awk '/^P:nginx$/,/V:/' /tmp/APKINDEX | sed -n 2p | sed 's/^V://'); \ + fi && \ + apk add --no-cache \ + nginx==${NGINX_VERSION} && \ + rm -f /etc/nginx/conf.d/stream.conf && \ + rm -f /etc/nginx/http.d/default.conf -COPY haproxy.cfg /usr/local/etc/haproxy/haproxy.cfg +# add local files +COPY root/ / EXPOSE 2375 + +ENTRYPOINT ["/docker-entrypoint.sh"] diff --git a/Dockerfile.aarch64 b/Dockerfile.aarch64 index 632a8f2..5933d3d 100644 --- a/Dockerfile.aarch64 +++ b/Dockerfile.aarch64 @@ -1,12 +1,11 @@ # syntax=docker/dockerfile:1 -ARG HAPROXY_VERSION - -FROM haproxy:${HAPROXY_VERSION:-lts}-alpine +FROM docker.io/alpine:3.19 # set version label ARG BUILD_DATE ARG VERSION +ARG NGINX_VERSION LABEL build_version="Linuxserver.io version:- ${VERSION} Build-date:- ${BUILD_DATE}" LABEL maintainer="thespad" @@ -18,13 +17,11 @@ ENV ALLOW_RESTARTS=0 \ COMMIT=0 \ CONFIGS=0 \ CONTAINERS=0 \ - DISABLE_IPV6=0 \ DISTRIBUTION=0 \ EVENTS=1 \ EXEC=0 \ IMAGES=0 \ INFO=0 \ - LOG_LEVEL=info \ NETWORKS=0 \ NODES=0 \ PING=1 \ @@ -40,8 +37,26 @@ ENV ALLOW_RESTARTS=0 \ VERSION=1 \ VOLUMES=0 -USER root +# install packages +RUN \ + echo "**** install build packages ****" && \ + apk add --no-cache \ + alpine-release \ + bash \ + curl \ + envsubst && \ + if [ -z ${NGINX_VERSION+x} ]; then \ + NGINX_VERSION=$(curl -sL "http://dl-cdn.alpinelinux.org/alpine/v3.19/main/x86_64/APKINDEX.tar.gz" | tar -xz -C /tmp \ + && awk '/^P:nginx$/,/V:/' /tmp/APKINDEX | sed -n 2p | sed 's/^V://'); \ + fi && \ + apk add --no-cache \ + nginx==${NGINX_VERSION} && \ + rm -f /etc/nginx/conf.d/stream.conf && \ + rm -f /etc/nginx/http.d/default.conf -COPY haproxy.cfg /usr/local/etc/haproxy/haproxy.cfg +# add local files +COPY root/ / EXPOSE 2375 + +ENTRYPOINT ["/docker-entrypoint.sh"] diff --git a/Jenkinsfile b/Jenkinsfile index 3cf5703..d5b1a44 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -17,7 +17,7 @@ pipeline { GITLAB_TOKEN=credentials('b6f0f1dd-6952-4cf6-95d1-9c06380283f0') GITLAB_NAMESPACE=credentials('gitlab-namespace-id') DOCKERHUB_TOKEN=credentials('docker-hub-ci-pat') - BUILD_VERSION_ARG = 'HAPROXY_VERSION' + BUILD_VERSION_ARG = 'NGINX_VERSION' LS_USER = 'linuxserver' LS_REPO = 'docker-socket-proxy' CONTAINER_NAME = 'socket-proxy' @@ -25,6 +25,9 @@ pipeline { DEV_DOCKERHUB_IMAGE = 'lsiodev/socket-proxy' PR_DOCKERHUB_IMAGE = 'lspipepr/socket-proxy' DIST_IMAGE = 'alpine' + DIST_TAG = '3.19' + DIST_REPO = 'http://dl-cdn.alpinelinux.org/alpine/v3.19/main/' + DIST_REPO_PACKAGES = 'nginx' MULTIARCH='true' CI='false' CI_WEB='false' @@ -110,14 +113,15 @@ pipeline { /* ######################## External Release Tagging ######################## */ - // If this is a custom command to determine version use that command - stage("Set tag custom bash"){ + // If this is an alpine repo change for external version determine an md5 from the version string + stage("Set tag Alpine Repo"){ steps{ script{ env.EXT_RELEASE = sh( - script: ''' docker run --rm quay.io/skopeo/stable:v1 inspect docker://docker.io/haproxy:lts-alpine | jq -r '.Env[] | select(startswith("HAPROXY_VERSION")) | split("=")[1]' ''', + script: '''curl -sL "${DIST_REPO}x86_64/APKINDEX.tar.gz" | tar -xz -C /tmp \ + && awk '/^P:'"${DIST_REPO_PACKAGES}"'$/,/V:/' /tmp/APKINDEX | sed -n 2p | sed 's/^V://' ''', returnStdout: true).trim() - env.RELEASE_LINK = 'custom_command' + env.RELEASE_LINK = 'alpine_repo' } } } @@ -837,11 +841,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 + echo "Updating external repo packages to ${EXT_RELEASE_CLEAN}" > releasebody.json echo '{"tag_name":"'${META_TAG}'",\ "target_commitish": "main",\ "name": "'${META_TAG}'",\ - "body": "**LinuxServer Changes:**\\n\\n'${LS_RELEASE_NOTES}'\\n\\n**Remote Changes:**\\n\\n' > start + "body": "**LinuxServer Changes:**\\n\\n'${LS_RELEASE_NOTES}'\\n\\n**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 b155d62..ed426c5 100644 --- a/README.md +++ b/README.md @@ -32,9 +32,9 @@ Find us at: [![Docker Stars](https://img.shields.io/docker/stars/linuxserver/socket-proxy.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&label=stars&logo=docker)](https://hub.docker.com/r/linuxserver/socket-proxy) [![Jenkins Build](https://img.shields.io/jenkins/build?labelColor=555555&logoColor=ffffff&style=for-the-badge&jobUrl=https%3A%2F%2Fci.linuxserver.io%2Fjob%2FDocker-Pipeline-Builders%2Fjob%2Fdocker-socket-proxy%2Fjob%2Fmain%2F&logo=jenkins)](https://ci.linuxserver.io/job/Docker-Pipeline-Builders/job/docker-socket-proxy/job/main/) -[Socket-proxy](https://github.com/Tecnativa/docker-socket-proxy) is a security-enhanced proxy for the Docker Socket. +Socket proxy is a security-enhanced proxy for the Docker Socket. -[![socket-proxy](https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/docker-logo.png)](https://github.com/Tecnativa/docker-socket-proxy) +![socket-proxy](https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/docker-logo.png) ## Supported Architectures @@ -52,9 +52,9 @@ The architectures supported by this image are: ## Application Setup -This container is a fork of [https://github.com/Tecnativa/docker-socket-proxy](https://github.com/Tecnativa/docker-socket-proxy) and as such does not follow our usual container conventions. It *does not* support mods or custom scripts/services, or running as a user other than root (or the docker user in a rootless environment). +This container is based on [https://github.com/Tecnativa/docker-socket-proxy](https://github.com/Tecnativa/docker-socket-proxy) and as such does not follow our usual container conventions. It *does not* support mods or custom scripts/services, or running as a user other than root (or the docker user in a rootless environment). -The container should be run on the same docker network as the service(s) using it. Most containers that would normally connect to a mounted docker.sock can have their endpoint overridden using the `DOCKER_HOST` environment variable if they do not offer the option in their configuration; it should typically be pointed to tcp://socket-proxy:2375. +The container should be run on the same docker network as the service(s) using it. Most containers that would normally connect to a mounted docker.sock can have their endpoint overridden using the `DOCKER_HOST` environment variable if they do not offer the option in their configuration; it should typically be pointed to `tcp://socket-proxy:2375`. * Never expose this container's port to a public network. It should be treated the same way you would treat the docker socket or TCP endpoint. * Revoke access to any API section that you consider your service should not need. @@ -74,34 +74,32 @@ services: image: lscr.io/linuxserver/socket-proxy:latest container_name: socket-proxy environment: - - EVENTS=1 #optional - - PING=1 #optional - - VERSION=1 #optional + - ALLOW_START=0 #optional + - ALLOW_STOP=0 #optional + - ALLOW_RESTARTS=0 #optional - AUTH=0 #optional - - SECRETS=0 #optional - - POST=0 #optional - BUILD=0 #optional - COMMIT=0 #optional - CONFIGS=0 #optional - CONTAINERS=0 #optional - - ALLOW_START=0 #optional - - ALLOW_STOP=0 #optional - - ALLOW_RESTARTS=0 #optional - DISTRIBUTION=0 #optional + - EVENTS=1 #optional - EXEC=0 #optional - IMAGES=0 #optional - INFO=0 #optional - - LOG_LEVEL=info #optional - NETWORKS=0 #optional - NODES=0 #optional + - PING=1 #optional + - POST=0 #optional - PLUGINS=0 #optional + - SECRETS=0 #optional - SERVICES=0 #optional - SESSION=0 #optional - SWARM=0 #optional - SYSTEM=0 #optional - TASKS=0 #optional + - VERSION=1 #optional - VOLUMES=0 #optional - - DISABLE_IPV6=0 #optional volumes: - /var/run/docker.sock:/var/run/docker.sock:ro restart: unless-stopped @@ -115,34 +113,32 @@ services: ```bash docker run -d \ --name=socket-proxy \ - -e EVENTS=1 `#optional` \ - -e PING=1 `#optional` \ - -e VERSION=1 `#optional` \ + -e ALLOW_START=0 `#optional` \ + -e ALLOW_STOP=0 `#optional` \ + -e ALLOW_RESTARTS=0 `#optional` \ -e AUTH=0 `#optional` \ - -e SECRETS=0 `#optional` \ - -e POST=0 `#optional` \ -e BUILD=0 `#optional` \ -e COMMIT=0 `#optional` \ -e CONFIGS=0 `#optional` \ -e CONTAINERS=0 `#optional` \ - -e ALLOW_START=0 `#optional` \ - -e ALLOW_STOP=0 `#optional` \ - -e ALLOW_RESTARTS=0 `#optional` \ -e DISTRIBUTION=0 `#optional` \ + -e EVENTS=1 `#optional` \ -e EXEC=0 `#optional` \ -e IMAGES=0 `#optional` \ -e INFO=0 `#optional` \ - -e LOG_LEVEL=info `#optional` \ -e NETWORKS=0 `#optional` \ -e NODES=0 `#optional` \ + -e PING=1 `#optional` \ + -e POST=0 `#optional` \ -e PLUGINS=0 `#optional` \ + -e SECRETS=0 `#optional` \ -e SERVICES=0 `#optional` \ -e SESSION=0 `#optional` \ -e SWARM=0 `#optional` \ -e SYSTEM=0 `#optional` \ -e TASKS=0 `#optional` \ + -e VERSION=1 `#optional` \ -e VOLUMES=0 `#optional` \ - -e DISABLE_IPV6=0 `#optional` \ -v /var/run/docker.sock:/var/run/docker.sock:ro \ --restart unless-stopped \ --read-only \ @@ -156,34 +152,32 @@ Containers are configured using parameters passed at runtime (such as those abov | Parameter | Function | | :----: | --- | -| `-e EVENTS=1` | `/events` | -| `-e PING=1` | `/_ping` | -| `-e VERSION=1` | `/version` | +| `-e ALLOW_START=0` | `/containers/id/start` | +| `-e ALLOW_STOP=0` | `/containers/id/stop` | +| `-e ALLOW_RESTARTS=0` | `/containers/id/stop`, `/containers/id/restart`, and `/containers/id/kill` | | `-e AUTH=0` | `/auth` | -| `-e SECRETS=0` | `/secrets` | -| `-e POST=0` | When set to `0`, only `GET` and `HEAD` operations are allowed, making API access read-only. | | `-e BUILD=0` | `/build` | | `-e COMMIT=0` | `/commit` | | `-e CONFIGS=0` | `/configs` | | `-e CONTAINERS=0` | `/containers` | -| `-e ALLOW_START=0` | `/containers/id/start` | -| `-e ALLOW_STOP=0` | `/containers/id/stop` | -| `-e ALLOW_RESTARTS=0` | `/containers/id/stop`, `/containers/id/restart`, and `/containers/id/kill` | | `-e DISTRIBUTION=0` | `/distribution` | +| `-e EVENTS=1` | `/events` | | `-e EXEC=0` | `/exec` & `/containers/{id}/exec` | | `-e IMAGES=0` | `/images` | | `-e INFO=0` | `/info` | -| `-e LOG_LEVEL=info` | Default value is `info`. Possible values are: `debug`, `info`, `notice`, `warning`, `err`, `crit`, `alert`, and `emerg`. | | `-e NETWORKS=0` | `/networks` | | `-e NODES=0` | `/nodes` | +| `-e PING=1` | `/_ping` | | `-e PLUGINS=0` | `/plugins` | +| `-e POST=0` | When set to `0`, only `GET` and `HEAD` operations are allowed, making API access read-only. | +| `-e SECRETS=0` | `/secrets` | | `-e SERVICES=0` | `/services` | | `-e SESSION=0` | `/session` | | `-e SWARM=0` | `/swarm` | | `-e SYSTEM=0` | `/system` | | `-e TASKS=0` | `/tasks` | +| `-e VERSION=1` | `/version` | | `-e VOLUMES=0` | `/volumes` | -| `-e DISABLE_IPV6=0` | Set to `1` to disable IPv6 bindings in scenarios where the host cannot support it. | | `-v /var/run/docker.sock:ro` | Mount the host docker socket into the container. | | `--read-only` | Make the container filesystem read-only. | | `--tmpfs /run` | Mount /run to tmpfs (RAM) to make it writeable. | @@ -307,4 +301,5 @@ Once registered you can define the dockerfile to use with `-f Dockerfile.aarch64 ## Versions +* **08.04.24:** - Use nginx due to haproxy's wonky websockets handling. * **07.04.24:** - Initial Release. diff --git a/haproxy.cfg b/haproxy.cfg deleted file mode 100644 index c61e908..0000000 --- a/haproxy.cfg +++ /dev/null @@ -1,72 +0,0 @@ -global - log stdout format raw daemon "${LOG_LEVEL}" - maxconn 4000 - -defaults - mode http - log global - option httplog - option dontlognull - option http-server-close - option redispatch - retries 3 - timeout http-request 10s - timeout queue 1m - timeout connect 10s - timeout client 10m - timeout server 10m - timeout http-keep-alive 10s - timeout check 10s - maxconn 3000 - - # Use provided example error pages - errorfile 400 /usr/local/etc/haproxy/errors/400.http - errorfile 403 /usr/local/etc/haproxy/errors/403.http - errorfile 408 /usr/local/etc/haproxy/errors/408.http - errorfile 500 /usr/local/etc/haproxy/errors/500.http - errorfile 502 /usr/local/etc/haproxy/errors/502.http - errorfile 503 /usr/local/etc/haproxy/errors/503.http - errorfile 504 /usr/local/etc/haproxy/errors/504.http - -backend dockerbackend - server dockersocket $SOCKET_PATH - -backend docker-events - server dockersocket $SOCKET_PATH - -frontend dockerfrontend - .if streq("$DISABLE_IPV6",1) - bind :2375 - .else - bind [::]:2375 v4v6 - .endif - http-request deny unless METH_GET || { env(POST) -m bool } - http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/containers/[a-zA-Z0-9_.-]+/((stop)|(restart)|(kill)) } { env(ALLOW_RESTARTS) -m bool } - http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/containers/[a-zA-Z0-9_.-]+/start } { env(ALLOW_START) -m bool } - http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/containers/[a-zA-Z0-9_.-]+/stop } { env(ALLOW_STOP) -m bool } - http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/auth } { env(AUTH) -m bool } - http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/build } { env(BUILD) -m bool } - http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/commit } { env(COMMIT) -m bool } - http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/configs } { env(CONFIGS) -m bool } - http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/containers } { env(CONTAINERS) -m bool } - http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/distribution } { env(DISTRIBUTION) -m bool } - http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/events } { env(EVENTS) -m bool } - http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/exec } { env(EXEC) -m bool } - http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/images } { env(IMAGES) -m bool } - http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/info } { env(INFO) -m bool } - http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/networks } { env(NETWORKS) -m bool } - http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/nodes } { env(NODES) -m bool } - http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/_ping } { env(PING) -m bool } - http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/plugins } { env(PLUGINS) -m bool } - http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/secrets } { env(SECRETS) -m bool } - http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/services } { env(SERVICES) -m bool } - http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/session } { env(SESSION) -m bool } - http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/swarm } { env(SWARM) -m bool } - http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/system } { env(SYSTEM) -m bool } - http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/tasks } { env(TASKS) -m bool } - http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/version } { env(VERSION) -m bool } - http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/volumes } { env(VOLUMES) -m bool } - http-request deny - default_backend dockerbackend - - use_backend docker-events if { path,url_dec -m reg -i ^(/v[\d\.]+)?/events } diff --git a/jenkins-vars.yml b/jenkins-vars.yml index fff8a4b..6fab271 100644 --- a/jenkins-vars.yml +++ b/jenkins-vars.yml @@ -2,14 +2,13 @@ # jenkins variables project_name: docker-socket-proxy -external_type: na -custom_version_command: "docker run --rm quay.io/skopeo/stable:v1 inspect docker://docker.io/haproxy:lts-alpine | jq -r '.Env[] | select(startswith(\"HAPROXY_VERSION\")) | split(\"=\")[1]'" +external_type: alpine_repo release_type: stable release_tag: latest ls_branch: main build_armhf: false repo_vars: - - BUILD_VERSION_ARG = 'HAPROXY_VERSION' + - BUILD_VERSION_ARG = 'NGINX_VERSION' - LS_USER = 'linuxserver' - LS_REPO = 'docker-socket-proxy' - CONTAINER_NAME = 'socket-proxy' @@ -17,6 +16,9 @@ repo_vars: - DEV_DOCKERHUB_IMAGE = 'lsiodev/socket-proxy' - PR_DOCKERHUB_IMAGE = 'lspipepr/socket-proxy' - DIST_IMAGE = 'alpine' + - DIST_TAG = '3.19' + - DIST_REPO = 'http://dl-cdn.alpinelinux.org/alpine/v3.19/main/' + - DIST_REPO_PACKAGES = 'nginx' - MULTIARCH='true' - CI='false' - CI_WEB='false' diff --git a/readme-vars.yml b/readme-vars.yml index 1d678ff..d949f45 100644 --- a/readme-vars.yml +++ b/readme-vars.yml @@ -36,9 +36,9 @@ full_custom_readme: | [![Docker Stars](https://img.shields.io/docker/stars/linuxserver/socket-proxy.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&label=stars&logo=docker)](https://hub.docker.com/r/linuxserver/socket-proxy) [![Jenkins Build](https://img.shields.io/jenkins/build?labelColor=555555&logoColor=ffffff&style=for-the-badge&jobUrl=https%3A%2F%2Fci.linuxserver.io%2Fjob%2FDocker-Pipeline-Builders%2Fjob%2Fdocker-socket-proxy%2Fjob%2Fmain%2F&logo=jenkins)](https://ci.linuxserver.io/job/Docker-Pipeline-Builders/job/docker-socket-proxy/job/main/) - [Socket-proxy](https://github.com/Tecnativa/docker-socket-proxy) is a security-enhanced proxy for the Docker Socket. + Socket proxy is a security-enhanced proxy for the Docker Socket. - [![socket-proxy](https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/docker-logo.png)](https://github.com/Tecnativa/docker-socket-proxy) + ![socket-proxy](https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/docker-logo.png) ## Supported Architectures @@ -56,9 +56,9 @@ full_custom_readme: | ## Application Setup - This container is a fork of [https://github.com/Tecnativa/docker-socket-proxy](https://github.com/Tecnativa/docker-socket-proxy) and as such does not follow our usual container conventions. It *does not* support mods or custom scripts/services, or running as a user other than root (or the docker user in a rootless environment). + This container is based on [https://github.com/Tecnativa/docker-socket-proxy](https://github.com/Tecnativa/docker-socket-proxy) and as such does not follow our usual container conventions. It *does not* support mods or custom scripts/services, or running as a user other than root (or the docker user in a rootless environment). - The container should be run on the same docker network as the service(s) using it. Most containers that would normally connect to a mounted docker.sock can have their endpoint overridden using the `DOCKER_HOST` environment variable if they do not offer the option in their configuration; it should typically be pointed to tcp://socket-proxy:2375. + The container should be run on the same docker network as the service(s) using it. Most containers that would normally connect to a mounted docker.sock can have their endpoint overridden using the `DOCKER_HOST` environment variable if they do not offer the option in their configuration; it should typically be pointed to `tcp://socket-proxy:2375`. * Never expose this container's port to a public network. It should be treated the same way you would treat the docker socket or TCP endpoint. * Revoke access to any API section that you consider your service should not need. @@ -78,34 +78,32 @@ full_custom_readme: | image: lscr.io/linuxserver/socket-proxy:latest container_name: socket-proxy environment: - - EVENTS=1 #optional - - PING=1 #optional - - VERSION=1 #optional + - ALLOW_START=0 #optional + - ALLOW_STOP=0 #optional + - ALLOW_RESTARTS=0 #optional - AUTH=0 #optional - - SECRETS=0 #optional - - POST=0 #optional - BUILD=0 #optional - COMMIT=0 #optional - CONFIGS=0 #optional - CONTAINERS=0 #optional - - ALLOW_START=0 #optional - - ALLOW_STOP=0 #optional - - ALLOW_RESTARTS=0 #optional - DISTRIBUTION=0 #optional + - EVENTS=1 #optional - EXEC=0 #optional - IMAGES=0 #optional - INFO=0 #optional - - LOG_LEVEL=info #optional - NETWORKS=0 #optional - NODES=0 #optional + - PING=1 #optional + - POST=0 #optional - PLUGINS=0 #optional + - SECRETS=0 #optional - SERVICES=0 #optional - SESSION=0 #optional - SWARM=0 #optional - SYSTEM=0 #optional - TASKS=0 #optional + - VERSION=1 #optional - VOLUMES=0 #optional - - DISABLE_IPV6=0 #optional volumes: - /var/run/docker.sock:/var/run/docker.sock:ro restart: unless-stopped @@ -119,34 +117,32 @@ full_custom_readme: | ```bash docker run -d \ --name=socket-proxy \ - -e EVENTS=1 `#optional` \ - -e PING=1 `#optional` \ - -e VERSION=1 `#optional` \ + -e ALLOW_START=0 `#optional` \ + -e ALLOW_STOP=0 `#optional` \ + -e ALLOW_RESTARTS=0 `#optional` \ -e AUTH=0 `#optional` \ - -e SECRETS=0 `#optional` \ - -e POST=0 `#optional` \ -e BUILD=0 `#optional` \ -e COMMIT=0 `#optional` \ -e CONFIGS=0 `#optional` \ -e CONTAINERS=0 `#optional` \ - -e ALLOW_START=0 `#optional` \ - -e ALLOW_STOP=0 `#optional` \ - -e ALLOW_RESTARTS=0 `#optional` \ -e DISTRIBUTION=0 `#optional` \ + -e EVENTS=1 `#optional` \ -e EXEC=0 `#optional` \ -e IMAGES=0 `#optional` \ -e INFO=0 `#optional` \ - -e LOG_LEVEL=info `#optional` \ -e NETWORKS=0 `#optional` \ -e NODES=0 `#optional` \ + -e PING=1 `#optional` \ + -e POST=0 `#optional` \ -e PLUGINS=0 `#optional` \ + -e SECRETS=0 `#optional` \ -e SERVICES=0 `#optional` \ -e SESSION=0 `#optional` \ -e SWARM=0 `#optional` \ -e SYSTEM=0 `#optional` \ -e TASKS=0 `#optional` \ + -e VERSION=1 `#optional` \ -e VOLUMES=0 `#optional` \ - -e DISABLE_IPV6=0 `#optional` \ -v /var/run/docker.sock:/var/run/docker.sock:ro \ --restart unless-stopped \ --read-only \ @@ -160,34 +156,32 @@ full_custom_readme: | | Parameter | Function | | :----: | --- | - | `-e EVENTS=1` | `/events` | - | `-e PING=1` | `/_ping` | - | `-e VERSION=1` | `/version` | + | `-e ALLOW_START=0` | `/containers/id/start` | + | `-e ALLOW_STOP=0` | `/containers/id/stop` | + | `-e ALLOW_RESTARTS=0` | `/containers/id/stop`, `/containers/id/restart`, and `/containers/id/kill` | | `-e AUTH=0` | `/auth` | - | `-e SECRETS=0` | `/secrets` | - | `-e POST=0` | When set to `0`, only `GET` and `HEAD` operations are allowed, making API access read-only. | | `-e BUILD=0` | `/build` | | `-e COMMIT=0` | `/commit` | | `-e CONFIGS=0` | `/configs` | | `-e CONTAINERS=0` | `/containers` | - | `-e ALLOW_START=0` | `/containers/id/start` | - | `-e ALLOW_STOP=0` | `/containers/id/stop` | - | `-e ALLOW_RESTARTS=0` | `/containers/id/stop`, `/containers/id/restart`, and `/containers/id/kill` | | `-e DISTRIBUTION=0` | `/distribution` | + | `-e EVENTS=1` | `/events` | | `-e EXEC=0` | `/exec` & `/containers/{id}/exec` | | `-e IMAGES=0` | `/images` | | `-e INFO=0` | `/info` | - | `-e LOG_LEVEL=info` | Default value is `info`. Possible values are: `debug`, `info`, `notice`, `warning`, `err`, `crit`, `alert`, and `emerg`. | | `-e NETWORKS=0` | `/networks` | | `-e NODES=0` | `/nodes` | + | `-e PING=1` | `/_ping` | | `-e PLUGINS=0` | `/plugins` | + | `-e POST=0` | When set to `0`, only `GET` and `HEAD` operations are allowed, making API access read-only. | + | `-e SECRETS=0` | `/secrets` | | `-e SERVICES=0` | `/services` | | `-e SESSION=0` | `/session` | | `-e SWARM=0` | `/swarm` | | `-e SYSTEM=0` | `/system` | | `-e TASKS=0` | `/tasks` | + | `-e VERSION=1` | `/version` | | `-e VOLUMES=0` | `/volumes` | - | `-e DISABLE_IPV6=0` | Set to `1` to disable IPv6 bindings in scenarios where the host cannot support it. | | `-v /var/run/docker.sock:ro` | Mount the host docker socket into the container. | | `--read-only` | Make the container filesystem read-only. | | `--tmpfs /run` | Mount /run to tmpfs (RAM) to make it writeable. | @@ -311,6 +305,7 @@ full_custom_readme: | ## Versions + * **08.04.24:** - Use nginx due to haproxy's wonky websockets handling. * **07.04.24:** - Initial Release. {%- endraw %} diff --git a/root/docker-entrypoint.sh b/root/docker-entrypoint.sh new file mode 100755 index 0000000..46a6072 --- /dev/null +++ b/root/docker-entrypoint.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +if [[ $POST == 1 ]]; then + envsubst "$(printf '${%s} ' $(bash -c "compgen -A variable"))" < /templates/default_post.template > /run/default.conf +else + envsubst "$(printf '${%s} ' $(bash -c "compgen -A variable"))" < /templates/default_nopost.template > /run/default.conf +fi + +echo ' +─────────────────────────────────────── + + ██╗ ███████╗██╗ ██████╗ + ██║ ██╔════╝██║██╔═══██╗ + ██║ ███████╗██║██║ ██║ + ██║ ╚════██║██║██║ ██║ + ███████╗███████║██║╚██████╔╝ + ╚══════╝╚══════╝╚═╝ ╚═════╝ + + Brought to you by linuxserver.io +─────────────────────────────────────── +─────────────────────────────────────── + +To support LSIO projects visit: +https://www.linuxserver.io/donate/ + +─────────────────────────────────────── +' + +echo "[ls.io-init] done." + +exec /usr/sbin/nginx -e stderr diff --git a/root/etc/nginx/nginx.conf b/root/etc/nginx/nginx.conf new file mode 100644 index 0000000..6227cfc --- /dev/null +++ b/root/etc/nginx/nginx.conf @@ -0,0 +1,77 @@ +## Version 2023/04/13 - Changelog: https://github.com/linuxserver/docker-baseimage-alpine-nginx/commits/master/root/defaults/nginx/nginx.conf.sample + +### Based on alpine defaults +# https://git.alpinelinux.org/aports/tree/main/nginx/nginx.conf?h=3.19-stable + +user root; + +# Enables the use of JIT for regular expressions to speed-up their processing. +pcre_jit on; + +# Configures default error logger. +error_log stderr; + +# Includes files with directives to load dynamic modules. +include /etc/nginx/modules/*.conf; + +# Include files with config snippets into the root context. +include /etc/nginx/conf.d/*.conf; + +events { + # The maximum number of simultaneous connections that can be opened by + # a worker process. + worker_connections 1024; +} + +http { + # Includes mapping of file name extensions to MIME types of responses + # and defines the default type. + include /etc/nginx/mime.types; + default_type application/octet-stream; + + # Don't tell nginx version to the clients. Default is 'on'. + server_tokens off; + + # Specifies the maximum accepted body size of a client request, as + # indicated by the request header Content-Length. If the stated content + # length is greater than this size, then the client receives the HTTP + # error code 413. Set to 0 to disable. Default is '1m'. + client_max_body_size 0; + client_body_temp_path /tmp; + proxy_temp_path /tmp; + fastcgi_temp_path /tmp; + uwsgi_temp_path /tmp; + scgi_temp_path /tmp; + + # Sendfile copies data between one FD and other from within the kernel, + # which is more efficient than read() + write(). Default is off. + sendfile on; + + # Causes nginx to attempt to send its HTTP response head in one packet, + # instead of using partial frames. Default is 'off'. + tcp_nopush on; + + # all ssl related config moved to ssl.conf + # included in server blocks where listen 443 is defined + + # Enable gzipping of responses. + #gzip on; + + # Set the Vary HTTP header as defined in the RFC 2616. Default is 'off'. + gzip_vary on; + + # Helper variable for proxying websockets. + map $http_upgrade $connection_upgrade { + default upgrade; + '' close; + } + + # Sets the path, format, and configuration for a buffered log write. + access_log /dev/stdout; + + # Includes virtual hosts configs. + include /run/default.conf; +} + +daemon off; +pid /run/nginx.pid; diff --git a/root/etc/nginx/proxy.conf b/root/etc/nginx/proxy.conf new file mode 100644 index 0000000..967d170 --- /dev/null +++ b/root/etc/nginx/proxy.conf @@ -0,0 +1,37 @@ +## Version 2023/02/09 - Changelog: https://github.com/linuxserver/docker-swag/commits/master/root/defaults/nginx/proxy.conf.sample + +# Timeout if the real server is dead +proxy_next_upstream error timeout invalid_header http_500 http_502 http_503; + +# Proxy Connection Settings +proxy_buffers 32 4k; +proxy_connect_timeout 240; +proxy_headers_hash_bucket_size 128; +proxy_headers_hash_max_size 1024; +proxy_http_version 1.1; +proxy_read_timeout 240; +proxy_redirect http:// $scheme://; +proxy_send_timeout 240; + +# Proxy Cache and Cookie Settings +proxy_cache_bypass $cookie_session; +#proxy_cookie_path / "/; Secure"; # enable at your own risk, may break certain apps +proxy_no_cache $cookie_session; + +# Proxy Header Settings +proxy_set_header Connection $connection_upgrade; +proxy_set_header Early-Data $ssl_early_data; +proxy_set_header Host $host; +proxy_set_header Proxy ""; +proxy_set_header Upgrade $http_upgrade; +proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; +proxy_set_header X-Forwarded-Host $host; +proxy_set_header X-Forwarded-Method $request_method; +proxy_set_header X-Forwarded-Port $server_port; +proxy_set_header X-Forwarded-Proto $scheme; +proxy_set_header X-Forwarded-Server $host; +proxy_set_header X-Forwarded-Ssl on; +proxy_set_header X-Forwarded-Uri $request_uri; +proxy_set_header X-Original-Method $request_method; +proxy_set_header X-Original-URL $scheme://$http_host$request_uri; +proxy_set_header X-Real-IP $remote_addr; diff --git a/root/templates/default_nopost.template b/root/templates/default_nopost.template new file mode 100644 index 0000000..badf08f --- /dev/null +++ b/root/templates/default_nopost.template @@ -0,0 +1,62 @@ +server { + listen 2375 default_server; + listen [::]:2375 default_server; + + server_name _; + + set $dockersocket $SOCKET_PATH; + set $path_restarts $ALLOW_RESTARTS; + set $path_stop $ALLOW_STOP; + set $path_start $ALLOW_START; + set $path_auth $AUTH; + set $path_build $BUILD; + set $path_commit $COMMIT; + set $path_configs $CONFIGS; + set $path_containers $CONTAINERS; + set $path_distribution $DISTRIBUTION; + set $path_events $EVENTS; + set $path_exec $EXEC; + set $path_images $IMAGES; + set $path_info $INFO; + set $path_networks $NETWORKS; + set $path_nodes $NODES; + set $path_ping $PING; + set $path_plugins $PLUGINS; + set $path_secrets $SECRETS; + set $path_services $SERVICES; + set $path_session $SESSION; + set $path_swarm $SWARM; + set $path_system $SYSTEM; + set $path_tasks $TASKS; + set $path_version $VERSION; + set $path_volumes $VOLUMES; + + include /etc/nginx/proxy.conf; + + location ~* ^(/v[\d\.]+)?/containers/[a-zA-Z0-9_.-]+/((stop)|(restart)|(kill)) {limit_except GET HEAD {deny all;}if ($path_restarts = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/containers/[a-zA-Z0-9_.-]+/start {limit_except GET HEAD {deny all;}if ($path_start = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/containers/[a-zA-Z0-9_.-]+/stop {limit_except GET HEAD {deny all;}if ($path_stop = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/auth {limit_except GET HEAD {deny all;}if ($path_auth = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/build {limit_except GET HEAD {deny all;}if ($path_build = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/commit {limit_except GET HEAD {deny all;}if ($path_commit = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/configs {limit_except GET HEAD {deny all;}if ($path_configs = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/containers {limit_except GET HEAD {deny all;}if ($path_containers = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/distribution {limit_except GET HEAD {deny all;}if ($path_distribution = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/events {limit_except GET HEAD {deny all;}if ($path_events = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/exec {limit_except GET HEAD {deny all;}if ($path_exec = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/images {limit_except GET HEAD {deny all;}if ($path_images = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/info {limit_except GET HEAD {deny all;}if ($path_info = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/networks {limit_except GET HEAD {deny all;}if ($path_networks = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/nodes {limit_except GET HEAD {deny all;}if ($path_nodes = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/_ping {limit_except GET HEAD {deny all;}if ($path_ping = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/plugins {limit_except GET HEAD {deny all;}if ($path_plugins = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/secrets {limit_except GET HEAD {deny all;}if ($path_secrets = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/services {limit_except GET HEAD {deny all;}if ($path_services = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/session {limit_except GET HEAD {deny all;}if ($path_session = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/swarm {limit_except GET HEAD {deny all;}if ($path_swarm = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/system {limit_except GET HEAD {deny all;}if ($path_system = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/tasks {limit_except GET HEAD {deny all;}if ($path_tasks = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/version {limit_except GET HEAD {deny all;}if ($path_version = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/volumes {limit_except GET HEAD {deny all;}if ($path_volumes = 0){return 403;}proxy_pass http://unix:$dockersocket;} + +} diff --git a/root/templates/default_post.template b/root/templates/default_post.template new file mode 100644 index 0000000..31af5d5 --- /dev/null +++ b/root/templates/default_post.template @@ -0,0 +1,62 @@ +server { + listen 2375 default_server; + listen [::]:2375 default_server; + + server_name _; + + set $dockersocket $SOCKET_PATH; + set $path_restarts $ALLOW_RESTARTS; + set $path_stop $ALLOW_STOP; + set $path_start $ALLOW_START; + set $path_auth $AUTH; + set $path_build $BUILD; + set $path_commit $COMMIT; + set $path_configs $CONFIGS; + set $path_containers $CONTAINERS; + set $path_distribution $DISTRIBUTION; + set $path_events $EVENTS; + set $path_exec $EXEC; + set $path_images $IMAGES; + set $path_info $INFO; + set $path_networks $NETWORKS; + set $path_nodes $NODES; + set $path_ping $PING; + set $path_plugins $PLUGINS; + set $path_secrets $SECRETS; + set $path_services $SERVICES; + set $path_session $SESSION; + set $path_swarm $SWARM; + set $path_system $SYSTEM; + set $path_tasks $TASKS; + set $path_version $VERSION; + set $path_volumes $VOLUMES; + + include /etc/nginx/proxy.conf; + + location ~* ^(/v[\d\.]+)?/containers/[a-zA-Z0-9_.-]+/((stop)|(restart)|(kill)) {if ($path_restarts = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/containers/[a-zA-Z0-9_.-]+/start {if ($path_start = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/containers/[a-zA-Z0-9_.-]+/stop {if ($path_stop = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/auth {if ($path_auth = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/build {if ($path_build = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/commit {if ($path_commit = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/configs {if ($path_configs = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/containers {if ($path_containers = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/distribution {if ($path_distribution = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/events {if ($path_events = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/exec {if ($path_exec = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/images {if ($path_images = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/info {if ($path_info = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/networks {if ($path_networks = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/nodes {if ($path_nodes = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/_ping {if ($path_ping = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/plugins {if ($path_plugins = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/secrets {if ($path_secrets = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/services {if ($path_services = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/session {if ($path_session = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/swarm {if ($path_swarm = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/system {if ($path_system = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/tasks {if ($path_tasks = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/version {if ($path_version = 0){return 403;}proxy_pass http://unix:$dockersocket;} + location ~* ^(/v[\d\.]+)?/volumes {if ($path_volumes = 0){return 403;}proxy_pass http://unix:$dockersocket;} + +}