diff --git a/.gitignore b/.gitignore index 03e9ceb..364aaa4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,15 @@ -.env.local -_traefik.dynamic/tls -_traefik.dynamic/shared/acme.json -**/app.env -ddns-updater/config.json +# These will be a local sym-link +*.local +*.local.yml +# local env should not be committed +app.env +# local data should always be in a subdir named local, and never committed +**/local +# traefik/tls and /sahred shouldn't exist, but in case they are copied over - don't commit them +_traefik/tls +_traefik/shared +# make it eash to disable stuff without committing +tmp.* +*.tmp +*.off + diff --git a/_bin/checkver.sh b/_bin/checkver.sh new file mode 100755 index 0000000..ebcfe5e --- /dev/null +++ b/_bin/checkver.sh @@ -0,0 +1,49 @@ +#! /usr/bin/env bash +SCRIPT_DIR=${SCRIPT_DIR:-"$( cd -- "$( dirname -- "$0" )" &> /dev/null && pwd )"} + +# Function to compare semantic versions +compare_major_version() { + local major_version1=$(echo $1 | cut -d. -f1) + local major_version2=$(echo $2 | cut -d. -f1) + + if [[ "$major_version1" == "$major_version2" ]]; then + return 0 + else + return 1 + fi +} + +# Get Current Version of Runtipi +runtipi_path=${RUNTIPI_DIR:-"$(cd -- "${SCRIPT_DIR}/../.." &> /dev/null && pwd )"} +[ -r "$runtipi_path/VERSION" ] || runtipi_path=${RUNTIPI_DIR:-"$(cd -- "${SCRIPT_DIR}/../../_" &> /dev/null && pwd )"} +current_version=$(cat "$runtipi_path/VERSION") + +# Get the latest release information from GitHub API +latest_release=$(curl -sL \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + https://api.github.com/repos/runtipi/runtipi/releases/latest) + +# Extract the tag name from the release information +tag_name=$(echo "$latest_release" | grep -o '"tag_name": "[^"]*' | cut -d'"' -f4) + +printf 'current: %-10s online: %-10s\n' "$current_version" "$tag_name" >&2 +# Compare major version numbers +compare_major_version "$tag_name" "$current_version" +# major_version_match=$? +# +# # Check if major versions are the same and if the latest release is newer than the current version +# if [[ $major_version_match -eq 0 ]] && [[ "$tag_name" > "$current_version" ]]; then +# echo "A new release is available: $tag_name" +# cd $runtipi_path +# echo "Backing up current version" +# if [ ! -d "$runtipi_path/backups" ]; then +# mkdir -p $runtipi_path/backups +# fi +# tar -czvf runtipi-backup-$current_version.tar.gz --exclude=media --exclude=backups * +# mv runtipi-backup-$current_version.tar.gz $runtipi_path/backups +# echo "Starting update" +# echo $runtipi_path/runtipi-cli update latest +# else +# echo "No new release found or major version mismatch" +# fi diff --git a/_bin/runtipictl b/_bin/runtipictl index 102d0ef..f760ca2 100755 --- a/_bin/runtipictl +++ b/_bin/runtipictl @@ -6,6 +6,12 @@ jlmkr () { JAIL_UID=${JAIL_UID:-${UID}} +jlmkr-shell() { + if jlmkr exec runtipi true; then + jlmkr shell --uid "${JAIL_UID}" runtipi + fi +} + jlmkr-exec () { local set_x=" set -x; pwd; id; " [ -z "$QUIET" ] || set_x="" @@ -83,6 +89,9 @@ case "${1}" in _ERROR_MSG="ERROR: failed to invoke a command inside the runtipi jail and can't start the jail." \ runtipi-cli start --env-file user-config/.env.local --no-permissions ;; + shell) + jlmkr-shell + ;; exec) jlmkr-exec "${@:2}" ;; @@ -124,8 +133,12 @@ case "${1}" in "" "" "" \ "misc." "" ""\ "" "exec" "execute within the shell, START_DIR env applies" \ + "" "shell" "enter an insteractive shell" \ "" "" "" \ - "" "setup" "setup runtipictl in user's .local/bin dir" + "" "setup" "setup runtipictl in user's .local/bin dir" \ + "" "" "" \ + "Related env. vars:" "" "" \ + "" "VISUAL EDITOR JAIL_UID QUIET START_DIR ROOT_EXEC" "" ;; esac diff --git a/_traefik.dynamic/dynamic/kasm-workspaces.yml b/_traefik.dynamic/dynamic/kasm-workspaces.yml deleted file mode 100644 index 3d478bb..0000000 --- a/_traefik.dynamic/dynamic/kasm-workspaces.yml +++ /dev/null @@ -1,42 +0,0 @@ -# http routing section -http: - routers: - # Define a connection between requests and services - "to-kasm-main": - rule: "Host(`k.szk.li`)" - entrypoints: - - websecure - # # If the rule matches, applies the middleware - middlewares: - - authentik_sysmgr - # - test-user - # If the rule matches, forward to the whoami service (declared below) - service: kasm-main - tls: - certresolver: myresolver - - # Define a connection between requests and services - "to-kasm-setup": - rule: "Host(`ksetup.szk.li`)" - entrypoints: - - websecure - # # If the rule matches, applies the middleware - middlewares: - - authentik_sysmgr - # - test-user - # If the rule matches, forward to the whoami service (declared below) - service: kasm-setup - tls: - certresolver: myresolver - - - services: - # Define how to reach an existing service on our infrastructure - kasm-main: - loadBalancer: - servers: - - url: "https://kasm-workspaces:8744" - kasm-setup: - loadBalancer: - servers: - - url: "https://kasm-workspaces:8743" diff --git a/_traefik.dynamic/dynamic/kateryna_apps.yml b/_traefik.dynamic/dynamic/kateryna_apps.yml deleted file mode 100644 index aaf1d10..0000000 --- a/_traefik.dynamic/dynamic/kateryna_apps.yml +++ /dev/null @@ -1,29 +0,0 @@ -# http routing section -http: - routers: - to-kateryna: - rule: "Host(`kateryna.szk.li`) - || Host(`kateryna.lksz.me`) - || Host(`m.lksz.me`) - || Host(`auth.lksz.me`) - || Host(`sync.lksz.me`) - || Host(`radarr.lksz.me`) - || Host(`sonarr.lksz.me`) - || Host(`prowlarr.lksz.me`) - || Host(`req.lksz.me`) - || Host(`jd.lksz.me`) - || Host(`nzb.lksz.me`) - || Host(`stats.player.lksz.me`) - " - entrypoints: - - websecure - service: kateryna-traefik - tls: - certresolver: myresolver - - services: - # Define how to reach an existing service on our infrastructure - kateryna-traefik: - loadBalancer: - servers: - - url: https://kateryna.lksz.me diff --git a/_traefik.dynamic/traefik.yml b/_traefik.dynamic/traefik.yml deleted file mode 100644 index 7c8216f..0000000 --- a/_traefik.dynamic/traefik.yml +++ /dev/null @@ -1,42 +0,0 @@ -api: - dashboard: true - insecure: true - -providers: - docker: - endpoint: 'unix:///var/run/docker.sock' - watch: true - exposedByDefault: false - file: - directory: /etc/traefik/dynamic - watch: true - -entryPoints: - web: - address: ':80' - forwardedHeaders: - trustedIPs: - - "127.0.0.1/32" - - "172.16.0.0/12" - http: - redirections: - entryPoint: - to: 'websecure' - scheme: 'https' - websecure: - address: ':443' - forwardedHeaders: - trustedIPs: - - "127.0.0.1/32" - - "172.16.0.0/12" - -certificatesResolvers: - httpresolver: - acme: -# email: acme@thisprops.com - storage: /shared/acme.json - httpChallenge: - entryPoint: web - -log: - level: ERROR diff --git a/_traefik/dynamic/_templates/mw.fwd-auth-sysmgr.yml.shefet b/_traefik/dynamic/_templates/mw.fwd-auth-sysmgr.yml.shefet new file mode 100644 index 0000000..c2a0f57 --- /dev/null +++ b/_traefik/dynamic/_templates/mw.fwd-auth-sysmgr.yml.shefet @@ -0,0 +1,19 @@ +http: + middlewares: + authentik_sysmgr: + forwardAuth: + address: https://auth.shefet.net/outpost.goauthentik.io/auth/traefik + trustForwardHeader: true + authResponseHeadersRegex: "^[Xx]-[Aa]uthentik" + # authResponseHeaders: + # - X-authentik-username + # - X-authentik-groups + # - X-authentik-email + # - X-authentik-name + # - X-authentik-uid + # - X-authentik-jwt + # - X-authentik-meta-jwks + # - X-authentik-meta-outpost + # - X-authentik-meta-provider + # - X-authentik-meta-app + # - X-authentik-meta-version \ No newline at end of file diff --git a/_traefik.dynamic/dynamic/fwd-auth-sysmgr.yml b/_traefik/dynamic/_templates/mw.fwd-auth-sysmgr.yml.sz similarity index 100% rename from _traefik.dynamic/dynamic/fwd-auth-sysmgr.yml rename to _traefik/dynamic/_templates/mw.fwd-auth-sysmgr.yml.sz diff --git a/_traefik/dynamic/_templates/rt.ha.yml.shefet b/_traefik/dynamic/_templates/rt.ha.yml.shefet new file mode 100644 index 0000000..774b6ea --- /dev/null +++ b/_traefik/dynamic/_templates/rt.ha.yml.shefet @@ -0,0 +1,23 @@ +# http routing section +http: + routers: + # Define a connection between requests and services + home-assistant: + rule: "Host(`ha.shefet.net`)" + entrypoints: + - websecure + # # If the rule matches, applies the middleware + # middlewares: + # - test-user + # If the rule matches, forward to the whoami service (declared below) + service: home-assistant + tls: + certresolver: myresolver + + services: + # Define how to reach an existing service on our infrastructure + home-assistant: + loadBalancer: + servers: + - url: "http://ha.lan:8123" + #- address: "ha.lan:8123" diff --git a/_traefik.dynamic/dynamic/ha.yml b/_traefik/dynamic/_templates/rt.ha.yml.sz similarity index 96% rename from _traefik.dynamic/dynamic/ha.yml rename to _traefik/dynamic/_templates/rt.ha.yml.sz index 82ad8e7..66ce575 100644 --- a/_traefik.dynamic/dynamic/ha.yml +++ b/_traefik/dynamic/_templates/rt.ha.yml.sz @@ -2,7 +2,7 @@ http: routers: # Define a connection between requests and services - "to-ha": + home-assistant: rule: "Host(`ha.lksz.me`)" entrypoints: - websecure diff --git a/_traefik/dynamic/http.yml b/_traefik/dynamic/http.yml new file mode 100644 index 0000000..ef2bee2 --- /dev/null +++ b/_traefik/dynamic/http.yml @@ -0,0 +1,4 @@ +http: + serversTransports: + insecuretransport: + insecureSkipVerify: true diff --git a/_traefik/dynamic/mw.lan-only.yml b/_traefik/dynamic/mw.lan-only.yml new file mode 100644 index 0000000..0cab8f0 --- /dev/null +++ b/_traefik/dynamic/mw.lan-only.yml @@ -0,0 +1,8 @@ +# Accepts request from defined IP +http: + middlewares: + lan-only: + ipWhiteList: + sourceRange: + - "127.0.0.1/32" + - "192.168.0.0/16" \ No newline at end of file diff --git a/_traefik.dynamic/dynamic/dynamic.yml b/_traefik/dynamic/mw.secureHeaders.yml similarity index 63% rename from _traefik.dynamic/dynamic/dynamic.yml rename to _traefik/dynamic/mw.secureHeaders.yml index 18769aa..3ca24bc 100644 --- a/_traefik.dynamic/dynamic/dynamic.yml +++ b/_traefik/dynamic/mw.secureHeaders.yml @@ -1,8 +1,4 @@ http: - serversTransports: - insecuretransport: - insecureSkipVerify: true - middlewares: secureHeaders: headers: @@ -18,14 +14,3 @@ http: permissionsPolicy: "camera=(), microphone=(), geolocation=()" customResponseHeaders: X-Robots-Tag: "noindex,nofollow,nosnippet,noarchive,notranslate,noimageindex" - -tls: - stores: - default: - defaultCertificate: - certFile: /etc/traefik/tls/cert.pem - keyFile: /etc/traefik/tls/key.pem - certificates: - - certFile: /etc/traefik/tls/cert.pem - keyFile: /etc/traefik/tls/key.pem - diff --git a/_traefik/dynamic/tls.yml b/_traefik/dynamic/tls.yml new file mode 100644 index 0000000..39b4586 --- /dev/null +++ b/_traefik/dynamic/tls.yml @@ -0,0 +1,9 @@ +tls: + stores: + default: + defaultCertificate: + certFile: /etc/traefik/tls/cert.pem + keyFile: /etc/traefik/tls/key.pem + certificates: + - certFile: /etc/traefik/tls/cert.pem + keyFile: /etc/traefik/tls/key.pem diff --git a/_traefik/static.yml b/_traefik/static.yml new file mode 100644 index 0000000..f7ead6f --- /dev/null +++ b/_traefik/static.yml @@ -0,0 +1,48 @@ + # log: + # level: INFO + + api: + dashboard: true + insecure: true + + providers: + docker: + endpoint: "unix:///var/run/docker.sock" + watch: true + exposedByDefault: false + file: + directory: /srv/traefik/dynamic + watch: true + + entryPoints: + web: + address: ':80' + forwardedHeaders: + trustedIPs: + - "127.0.0.1/32" + - "172.16.0.0/12" + http: + redirections: + entryPoint: + to: 'websecure' + scheme: 'https' + websecure: + address: ':443' + forwardedHeaders: + trustedIPs: + - "127.0.0.1/32" + - "172.16.0.0/12" + + certificatesResolvers: + myresolver: + acme: + # email: acme@thisprops.com + storage: /shared/acme.json + # httpChallenge: + # entryPoint: web + #logging: true + dnsChallenge: + provider: cloudflare + resolvers: + - 1.1.1.1:53 # - --certificatesresolvers.cloudflare.acme.dnschallenge.resolvers[0]=1.1.1.1:53 + - 8.8.8.8:53 # - --certificatesresolvers.cloudflare.acme.dnschallenge.resolvers[1]=8.8.8.8:53 \ No newline at end of file diff --git a/szetup.sh b/szetup.sh new file mode 100755 index 0000000..bbc4988 --- /dev/null +++ b/szetup.sh @@ -0,0 +1,35 @@ +#! /usr/bin/env bash +set -e +SCRIPT_DIR=${SCRIPT_DIR:-"$( cd -- "$( dirname -- "$0" )" &> /dev/null && pwd )"} + +SYS_NAME=${1:-${SYS_NAME:?Must supply sysname as 1st argument}} +TOP_DIR="$SCRIPT_DIR/_traefik/dynamic" + +# Store the find results in an array +mapfile -d '' -t DELETE < <(find "$TOP_DIR" -maxdepth 1 -mindepth 1 -type l -lname '*_templates/*' -print0) + +# If links were found, process and delete them +if [ ${#DELETE[@]} -gt 0 ]; then + for link in "${DELETE[@]}"; do + # Get the target of the symbolic link + target=$(basename $(readlink -f "$link")) + + # Delete the link + rm "$link" + + # Report the deleted link and its target + printf '"%s" (%s) deleted.\n' "$link" "${target##*.}" + done +else + echo "No matching symbolic links found to delete." +fi + + +find "$TOP_DIR/_templates" -maxdepth 1 -mindepth 1 -type f -name "*.${SYS_NAME}" -print0 \ +| while IFS= read -r -d '' file; do + base=$(basename "$file" ".${SYS_NAME}") + ext="${base##*.}" + #echo ln -rs "${file#${TOP_DIR}/}" "${base}" + ln -vrs "${file}" "${TOP_DIR}/${base%${ext}}local.$ext" +done + diff --git a/tipi-compose.yml b/tipi-compose.yml index c25c122..71e87d0 100644 --- a/tipi-compose.yml +++ b/tipi-compose.yml @@ -1,16 +1,37 @@ services: runtipi-reverse-proxy: + volumes: + - type: bind + source: ./traefik/shared + target: /shared + read_only: false + - type: bind + source: ./traefik + target: /srv/traefik + read_only: false + - type: bind + source: ./user-config/_traefik/dynamic/ + target: /srv/traefik/dynamic/ + read_only: true + - type: bind + source: ./user-config/_traefik/static.yml + target: /srv/traefik/static.yml + read_only: true + logging: + driver: "json-file" + options: + max-size: "2m" + max-file: "3" ports: - 8080:8080 - command: - - '--providers.docker' - - '--providers.file.directory=/srv/runtipi/user-config/_traefik.dynamic' + command: + - '--log.level=DEBUG' + - '--configFile=/srv/traefik/static.yml' - '--certificatesresolvers.myresolver.acme.email=${ACME_EMAIL}' - - '--certificatesresolvers.myresolver.acme.storage=/shared/acme.json' - - '--certificatesresolvers.myresolver.acme.dnschallenge.provider=cloudflare' environment: - CF_API_EMAIL: "${ACME_EMAIL}" - CF_DNS_API_TOKEN: "${CF_DNS_API_TOKEN}" + CF_API_EMAIL: "${ACME_EMAIL:?}" + CF_DNS_API_TOKEN: "${CF_DNS_API_TOKEN:?}" + TRAEFIK_API_DISABLEDASHBOARDAD: "true" networks: - tipi_main_network - tipi_internal_network diff --git a/vaultwarden/docker-compose.yml b/vaultwarden/docker-compose.yml index b4779f3..bc9f13c 100644 --- a/vaultwarden/docker-compose.yml +++ b/vaultwarden/docker-compose.yml @@ -16,14 +16,12 @@ services: volumes: - /srv/vaultwarden/data:/data labels: - # Main - traefik.docker.network: runtipi_tipi_main_network - # # Websecure - traefik.http.routers.vaultwarden-more.rule: Host(`vault.lksz.me`)${APP_ROUTE_OPTIONAL:-} - traefik.http.routers.vaultwarden-more.entrypoints: websecure - traefik.http.routers.vaultwarden-more.service: vaultwarden - traefik.http.routers.vaultwarden-more.tls: true - traefik.http.routers.vaultwarden-more.tls.certresolver: myresolver + # Websecure + traefik.http.routers.vaultwarden.rule: Host(`www.${ROOT_DOMAIN}`)${APP_ROUTE_OPTIONAL:-} + # traefik.http.routers.vaultwarden-more.entrypoints: websecure + # traefik.http.routers.vaultwarden-more.service: vaultwarden + # traefik.http.routers.vaultwarden-more.tls: true + # traefik.http.routers.vaultwarden-more.tls.certresolver: myresolver networks: vaultwarden_pg_dockge: external: true