diff --git a/.assets/example.png b/.assets/example.png new file mode 100644 index 0000000..8cdb059 Binary files /dev/null and b/.assets/example.png differ diff --git a/.github/workflows/BuildImage.yml b/.github/workflows/BuildImage.yml index 518b0d8..21c8db5 100644 --- a/.github/workflows/BuildImage.yml +++ b/.github/workflows/BuildImage.yml @@ -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: "dashboard" jobs: build: diff --git a/Dockerfile b/Dockerfile index 4ece5e8..ae5c3e5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ FROM scratch -LABEL maintainer="username" +LABEL maintainer="quietsy" # copy local files COPY root/ / diff --git a/Dockerfile.complex b/Dockerfile.complex deleted file mode 100644 index db4598e..0000000 --- a/Dockerfile.complex +++ /dev/null @@ -1,23 +0,0 @@ -## Buildstage ## -FROM ghcr.io/linuxserver/baseimage-alpine:3.12 as buildstage - -RUN \ - echo "**** install packages ****" && \ - apk add --no-cache \ - curl && \ - echo "**** grab rclone ****" && \ - mkdir -p /root-layer && \ - curl -o \ - /root-layer/rclone.deb -L \ - "https://downloads.rclone.org/v1.47.0/rclone-v1.47.0-linux-amd64.deb" - -# copy local files -COPY root/ /root-layer/ - -## Single layer deployed image ## -FROM scratch - -LABEL maintainer="username" - -# Add files from buildstage -COPY --from=buildstage /root-layer/ / diff --git a/README.md b/README.md index 5636dec..4de757e 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,11 @@ -# Rsync - Docker mod for openssh-server +# Dashboard Docker mod for SWAG -This mod adds rsync to openssh-server, to be installed/updated during container start. +This mod adds a dashboard to SWAG powered by [Goaccess](https://goaccess.io/). -In openssh-server docker arguments, set an environment variable `DOCKER_MODS=linuxserver/mods:openssh-server-rsync` +# Configuration -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` +* Enable the dashboard by copying `/config/nginx/proxy-confs/dashboard.subdomain.conf.sample` to `/config/nginx/proxy-confs/dashboard.subdomain.conf` +* Navigate to `dashboard.domain.com` from your LAN -# 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 `-`. 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. +# Example +![Example](.assets/example.png) diff --git a/root/dashboard/dashboard.subdomain.conf.sample b/root/dashboard/dashboard.subdomain.conf.sample new file mode 100644 index 0000000..3f3e57b --- /dev/null +++ b/root/dashboard/dashboard.subdomain.conf.sample @@ -0,0 +1,45 @@ +## Version 2022/01/12 +# Make sure that your dns has a cname set for dashboard + +server { + listen 443 ssl; + listen [::]:443 ssl; + + server_name dashboard.*; + + root /dashboard/www; + index index.php; + + include /config/nginx/ssl.conf; + + client_max_body_size 0; + + # enable for ldap auth, fill in ldap details in ldap.conf + #include /config/nginx/ldap.conf; + + # enable for Authelia + #include /config/nginx/authelia-server.conf; + + location / { + # enable the next two lines for http auth + #auth_basic "Restricted"; + #auth_basic_user_file /config/nginx/.htpasswd; + + # enable the next two lines for ldap auth + #auth_request /auth; + #error_page 401 =200 /ldaplogin; + + # enable for Authelia + #include /config/nginx/authelia-location.conf; + + allow 10.0.0.0/8; + allow 172.16.0.0/12; + allow 192.168.0.0/16; + deny all; + + fastcgi_split_path_info ^(.+\.php)(/.+)$; + fastcgi_pass 127.0.0.1:9000; + fastcgi_index index.php; + include /etc/nginx/fastcgi_params; + } +} diff --git a/root/dashboard/swag-status.py b/root/dashboard/swag-status.py new file mode 100644 index 0000000..430d06f --- /dev/null +++ b/root/dashboard/swag-status.py @@ -0,0 +1,49 @@ +import collections +import concurrent.futures +import glob +import json +import os +import re +import requests +import urllib3 + + +def find_apps(): + apps = {} + file_paths = glob.glob("/config/nginx/**/*", recursive=True) + for file_path in file_paths: + if not os.path.isfile(file_path): + continue + file = open(file_path, "r") + content = file.read() + results = re.finditer(r"(\s+)set \$upstream_app (?P\S+?);(\s+)set \$upstream_port (?P\d+);\n(\s+)set \$upstream_proto (?P\w+);", content) + for result in results: + params = result.groupdict() + app = f"{params['proto']}://{params['name']}:{params['port']}" + if app not in apps: + apps[app] = set() + if not file_path.endswith(".sample"): + apps[app].add(file_path) + return apps + + +def is_available(url): + try: + ans = requests.head(url, timeout=5, verify=False) + return ans.status_code < 404 + except: + return False + +urllib3.disable_warnings() +apps = find_apps() +discovered_apps = collections.defaultdict(dict) +with concurrent.futures.ThreadPoolExecutor(max_workers=100) as executor: + futures = {executor.submit(is_available, app): app for app in apps.keys()} + for future in concurrent.futures.as_completed(futures): + app = futures[future] + if not future.result() and not apps[app]: + continue + discovered_apps[app]["status"] = future.result() + discovered_apps[app]["locations"] = list(apps[app]) + +print(json.dumps(discovered_apps, sort_keys=True)) \ No newline at end of file diff --git a/root/dashboard/www/index.php b/root/dashboard/www/index.php new file mode 100644 index 0000000..45a141f --- /dev/null +++ b/root/dashboard/www/index.php @@ -0,0 +1,87 @@ + $data){ + $tr_class = ($index % 2 == 0) ? 'shaded' : ''; + $status .= ''.$result.''; + if ($data->status == 1) { + $status .= ''; + } else { + $status .= ''; + } + $status .= ''; + if (!empty($data->locations)) { + $locations = $data->locations; + $location = implode(",", $locations); + $status .= ''.$location.''; + } else { + $status .= ''; + } + $status .= ''; + $index++; + } + return << + .status-div { + display: inline-block; + } + .status-text { + font-size: 15px; + } + td { + padding: 6px; + text-align: center; + } + .align-td { + text-align: center; + } + .green-circle { + padding: 2px 10px; + border-radius: 100%; + background-color: green; + border: 1px solid black; + } + .red-circle { + padding: 2px 10px; + border-radius: 50%; + background-color: red; + border: 1px solid black; + } + +

Welcome to your SWAG instance

+

A webserver and reverse proxy solution brought to you by linuxserver.io with php support and a built-in Certbot client.

+

We have an article on how to use swag here: docs.linuxserver.io

+

For help and support, please visit: linuxserver.io/support

+
+
+ + + + + + + + + + + + + + + {$status} + +

Application

Available

Proxied

Location

+
+
+
+
+
+ HTML; + } + $access = shell_exec("cat /config/log/nginx/access.log | goaccess -a -o html --html-prefs='{\"theme\":\"darkGray\"}' --log-format COMBINED --geoip-database=/config/geoip2db/GeoLite2-City.mmdb -"); + $status = GetStatus(); + echo str_replace("
", $status, $access); +?> diff --git a/root/etc/cont-init.d/98-dashboard-config b/root/etc/cont-init.d/98-dashboard-config new file mode 100644 index 0000000..b4f7561 --- /dev/null +++ b/root/etc/cont-init.d/98-dashboard-config @@ -0,0 +1,8 @@ +#!/usr/bin/with-contenv bash + +echo "Applying the SWAG dashboard mod..." + +apk add --no-cache --upgrade goaccess +cp -f /dashboard/dashboard.subdomain.conf.sample /config/nginx/proxy-confs/ + +echo "Applied the SWAG dashboard mod" diff --git a/root/etc/cont-init.d/98-vpn-config b/root/etc/cont-init.d/98-vpn-config deleted file mode 100644 index a5f9127..0000000 --- a/root/etc/cont-init.d/98-vpn-config +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/with-contenv bash - -# Determine if setup is needed -if [ ! -f /usr/local/lib/python***/dist-packages/sshuttle ] && \ -[ -f /usr/bin/apt ]; then - ## Ubuntu - apt-get update - apt-get install --no-install-recommends -y \ - iptables \ - openssh-client \ - python3 \ - python3-pip - pip3 install sshuttle -fi -if [ ! -f /usr/lib/python***/site-packages/sshuttle ] && \ -[ -f /sbin/apk ]; then - # Alpine - apk add --no-cache \ - iptables \ - openssh \ - py3-pip \ - python3 - pip3 install sshuttle -fi - -chown -R root:root /root -chmod -R 600 /root/.ssh diff --git a/root/etc/services.d/sshvpn/run b/root/etc/services.d/sshvpn/run deleted file mode 100644 index 7d49e79..0000000 --- a/root/etc/services.d/sshvpn/run +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/with-contenv bash - -sshuttle --dns --remote root@${HOST}:${PORT} 0/0 -x 172.17.0.0/16