Skip to content

Commit 349b439

Browse files
authored
Merge pull request #205 from linuxserver/swag-auto-proxy-dev
swag-auto-proxy: initial release
2 parents d1dc6e5 + fe3296e commit 349b439

File tree

10 files changed

+205
-69
lines changed

10 files changed

+205
-69
lines changed

.github/workflows/BuildImage.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ name: Build Image
33
on: [push, pull_request, workflow_dispatch]
44

55
env:
6-
ENDPOINT: "linuxserver/mods" #don't modify
7-
BASEIMAGE: "replace_baseimage" #replace
8-
MODNAME: "replace_modname" #replace
6+
ENDPOINT: "linuxserver/mods"
7+
BASEIMAGE: "swag"
8+
MODNAME: "auto-proxy"
99

1010
jobs:
1111
build:

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
FROM scratch
22

3-
LABEL maintainer="username"
3+
LABEL maintainer="aptalca"
44

55
# copy local files
66
COPY root/ /

Dockerfile.complex

Lines changed: 0 additions & 23 deletions
This file was deleted.

README.md

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,37 @@
1-
# Rsync - Docker mod for openssh-server
1+
# Auto-proxy - Docker mod for SWAG
22

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

5-
In openssh-server docker arguments, set an environment variable `DOCKER_MODS=linuxserver/mods:openssh-server-rsync`
5+
## Requirements:
6+
- This mod needs the `universal-docker` mod installed and set up with either mapping `docker.sock` or setting the environment variable `DOCKER_HOST=remoteaddress`.
7+
- 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.
8+
- Containers to be auto-detected and reverse proxied must have a label `swag=enable` at a minimum.
9+
- 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`).
610

7-
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`
11+
## Labels:
12+
- `swag=enable` - required for auto-detection
13+
- `swag_port=80` - *optional* - overrides *internal* exposed port
14+
- `swag_proto=http` - *optional* - overrides internal proto (defaults to http)
15+
- `swag_url=containername.domain.com` - *optional* - overrides *server_name* (defaults to `containername.*`)
16+
- `swag_auth=authelia` - *optional* - enables auth methods (options are `authelia`, `ldap` and `http` for basic http auth)
17+
- `swag_auth_bypass=/api,/othersubfolder` - *optional* - bypasses auth for selected subfolders. Comma separated, no spaces.
818

9-
# Mod creation instructions
1019

11-
* Fork the repo, create a new branch based on the branch `template`.
12-
* Edit the `Dockerfile` for the mod. `Dockerfile.complex` is only an example and included for reference; it should be deleted when done.
13-
* Inspect the `root` folder contents. Edit, add and remove as necessary.
14-
* Edit this readme with pertinent info, delete these instructions.
15-
* Finally edit the `.github/workflows/BuildImage.yml`. Customize the build branch, and the vars for `BASEIMAGE` and `MODNAME`.
16-
* 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.
17-
* Submit PR against the branch created by the team.
20+
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`.
21+
22+
## Security Consideration:
23+
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.
24+
25+
Here's a sample compose yaml snippet for tecnativa/docker-socket-proxy:
26+
```yaml
27+
dockerproxy:
28+
image: ghcr.io/tecnativa/docker-socket-proxy:latest
29+
container_name: dockerproxy
30+
volumes:
31+
- /var/run/docker.sock:/var/run/docker.sock:ro
32+
restart: unless-stopped
33+
environment:
34+
- CONTAINERS=1
35+
- POST=0
36+
```
37+
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.

root/app/auto-proxy.sh

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
#!/usr/bin/with-contenv bash
2+
3+
AUTO_GEN=""
4+
# figure out which containers to generate confs for or which confs to remove
5+
if [ ! -f /auto-proxy/enabled_containers ]; then
6+
docker ps --filter "label=swag=enable" --format "{{.Names}}" > /auto-proxy/enabled_containers
7+
AUTO_GEN=$(cat /auto-proxy/enabled_containers)
8+
else
9+
ENABLED_CONTAINERS=$(docker ps --filter "label=swag=enable" --format "{{.Names}}")
10+
for CONTAINER in ${ENABLED_CONTAINERS}; do
11+
if [ ! -f "/auto-proxy/${CONTAINER}.conf" ]; then
12+
echo "**** New container ${CONTAINER} detected, will generate new conf. ****"
13+
AUTO_GEN="${CONTAINER} ${AUTO_GEN}"
14+
else
15+
INSPECTION=$(docker inspect ${CONTAINER})
16+
for VAR in swag_port swag_proto swag_url swag_auth swag_auth_bypass; do
17+
VAR_VALUE=$(echo ${INSPECTION} | jq -r ".[0].Config.Labels[\"${VAR}\"]")
18+
if [ "${VAR_VALUE}" == "null" ]; then
19+
VAR_VALUE=""
20+
fi
21+
if ! grep -q "${VAR}=\"${VAR_VALUE}\"" "/auto-proxy/${CONTAINER}.conf"; then
22+
AUTO_GEN="${CONTAINER} ${AUTO_GEN}"
23+
echo "**** Labels for ${CONTAINER} changed, will generate new conf. ****"
24+
break
25+
fi
26+
done
27+
fi
28+
done
29+
EXISTING_CONFS=$(cat /auto-proxy/enabled_containers)
30+
for CONTAINER in $EXISTING_CONFS; do
31+
if ! grep -q "${CONTAINER}" <<< "${ENABLED_CONTAINERS}"; then
32+
echo "**** Removing conf for ${CONTAINER} ****"
33+
rm -rf "/auto-proxy/${CONTAINER}.conf" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
34+
REMOVED_CONTAINERS="true"
35+
fi
36+
done
37+
echo "${ENABLED_CONTAINERS}" > /auto-proxy/enabled_containers
38+
fi
39+
40+
for CONTAINER in ${AUTO_GEN}; do
41+
INSPECTION=$(docker inspect ${CONTAINER})
42+
rm -rf "/auto-proxy/${CONTAINER}.conf"
43+
for VAR in swag_port swag_proto swag_url swag_auth swag_auth_bypass; do
44+
VAR_VALUE=$(echo ${INSPECTION} | jq -r ".[0].Config.Labels[\"${VAR}\"]")
45+
if [ "${VAR_VALUE}" == "null" ]; then
46+
VAR_VALUE=""
47+
fi
48+
echo "${VAR}=\"${VAR_VALUE}\"" >> "/auto-proxy/${CONTAINER}.conf"
49+
done
50+
. /auto-proxy/${CONTAINER}.conf
51+
if [ -f "/config/nginx/proxy-confs/${CONTAINER}.subdomain.conf.sample" ]; then
52+
cp "/config/nginx/proxy-confs/${CONTAINER}.subdomain.conf.sample" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
53+
echo "**** Using preset proxy conf for ${CONTAINER} ****"
54+
if [ -n "${swag_auth_bypass}" ]; then
55+
echo "**** Swag auth bypass is auto managed via preset confs and cannot be overridden via env vars ****"
56+
fi
57+
if [ -n "${swag_port}" ]; then
58+
sed -i "s|set \$upstream_port .*|set \$upstream_port ${swag_port};|g" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
59+
echo "**** Overriding port for ${CONTAINER} ****"
60+
fi
61+
if [ -n "${swag_proto}" ]; then
62+
sed -i "s|set \$upstream_proto .*|set \$upstream_proto ${swag_proto};|g" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
63+
echo "**** Overriding proto for ${CONTAINER} ****"
64+
fi
65+
if [ -n "${swag_url}" ]; then
66+
sed -i "s|server_name .*|server_name ${swag_url};|" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
67+
echo "**** Overriding url for ${CONTAINER} ****"
68+
fi
69+
if [ "${swag_auth}" == "authelia" ]; then
70+
sed -i "s|#include /config/nginx/authelia|include /config/nginx/authelia|g" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
71+
echo "**** Enabling Authelia for ${CONTAINER} ****"
72+
elif [ "${swag_auth}" == "http" ]; then
73+
sed -i "s|#auth_basic|auth_basic|g" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
74+
echo "**** Enabling basic http auth for ${CONTAINER} ****"
75+
elif [ "${swag_auth}" == "ldap" ]; then
76+
sed -i "s|#include /config/nginx/ldap.conf;|include /config/nginx/ldap.conf;|g" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
77+
sed -i "s|#auth_request /auth;|auth_request /auth;|g" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
78+
sed -i "s|#error_page 401 =200 /ldaplogin;|error_page 401 =200 /ldaplogin;|g" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
79+
echo "**** Enabling basic http auth for ${CONTAINER} ****"
80+
fi
81+
else
82+
echo "**** No preset proxy conf found for ${CONTAINER}, generating from scratch ****"
83+
cp "/config/nginx/proxy-confs/_template.subdomain.conf.sample" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
84+
if [ -n "${swag_auth_bypass}" ]; then
85+
sed -i 's|^}$||' "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
86+
for location in $(echo ${swag_auth_bypass} | tr "," " "); do
87+
cat <<DUDE >> "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
88+
89+
location ~ ${location} {
90+
include /config/nginx/proxy.conf;
91+
include /config/nginx/resolver.conf;
92+
set \$upstream_app <container_name>;
93+
set \$upstream_port <port_number>;
94+
set \$upstream_proto <http or https>;
95+
proxy_pass \$upstream_proto://\$upstream_app:\$upstream_port;
96+
97+
}
98+
99+
DUDE
100+
done
101+
echo "}" >> "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
102+
fi
103+
sed -i "s|<container_name>|${CONTAINER}|g" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
104+
if [ -z "${swag_port}" ]; then
105+
swag_port=$(docker inspect ${CONTAINER} | jq -r '.[0].NetworkSettings.Ports | keys[0]' | sed 's|/.*||')
106+
if [ "${swag_port}" == "null" ]; then
107+
echo "**** No exposed ports found for ${CONTAINER}. Setting reverse proxy port to 80. ****"
108+
swag_port="80"
109+
fi
110+
fi
111+
sed -i "s|set \$upstream_port .*|set \$upstream_port ${swag_port};|g" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
112+
echo "**** Setting port ${swag_port} for ${CONTAINER} ****"
113+
if [ -z "${swag_proto}" ]; then
114+
swag_proto="http"
115+
fi
116+
sed -i "s|set \$upstream_proto .*|set \$upstream_proto ${swag_proto};|g" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
117+
echo "**** Setting proto ${swag_proto} for ${CONTAINER} ****"
118+
if [ -z "${swag_url}" ]; then
119+
swag_url="${CONTAINER}.*"
120+
fi
121+
sed -i "s|server_name .*|server_name ${swag_url};|" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
122+
echo "**** Setting url ${swag_url} for ${CONTAINER} ****"
123+
if [ "${swag_auth}" == "authelia" ]; then
124+
sed -i "s|#include /config/nginx/authelia|include /config/nginx/authelia|g" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
125+
echo "**** Enabling Authelia for ${CONTAINER} ****"
126+
elif [ "${swag_auth}" == "http" ]; then
127+
sed -i "s|#auth_basic|auth_basic|g" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
128+
echo "**** Enabling basic http auth for ${CONTAINER} ****"
129+
elif [ "${swag_auth}" == "ldap" ]; then
130+
sed -i "s|#include /config/nginx/ldap.conf;|include /config/nginx/ldap.conf;|g" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
131+
sed -i "s|#auth_request /auth;|auth_request /auth;|g" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
132+
sed -i "s|#error_page 401 =200 /ldaplogin;|error_page 401 =200 /ldaplogin;|g" "/config/nginx/proxy-confs/auto-proxy-${CONTAINER}.subdomain.conf"
133+
echo "**** Enabling basic http auth for ${CONTAINER} ****"
134+
fi
135+
fi
136+
done
137+
138+
if ([ -n "${AUTO_GEN}" ] || [ "${REMOVED_CONTAINERS}" == "true" ]) && ps aux | grep [n]ginx: > /dev/null; then
139+
if /usr/sbin/nginx -c /config/nginx/nginx.conf -t; then
140+
echo "**** Changes to nginx config are valid, reloading nginx ****"
141+
/usr/sbin/nginx -c /config/nginx/nginx.conf -s reload
142+
else
143+
echo "**** Changes to nginx config are not valid, skipping nginx reload. Please double check the config including the auto-proxy confs. ****"
144+
fi
145+
fi

root/defaults/auto-proxy-readme

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
The files named "auto-proxy-<servicename>.subdomain.conf" are managed by the SWAG-auto-proxy mod.
2+
*** Do not manually modify those files ***
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/usr/bin/with-contenv bash
2+
3+
sed -i '/\/app\/auto-proxy.sh/d' /config/crontabs/root
4+
rm -rf /config/nginx/proxy-confs/auto-proxy*.conf

root/etc/cont-init.d/98-auto-proxy

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#!/usr/bin/with-contenv bash
2+
3+
if [ ! -f /usr/local/bin/docker ]; then
4+
echo "**** Docker mod not installed, skipping SWAG auto-proxy ****"
5+
exit 0
6+
fi
7+
8+
rm -rf /config/nginx/proxy-confs/auto-proxy*.conf
9+
cp /defaults/auto-proxy-readme /config/nginx/proxy-confs/auto-proxy-readme
10+
rm -rf /auto-proxy
11+
mkdir /auto-proxy
12+
13+
if ! grep -q "/app/auto-proxy.sh" /config/crontabs/root; then
14+
echo "* * * * * /app/auto-proxy.sh" >> /config/crontabs/root
15+
cp /config/crontabs/root /etc/crontabs/root
16+
fi
17+
18+
/app/auto-proxy.sh

root/etc/cont-init.d/98-vpn-config

Lines changed: 0 additions & 27 deletions
This file was deleted.

root/etc/services.d/sshvpn/run

Lines changed: 0 additions & 3 deletions
This file was deleted.

0 commit comments

Comments
 (0)