Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/BuildImage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ name: Build Image
on: [push, pull_request, workflow_dispatch]

env:
ENDPOINT: "linuxserver/mods" #don't modify
BASEIMAGE: "replace_baseimage" #replace
MODNAME: "replace_modname" #replace
ENDPOINT: "linuxserver/mods"
BASEIMAGE: "swag"
MODNAME: "auto-proxy"

jobs:
build:
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
FROM scratch

LABEL maintainer="username"
LABEL maintainer="aptalca"

# copy local files
COPY root/ /
23 changes: 0 additions & 23 deletions Dockerfile.complex

This file was deleted.

44 changes: 32 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,37 @@
# Rsync - Docker mod for openssh-server
# Auto-proxy - Docker mod for SWAG

This mod adds rsync to openssh-server, to be installed/updated during container start.
This mod gives SWAG the ability to auto-detect running containers via labels and automatically enable reverse proxy for them.

In openssh-server docker arguments, set an environment variable `DOCKER_MODS=linuxserver/mods:openssh-server-rsync`
## Requirements:
- This mod needs the `universal-docker` mod installed and set up with either mapping `docker.sock` or setting the environment variable `DOCKER_HOST=remoteaddress`.
- Other containers to be auto-detected and reverse proxied should be in the same [user defined bridge network](https://docs.linuxserver.io/general/swag#docker-networking) as SWAG.
- Containers to be auto-detected and reverse proxied must have a label `swag=enable` at a minimum.
- To benefit from curated preset proxy confs we provide, the container name must match the container names that are suggested in our readme examples (ie. `radarr` and not `Radarr-4K`).

If adding multiple mods, enter them in an array separated by `|`, such as `DOCKER_MODS=linuxserver/mods:openssh-server-rsync|linuxserver/mods:openssh-server-mod2`
## Labels:
- `swag=enable` - required for auto-detection
- `swag_port=80` - *optional* - overrides *internal* exposed port
- `swag_proto=http` - *optional* - overrides internal proto (defaults to http)
- `swag_url=containername.domain.com` - *optional* - overrides *server_name* (defaults to `containername.*`)
- `swag_auth=authelia` - *optional* - enables auth methods (options are `authelia`, `ldap` and `http` for basic http auth)
- `swag_auth_bypass=/api,/othersubfolder` - *optional* - bypasses auth for selected subfolders. Comma separated, no spaces.

# Mod creation instructions

* Fork the repo, create a new branch based on the branch `template`.
* Edit the `Dockerfile` for the mod. `Dockerfile.complex` is only an example and included for reference; it should be deleted when done.
* Inspect the `root` folder contents. Edit, add and remove as necessary.
* Edit this readme with pertinent info, delete these instructions.
* Finally edit the `.github/workflows/BuildImage.yml`. Customize the build branch, and the vars for `BASEIMAGE` and `MODNAME`.
* Ask the team to create a new branch named `<baseimagename>-<modname>`. Baseimage should be the name of the image the mod will be applied to. The new branch will be based on the `template` branch.
* Submit PR against the branch created by the team.
In SWAG docker arguments, set an environment variable `DOCKER_MODS=linuxserver/mods:universal-docker|linuxserver/mods:swag-auto-proxy` and either add a volume mapping for `/var/run/docker.sock:/var/run/docker.sock:ro`, or set an environment var `DOCKER_HOST=remoteaddress`.

## Security Consideration:
Mapping the `docker.sock`, especially in a publicly accessible container is a security liability. Since this mod only needs read-only access to the docker api, the recommended method is to proxy the `docker.sock` via a solution like [tecnativa/docker-socket-proxy](https://hub.docker.com/r/tecnativa/docker-socket-proxy), limit the access, and set `DOCKER_HOST=` to point to the proxy address.

Here's a sample compose yaml snippet for tecnativa/docker-socket-proxy:
```yaml
dockerproxy:
image: ghcr.io/tecnativa/docker-socket-proxy:latest
container_name: dockerproxy
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
restart: unless-stopped
environment:
- CONTAINERS=1
- POST=0
```
Then the env var in SWAG can be set as `DOCKER_HOST=dockerproxy`. This will allow docker cli in SWAG to be able to retrieve info on other containers, but it won't be allowed to spin up new containers.
145 changes: 145 additions & 0 deletions root/app/auto-proxy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
#!/usr/bin/with-contenv bash

AUTO_GEN=""
# figure out which containers to generate confs for or which confs to remove
if [ ! -f /auto-proxy/enabled_containers ]; then
docker ps --filter "label=swag=enable" --format "{{.Names}}" > /auto-proxy/enabled_containers
AUTO_GEN=$(cat /auto-proxy/enabled_containers)
else
ENABLED_CONTAINERS=$(docker ps --filter "label=swag=enable" --format "{{.Names}}")
for CONTAINER in ${ENABLED_CONTAINERS}; do
if [ ! -f "/auto-proxy/${CONTAINER}.conf" ]; then
echo "**** New container ${CONTAINER} detected, will generate new conf. ****"
AUTO_GEN="${CONTAINER} ${AUTO_GEN}"
else
INSPECTION=$(docker inspect ${CONTAINER})
for VAR in swag_port swag_proto swag_url swag_auth swag_auth_bypass; do
VAR_VALUE=$(echo ${INSPECTION} | jq -r ".[0].Config.Labels[\"${VAR}\"]")
if [ "${VAR_VALUE}" == "null" ]; then
VAR_VALUE=""
fi
if ! grep -q "${VAR}=\"${VAR_VALUE}\"" "/auto-proxy/${CONTAINER}.conf"; then
AUTO_GEN="${CONTAINER} ${AUTO_GEN}"
echo "**** Labels for ${CONTAINER} changed, will generate new conf. ****"
break
fi
done
fi
done
EXISTING_CONFS=$(cat /auto-proxy/enabled_containers)
for CONTAINER in $EXISTING_CONFS; do
if ! grep -q "${CONTAINER}" <<< "${ENABLED_CONTAINERS}"; then
echo "**** Removing conf for ${CONTAINER} ****"
rm -rf "/auto-proxy/${CONTAINER}.conf" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
REMOVED_CONTAINERS="true"
fi
done
echo "${ENABLED_CONTAINERS}" > /auto-proxy/enabled_containers
fi

for CONTAINER in ${AUTO_GEN}; do
INSPECTION=$(docker inspect ${CONTAINER})
rm -rf "/auto-proxy/${CONTAINER}.conf"
for VAR in swag_port swag_proto swag_url swag_auth swag_auth_bypass; do
VAR_VALUE=$(echo ${INSPECTION} | jq -r ".[0].Config.Labels[\"${VAR}\"]")
if [ "${VAR_VALUE}" == "null" ]; then
VAR_VALUE=""
fi
echo "${VAR}=\"${VAR_VALUE}\"" >> "/auto-proxy/${CONTAINER}.conf"
done
. /auto-proxy/${CONTAINER}.conf
if [ -f "/config/nginx/proxy-confs/${CONTAINER}.subdomain.conf.sample" ]; then
cp "/config/nginx/proxy-confs/${CONTAINER}.subdomain.conf.sample" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
echo "**** Using preset proxy conf for ${CONTAINER} ****"
if [ -n "${swag_auth_bypass}" ]; then
echo "**** Swag auth bypass is auto managed via preset confs and cannot be overridden via env vars ****"
fi
if [ -n "${swag_port}" ]; then
sed -i "s|set \$upstream_port .*|set \$upstream_port ${swag_port};|g" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
echo "**** Overriding port for ${CONTAINER} ****"
fi
if [ -n "${swag_proto}" ]; then
sed -i "s|set \$upstream_proto .*|set \$upstream_proto ${swag_proto};|g" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
echo "**** Overriding proto for ${CONTAINER} ****"
fi
if [ -n "${swag_url}" ]; then
sed -i "s|server_name .*|server_name ${swag_url};|" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
echo "**** Overriding url for ${CONTAINER} ****"
fi
if [ "${swag_auth}" == "authelia" ]; then
sed -i "s|#include /config/nginx/authelia|include /config/nginx/authelia|g" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
echo "**** Enabling Authelia for ${CONTAINER} ****"
elif [ "${swag_auth}" == "http" ]; then
sed -i "s|#auth_basic|auth_basic|g" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
echo "**** Enabling basic http auth for ${CONTAINER} ****"
elif [ "${swag_auth}" == "ldap" ]; then
sed -i "s|#include /config/nginx/ldap.conf;|include /config/nginx/ldap.conf;|g" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
sed -i "s|#auth_request /auth;|auth_request /auth;|g" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
sed -i "s|#error_page 401 =200 /ldaplogin;|error_page 401 =200 /ldaplogin;|g" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
echo "**** Enabling basic http auth for ${CONTAINER} ****"
fi
else
echo "**** No preset proxy conf found for ${CONTAINER}, generating from scratch ****"
cp "/config/nginx/proxy-confs/_template.subdomain.conf.sample" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
if [ -n "${swag_auth_bypass}" ]; then
sed -i 's|^}$||' "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
for location in $(echo ${swag_auth_bypass} | tr "," " "); do
cat <<DUDE >> "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"

location ~ ${location} {
include /config/nginx/proxy.conf;
include /config/nginx/resolver.conf;
set \$upstream_app <container_name>;
set \$upstream_port <port_number>;
set \$upstream_proto <http or https>;
proxy_pass \$upstream_proto://\$upstream_app:\$upstream_port;

}

DUDE
done
echo "}" >> "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
fi
sed -i "s|<container_name>|${CONTAINER}|g" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
if [ -z "${swag_port}" ]; then
swag_port=$(docker inspect ${CONTAINER} | jq -r '.[0].NetworkSettings.Ports | keys[0]' | sed 's|/.*||')
if [ "${swag_port}" == "null" ]; then
echo "**** No exposed ports found for ${CONTAINER}. Setting reverse proxy port to 80. ****"
swag_port="80"
fi
fi
sed -i "s|set \$upstream_port .*|set \$upstream_port ${swag_port};|g" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
echo "**** Setting port ${swag_port} for ${CONTAINER} ****"
if [ -z "${swag_proto}" ]; then
swag_proto="http"
fi
sed -i "s|set \$upstream_proto .*|set \$upstream_proto ${swag_proto};|g" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
echo "**** Setting proto ${swag_proto} for ${CONTAINER} ****"
if [ -z "${swag_url}" ]; then
swag_url="${CONTAINER}.*"
fi
sed -i "s|server_name .*|server_name ${swag_url};|" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
echo "**** Setting url ${swag_url} for ${CONTAINER} ****"
if [ "${swag_auth}" == "authelia" ]; then
sed -i "s|#include /config/nginx/authelia|include /config/nginx/authelia|g" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
echo "**** Enabling Authelia for ${CONTAINER} ****"
elif [ "${swag_auth}" == "http" ]; then
sed -i "s|#auth_basic|auth_basic|g" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
echo "**** Enabling basic http auth for ${CONTAINER} ****"
elif [ "${swag_auth}" == "ldap" ]; then
sed -i "s|#include /config/nginx/ldap.conf;|include /config/nginx/ldap.conf;|g" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
sed -i "s|#auth_request /auth;|auth_request /auth;|g" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
sed -i "s|#error_page 401 =200 /ldaplogin;|error_page 401 =200 /ldaplogin;|g" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
echo "**** Enabling basic http auth for ${CONTAINER} ****"
fi
fi
done

if ([ -n "${AUTO_GEN}" ] || [ "${REMOVED_CONTAINERS}" == "true" ]) && ps aux | grep [n]ginx: > /dev/null; then
if /usr/sbin/nginx -c /config/nginx/nginx.conf -t; then
echo "**** Changes to nginx config are valid, reloading nginx ****"
/usr/sbin/nginx -c /config/nginx/nginx.conf -s reload
else
echo "**** Changes to nginx config are not valid, skipping nginx reload. Please double check the config including the auto-proxy confs. ****"
fi
fi
2 changes: 2 additions & 0 deletions root/defaults/auto-proxy-readme
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
The files named "auto-proxy-<servicename>.subdomain.conf" are managed by the SWAG-auto-proxy mod.
*** Do not manually modify those files ***
4 changes: 4 additions & 0 deletions root/etc/cont-finish.d/98-auto-proxy
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/with-contenv bash

sed -i '/\/app\/auto-proxy.sh/d' /config/crontabs/root
rm -rf /config/nginx/proxy-confs/auto-proxy*.conf
18 changes: 18 additions & 0 deletions root/etc/cont-init.d/98-auto-proxy
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/with-contenv bash

if [ ! -f /usr/local/bin/docker ]; then
echo "**** Docker mod not installed, skipping SWAG auto-proxy ****"
exit 0
fi

rm -rf /config/nginx/proxy-confs/auto-proxy*.conf
cp /defaults/auto-proxy-readme /config/nginx/proxy-confs/auto-proxy-readme
rm -rf /auto-proxy
mkdir /auto-proxy

if ! grep -q "/app/auto-proxy.sh" /config/crontabs/root; then
echo "* * * * * /app/auto-proxy.sh" >> /config/crontabs/root
cp /config/crontabs/root /etc/crontabs/root
fi

/app/auto-proxy.sh
27 changes: 0 additions & 27 deletions root/etc/cont-init.d/98-vpn-config

This file was deleted.

3 changes: 0 additions & 3 deletions root/etc/services.d/sshvpn/run

This file was deleted.