From c12910d0f15b2425e68186386b3540e6be52c462 Mon Sep 17 00:00:00 2001 From: root Date: Sat, 6 Jun 2026 12:42:48 -0400 Subject: [PATCH] infrastructure: move .env + CrowdSec key into org with noweb references --- infrastructure.org | 256 ++++++++++++++++++++++++++++++++++++++++++++- tangle-deploy.sh | 23 +--- 2 files changed, 258 insertions(+), 21 deletions(-) mode change 100644 => 100755 tangle-deploy.sh diff --git a/infrastructure.org b/infrastructure.org index 179acc2..72ba5b9 100644 --- a/infrastructure.org +++ b/infrastructure.org @@ -230,6 +230,11 @@ Why each piece: Shared middleware used by all routers. Defined once here, referenced by name in every router block. + +#+NAME: crowdsec_key +#+BEGIN_SRC sh :results raw :exports none +echo "Xvx3UTjAdThkqtNuVhciWzEOJuBZoWH58KE+E7C3L6I" +#+END_SRC #+BEGIN_SRC yaml :tangle /docker/appdata/traefik/dynamic.yaml http: middlewares: @@ -261,7 +266,7 @@ http: crowdsec-bouncer-traefik-plugin: enabled: "true" crowdsecMode: live - crowdsecLapiKey: __CROWDSEC_LAPI_KEY__ + crowdsecLapiKey: <> crowdsecLapiHost: crowdsec:8080 crowdsecLapiScheme: http updateFrequencySec: 5 @@ -1529,3 +1534,252 @@ http: #+END_SRC service: http://10.10.10.29:8082 middleware: tunnel-headers@file + +* Environment Variables + +Tangled to /docker/compose/.env. The CROWDSEC_LAPI_KEY is a noweb reference +to the shared crowdsec_key block, so it stays in sync with dynamic.yaml. + +#+BEGIN_SRC dotenv :tangle /docker/compose/.env +## Auto-generated from infrastructure.org -- do not edit directly. +## Edit infrastructure.org and tangle to update. + +################################################################################# +################################################################################# +################################################################################# +## +## Docker Compose Environment Variable file for Jellyfin / *ARR Media Stack +## +## Update any of the environment variables below as required. +## +## It is highly recommended Linux users set up a "docker" user, so the +## applications can access the local filesystem with this user's access +## privileges. Use PUID / PGID to map user access between the Docker apps +## and local filesystem. +## +## The MediaStack Guide is located at https://MediaStack.Guide +## +################################################################################# +################################################################################# +################################################################################# + +################################################### +## add /dev/net/tun to LXC +## https://pve.proxmox.com/wiki/OpenVPN_in_LXC +################################################### + +# Name of the project in Docker +COMPOSE_PROJECT_NAME=docker-production +COMPOSE_BAKE=true + +# This is the network subnet which will be used inside the docker "media_network", change as required. +# LOCAL_SUBNET is your home network and is needed so the VPN client allows access to your home computers. +DOCKER_SUBNET=172.28.10.0/24 +DOCKER_GATEWAY=172.28.10.1 +LOCAL_SUBNET=10.10.10.0/24 # This is the IP Subnet used on your home network +LOCAL_DOCKER_IP=10.10.10.201 # This is the IP Address of your Docker computer + +# Each of the "*ARR" applications have been configured so the theme can be changed to your needs. +# Refer to Theme Park for more info / options: https://docs.theme-park.dev/theme-options/aquamarine/ +TP_THEME=nord + +# If you intend to use Plex as your Media Server, then enter your Plex Claim +# information below, to link this Plex Media Server to your Plex account +# Access Plex claim at: https://account.plex.tv/en/claim +PLEX_CLAIM=claim-1234567890abcdef + +# These are the folders on your local host computer / NAS running docker, they MUST exist +# and have correct permissions for PUID and PGUI prior to running the docker compose. +# +# Use the commands in the Guide to create all the sub-folders in each of these folders. + +# Host Data Folders - Will accept Linux, Windows, NAS folders. +# Make sure these folders exists before running the "docker compose" command. +FOLDER_FOR_MEDIA=/library +# <-- Update for your folders - Synology Example: /volume1/media +FOLDER_FOR_DATA=/docker/appdata +# <-- Update for your folders - Synology Example: /volume1/docker/appdata +FOLDER_FOR_MORE=/more +# File access, date and time details for the containers / applications to use. +# Run "sudo id docker" on host computer to find PUID / PGID and update these to suit. +PUID=1000 +PGID=1000 +UMASK=0002 +TIMEZONE=America/New_York + +# Update your own Internet VPN provide details below +# Online documentation: https://github.com/qdm12/gluetun-wiki/tree/main/setup/providers +VPN_TYPE=openvpn +VPN_SERVICE_PROVIDER=privado +VPN_USERNAME=nhmpxamumlrj +VPN_PASSWORD=ulm8kRtJdmFLAum3tEb + +# You MUST provide at least one entry to the SERVER variables below, that supports your VPN provider's settings. +# If you want to add more than one entry per line, use comma separated values: "one,two,three" etc... +SERVER_COUNTRIES=Netherlands +SERVER_REGIONS= +SERVER_CITIES= +SERVER_HOSTNAMES= +SERVER_CATEGORIES= + +# Fill in this item ONLY if you're using a custom OpenVPN configuration +# Should be inside gluetun data folder - Example: /gluetun/custom-openvpn.conf +# You can then edit it inside the FOLDER_FOR_DATA location for gluetun. +OPENVPN_CUSTOM_CONFIG= +GLUETUN_CONTROL_PORT=8320 + +# Fill in these items ONLY if you change VPN_TYPE to "wireguard" +VPN_ENDPOINT_IP= +VPN_ENDPOINT_PORT= +WIREGUARD_PUBLIC_KEY= +WIREGUARD_PRIVATE_KEY= +WIREGUARD_PRESHARED_KEY= +WIREGUARD_ADDRESSES= + +# These are the ports used to access each of the applications in your web browser. +# You can safely change these if you need, but they can't conflict with other active ports. +QBIT_PORT=6881 +FLARESOLVERR_PORT=8191 +TDARR_SERVER_PORT=8266 + +# WebUI ports for internal access to applications +WEBUI_PORT_AUDIOBOOKSHELF=13378 +WEBUI_PORT_AUTHENTIK=6080 +WEBUI_PORT_BAZARR=6767 +WEBUI_PORT_CHROMIUM=3650 +WEBUI_PORT_DDNS_UPDATER=8310 +WEBUI_PORT_FILEBOT=5454 +WEBUI_PORT_GUACAMOLE=9200 +WEBUI_PORT_GRAFANA=3800 +WEBUI_PORT_HEADPLANE=3500 +WEBUI_PORT_HEIMDALL=2080 +WEBUI_PORT_HOMARR=3200 +WEBUI_PORT_HOMEPAGE=3000 +WEBUI_PORT_HUNTARR=9705 +WEBUI_PORT_JELLYFIN=8096 +WEBUI_PORT_JELLYSEERR=5055 +WEBUI_PORT_LAZYLIBRARIAN=5299 +WEBUI_PORT_LIDARR=8686 +WEBUI_PORT_MYLAR=8090 +WEBUI_PORT_PLEX=32400 +WEBUI_PORT_PORTAINER=9000 +WEBUI_PORT_PROMETHEUS=9090 +WEBUI_PORT_PROWLARR=9696 +WEBUI_PORT_QBITTORRENT=8200 +WEBUI_PORT_RADARR=7878 +WEBUI_PORT_READARR=8787 +WEBUI_PORT_SABNZBD=8100 +WEBUI_PORT_SONARR=8989 +WEBUI_PORT_STASH=7777 +WEBUI_PORT_TDARR=8265 +WEBUI_PORT_TRAEFIK=8080 +WEBUI_PORT_WHISPARR=6969 + +CHROMIUM_START_PAGE="https://github.com/geekau/mediastack/" + +# Traefik is configured for Reverse Proxy. Set your Internet gateway to redirect incoming ports 80 and 443 +# to the ports used below (using Docker IP Address), and they will be translated back to 80 and 443 by Traefik. +# Change these port numbers if you have conflicting services running on the Docker host computer. +# If ports 80 and 443 are already used, then adjust and redirect incoming ports to 5080 and 5443, or similar. + +REVERSE_PROXY_PORT_HTTP=80 +REVERSE_PROXY_PORT_HTTPS=443 + +# Traefik Configuration +# Your CloudFlare Account Email Address +CLOUDFLARE_EMAIL=gharbeia@riseup.net +# Your CloudFlare Registered Domain Name +CLOUDFLARE_DNS_ZONE=gharbeia.net +# Your CloudFlare Read / Write API Token +CLOUDFLARE_DNS_API_TOKEN=cfut_unDIAx2wqL2tm8OmcZWpzrQTRPPA5FlenlVfeL7Nf94c360b +# Headscale / Headplane / Tailscale VPN Wireguard Mesh Networking +# These port settings are only to change the internal port due to conflicts, Headscale, Tailscale and Headplane will +# all function normally using the default ports as they are routed through Traefik reverse proxy. +CONNECT_PORT_HEADSCALE=4080 +METRICS_PORT_HEADSCALE=4090 + +CROWDSEC_PORT=9080 +METRICS_PORT_TRAEFIK=8082 +INTERNAL_PORT_TRAEFIK=8083 +METRICS_PORT_UNPACKERR=5656 + +# The Tailscale Docker container is configured as an exit node inside your home network, so traffic can route securely +# across the Internet, and break out behind your home gateway / router. +# sudo docker exec -it headscale headscale users create exit-node +# sudo docker exec -it headscale headscale --user exit-node preauthkeys create +# NOTE: Headscale must be running before the commands can be executed, then update authkey below and restart Tailscale. +TAILSCALE_AUTHKEY=57332c4f29ef77727d3310a34d903ae83ccae4c6392460fc +# Connect to the following address to complete the initial setup of Authentik after first deployment: +# http://:6080/if/flow/initial-setup/ + +# echo AUTHENTIK_SECRET_KEY=$(openssl rand -base64 60 | tr -d '\n') +AUTHENTIK_SECRET_KEY=P)'K"7sF#>Ia+m-8jOyn6\]6S +AUTHENTIK_VERSION=2025.4.1 +AUTHENTIK_ERROR_REPORTING__ENABLED=true +POSTGRESQL_PORT=5432 +VALKEY_PORT=6379 + +# echo POSTGRESQL_PASSWORD=$(openssl rand -base64 60 | tr -d '\n') +POSTGRESQL_PASSWORD=1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef +POSTGRESQL_USERNAME=library-postgresql +AUTHENTIK_DATABASE=library-authentik +GUACAMOLE_DATABASE=library-guacamole +GUACD_PORT=4822 + +# SMTP Host Emails are sent to +EMAIL_SERVER_HOST=smtp.fastmail.com +EMAIL_SERVER_PORT=25 +# Optionally authenticate (don't add quotation marks to your password) +EMAIL_ADDRESS=amr@gharbeia.net +EMAIL_PASSWORD=3a58334x8a9r8x7e +# Use StartTLS +EMAIL_TLS=true +# Use SSL - StartTLS and SSL can't both be true +EMAIL_SSL=false +# Email address authentik will send from, should have a correct @domain.name +EMAIL_SENDER=authentik@gharbeia.net + +#### Gitea + +GITEA__database__DB_TYPE=sqlite3 +GITEA__database__PATH=/data/gitea/gitea.db +GITEA__server__DOMAIN=10.10.10.201 +GITEA__server__HTTP_PORT=3001 +GITEA__server__SSH_PORT=2222 +GITEA__server__ROOT_URL=http://10.10.10.201:3000/ +GITEA__security__INSTALL_LOCK=true +GITEA__service__DISABLE_REGISTRATION=false + +# ports: +# - "127.0.0.1:3000:3000" +# - "127.0.0.1:2222:22" + + + + +# Cloudflare Tunnel token for cloudflared +TUNNEL_TOKEN=eyJhIjoiYWY0Y2RkYWM0N2UwMDFmZDZkNWMyMGFjNmRkZGFkM2QiLCJ0IjoiYzI5Mjk1YzUtOTQ2YS00ZGRmLWJkZmUtN2VhZmNkNzRmYWEzIiwicyI6Ik5qQm1aVEV4TjJFdFptRTFPUzAwTjJWbUxUZ3pORE10TURKa1lqRXhNMlptT1RVNCJ9 + +# Tube Archivist +TA_USERNAME=admin +TA_PASSWORD=DsO1BPfMEXMJROG9NlgEslOd +WEBUI_PORT_AUDIOMUSE=8005 + +# khaledfahmy.org +KHALEDFAHMY_DB_ROOT_PASSWORD=kf_root_ch4ng3_m3 +KHALEDFAHMY_DB_PASSWORD=t1)~Bt~1uwmwe?pq}sZj%b!t8 + +# Nancy Okail (WordPress) +NANCYOKAIL_DB_ROOT_PASSWORD=changeme_placeholder +NANCYOKAIL_DB_PASSWORD=changeme_placeholder + +# Rim Naguib (WordPress) +RIMNAGUIB_DB_ROOT_PASSWORD=changeme_placeholder +RIMNAGUIB_DB_PASSWORD=changeme_placeholder + +# Fishere (WordPress) +FISHERE_DB_ROOT_PASSWORD=changeme_placeholder +FISHERE_DB_PASSWORD=changeme_placeholder +CROWDSEC_LAPI_KEY=<> + +#+END_SRC diff --git a/tangle-deploy.sh b/tangle-deploy.sh old mode 100644 new mode 100755 index e19d36c..344f0ab --- a/tangle-deploy.sh +++ b/tangle-deploy.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +# tangle-deploy — Tangle infrastructure.org and restart affected services GITEA_URL='ssh://git@git.gharbeia.net:2222/amr/infrastructure.git' REPO_DIR="${1:-/docker/compose/infrastructure}" ORG_FILE="${REPO_DIR}/infrastructure.org" @@ -16,15 +17,8 @@ fi echo "=== Tangling $ORG_FILE ===" emacs --batch -Q --load /usr/share/emacs/28.2/lisp/org/org-loaddefs.el \ --eval "(require 'org)" \ - --eval "(org-babel-tangle-file \"$ORG_FILE\")" 2>&1 -# Substitute env vars in tangled files -# Read key from .env directly (avoid sourcing due to quoting issues in other vars) -CROWDSEC_LAPI_KEY=$(grep ^CROWDSEC_LAPI_KEY /docker/compose/.env | cut -d= -f2-) -if [ -z "$CROWDSEC_LAPI_KEY" ] || [ "$CROWDSEC_LAPI_KEY" = "__CROWDSEC_LAPI_KEY__" ]; then - echo "ERROR: CROWDSEC_LAPI_KEY not set or still a placeholder in .env!" - exit 1 -fi -sed -i "s|__CROWDSEC_LAPI_KEY__|${CROWDSEC_LAPI_KEY}|g" /docker/appdata/traefik/dynamic.yaml + --eval "(require 'ob-shell)" \ + --eval '(let ((org-confirm-babel-evaluate nil)) (org-babel-tangle-file "'"$ORG_FILE"'"))' 2>&1 echo "=== Restarting services ===" cd /docker/compose if [ -f /docker/appdata/traefik/traefik.yaml ] || \ @@ -33,17 +27,6 @@ if [ -f /docker/appdata/traefik/traefik.yaml ] || \ [ -f /docker/appdata/traefik/dynamic.yaml ]; then echo 'Traefik config changed -- restarting...' docker compose up -d traefik - # Verify CrowdSec bouncer is working after restart - sleep 2 - STATUS=$(docker exec traefik wget -q -O /dev/null -S http://traefik:8081/application/o/authorize/ --header="Host: auth.gharbeia.net" 2>&1 | head -1 | awk '{print $2}') - if [ "$STATUS" = "403" ]; then - echo "WARNING: auth.gharbeia.net still returns 403 after deploy!" - echo " CrowdSec bouncer may have a bad API key." - echo " Run: docker exec crowdsec cscli bouncers add traefik-bouncer" - echo " Then update CROWDSEC_LAPI_KEY in /docker/compose/.env and re-deploy." - else - echo "OK: auth.gharbeia.net returns $STATUS (expected: 400)" - fi fi if [ -f /docker/compose/docker-compose.yaml ]; then echo 'Docker compose changed -- restarting all services'