From 2ae84f44816b4027e73028f5beb0cf5899ab0b8d Mon Sep 17 00:00:00 2001 From: aki Date: Sat, 26 Apr 2025 14:10:11 +0800 Subject: [PATCH] feat(setup): Enhance update script and add user database example --- .gitignore | 2 +- README.md | 105 ++--- ...atabase.yml => users_database.example.yml} | 0 docker-compose.yml | 4 - update-setup.sh | 424 +++++++++++------- 5 files changed, 307 insertions(+), 228 deletions(-) rename authelia/{users_database.yml => users_database.example.yml} (100%) diff --git a/.gitignore b/.gitignore index 668d112..8f0724e 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,7 @@ .idea docker-compose.override.yml /authelia/*.yml -!/authelia/configuration.example.yml +!/authelia/*.example.yml /homepage/logs /homepage/*.yaml /homepage/*.css diff --git a/README.md b/README.md index 51f6632..bf0df5e 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ The core idea is to manage media libraries (movies, TV shows, music), automate d - [(Optional) VPN Configuration](#optional-vpn-configuration) - [(Optional) Traefik DNS Challenge](#optional-traefik-dns-challenge) - [Service Access](#service-access) + - [Setup Script Commands (`update-setup.sh`)](#setup-script-commands-update-setupsh) - [Managing Service Authentication](#managing-service-authentication) - [Optional Services](#optional-services) - [Troubleshooting](#troubleshooting) @@ -169,13 +170,15 @@ After completing all [Required Setup Steps](#required-setup-steps) above, follow # Make the script executable chmod +x ./update-setup.sh - # Run the setup tool - ./update-setup.sh + # Run the setup tool (use 'all' for initial setup) + ./update-setup.sh all ``` - This interactive script will guide you through: - - Updating your `.env` file while preserving existing values - - Configuring Authelia with your Tailscale domain settings - - Setting up service configurations and retrieving API keys + This script will: + - Update your `.env` file while preserving existing values (`update-env`). + - Configure Authelia with your Tailscale domain settings (`update-authelia`). + - Set up service configurations and retrieve API keys (`update-services`). + + You can also run individual commands like `./update-setup.sh update-authelia`. Run `./update-setup.sh help` for all options. 5. **Start the Stack:** ```bash @@ -327,21 +330,19 @@ Authelia uses the `authelia/users_database.yml` file to manage users. groups: - users # Add to 'admins' group if needed ``` - 4. Save the file. Authelia should pick up the changes automatically (or restart the Authelia container: `docker compose restart authelia`). + 4. Save the file and restart Authelia: `docker compose restart authelia`. + +* **Adding/Updating Users (Recommended Method):** + Use the setup script's interactive tool: + ```bash + ./update-setup.sh manage-accounts + ``` + This script handles password hashing and file formatting, reducing the chance of errors. It will prompt you for the username, display name, email, and groups, then generate a secure password hash. * **Enabling User Registration (Optional):** 1. Edit `authelia/configuration.yml`. 2. Find the commented-out `registration:` section near the bottom. - 3. Uncomment it and set `enable: true`: - ```yaml - # registration: - # enable: false # Set to true to enable registration form - ``` - becomes: - ```yaml - registration: - enable: true - ``` + 3. Uncomment it and set `enable: true`. 4. Save the file and restart Authelia (`docker compose restart authelia`). 5. A "Register" link will now appear on the Authelia login page. @@ -376,43 +377,43 @@ Replace `` with your Tailscale device name (e.g., `tailscale-nas If you configure DNS for your `APP_HOSTNAME` variable to point to the Tailscale IP, you can use `https:///`. +### Setup Script Commands (`update-setup.sh`) + +The `update-setup.sh` script provides various commands to manage your configuration. Run `./update-setup.sh help` to see all options. + +**Core Setup & Updates:** + +* `./update-setup.sh update-env`: Updates `.env` from `.env.example`, preserving existing values and highlighting new/deprecated keys. +* `./update-setup.sh update-authelia`: Updates `authelia/configuration.yml` from the example, applying domain settings from `.env` and attempting to preserve secrets (uses `yq` if available). +* `./update-setup.sh update-services`: Updates configurations for running *arr/qBittorrent/Bazarr containers (sets URL base, extracts API keys to `.env`). Restarts affected containers. +* `./update-setup.sh all`: Runs `update-env`, `update-authelia`, and `update-services` sequentially. Recommended for initial setup and major updates. + +**Authentication Management:** + +* `./update-setup.sh list-auth`: Lists all detected services in `docker-compose.yml` and shows whether Authelia authentication is enabled or disabled for them. +* `./update-setup.sh enable-auth `: Enables Authelia authentication for the specified `` by adding the `authelia-auth@docker` middleware label in `docker-compose.yml`. +* `./update-setup.sh disable-auth `: Disables Authelia authentication for the specified `` by removing the `authelia-auth@docker` middleware label. +* `./update-setup.sh enable-all-auth`: Attempts to enable authentication for all applicable services. +* `./update-setup.sh disable-all-auth`: Attempts to disable authentication for all applicable services. + +> **Important:** After using `enable-auth`, `disable-auth`, `enable-all-auth`, or `disable-all-auth`, you **must** restart your stack for the changes to take effect: +> ```bash +> docker compose down +> docker compose up -d +> ``` + +**User & File Management:** + +* `./update-setup.sh manage-accounts`: Starts an interactive tool to add or update users in `authelia/users_database.yml`. It generates password hashes and prompts for user details. +* `./update-setup.sh cleanup`: Interactively finds and deletes old backup files (`.bak`) created by the script. Allows keeping the most recent backup of each type. + +**Help:** + +* `./update-setup.sh help`: Displays the full list of commands and usage instructions. + ### Managing Service Authentication -You can control which services require authentication using the updated `update-setup.sh` script: - -```bash -# List all services and their authentication status -./update-setup.sh list-auth - -# Disable authentication for Jellyfin (no login required) -./update-setup.sh disable-auth jellyfin - -# Enable authentication for Jellyfin (login required) -./update-setup.sh enable-auth jellyfin - -# Disable authentication for all services -./update-setup.sh disable-all-auth - -# Enable authentication for all services -./update-setup.sh enable-all-auth - -# Clean up backup files (keeps most recent by default) -./update-setup.sh cleanup - -# View all available commands -./update-setup.sh help -``` - -You can also manage authentication through the interactive menu by running `./update-setup.sh` and selecting option 5. - -After making changes, restart your stack for the changes to take effect: - -```bash -docker compose down -docker compose up -d -``` - -This approach gives you complete control over which services require authentication, without needing to manually edit configuration files. +Use the `update-setup.sh` script to easily control which services require Authelia login. See the `Authentication Management` commands in the [Setup Script Commands](#setup-script-commands-update-setupsh) section above for details. ## Optional Services diff --git a/authelia/users_database.yml b/authelia/users_database.example.yml similarity index 100% rename from authelia/users_database.yml rename to authelia/users_database.example.yml diff --git a/docker-compose.yml b/docker-compose.yml index 6f50a10..1aa9001 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -15,7 +15,6 @@ services: - --experimental.plugins.rewriteHeaders.version=v0.0.3 - --providers.docker.network=docker-compose-nas - --providers.docker.endpoint=unix:///var/run/docker.sock - - --log.level=DEBUG network_mode: service:tailscale volumes: - /var/run/docker.sock:/var/run/docker.sock:ro @@ -23,9 +22,6 @@ services: test: ["CMD", "traefik", "healthcheck", "--ping"] interval: 30s retries: 10 - labels: - - traefik.enable=true - # Remove middleware definition from traefik service redis: image: redis:alpine container_name: redis diff --git a/update-setup.sh b/update-setup.sh index 2b93715..81bb742 100755 --- a/update-setup.sh +++ b/update-setup.sh @@ -211,51 +211,131 @@ update_env_file() { update_authelia_config() { print_header "Authelia Configuration Update Tool" - + # Check if files exist if ! check_file "$AUTHELIA_CONFIG_EXAMPLE"; then - echo -e "${RED}Error: Example configuration file doesn't exist${NC}" + echo -e "${RED}Error: Example configuration file '$AUTHELIA_CONFIG_EXAMPLE' doesn't exist${NC}" + return 1 + fi + if ! check_file "$ENV_FILE"; then + echo -e "${RED}Error: Environment file '$ENV_FILE' doesn't exist. Cannot retrieve domain settings.${NC}" + return 1 + fi + + # Get the tailnet domain and hostname from .env + local TAILNET_DOMAIN=$(grep -oP "^TAILSCALE_TAILNET_DOMAIN=\K.*" "$ENV_FILE" | tr -d '"' | tr -d "'") + local TAILSCALE_HOSTNAME=$(grep -oP "^TAILSCALE_HOSTNAME=\K.*" "$ENV_FILE" | tr -d '"' | tr -d "'") + local FULL_HOSTNAME="${TAILSCALE_HOSTNAME}.${TAILNET_DOMAIN}" + local WILDCARD_DOMAIN="*.${TAILNET_DOMAIN}" + + if [ -z "$TAILNET_DOMAIN" ] || [ -z "$TAILSCALE_HOSTNAME" ]; then + echo -e "${RED}Error: Could not read TAILSCALE_TAILNET_DOMAIN or TAILSCALE_HOSTNAME from $ENV_FILE${NC}" return 1 fi # If config file doesn't exist, create it from example if [ ! -f "$AUTHELIA_CONFIG" ]; then - echo -e "${YELLOW}Authelia configuration file doesn't exist, creating from example...${NC}" + echo -e "${YELLOW}Authelia configuration file '$AUTHELIA_CONFIG' doesn't exist, creating from example...${NC}" cp "$AUTHELIA_CONFIG_EXAMPLE" "$AUTHELIA_CONFIG" echo -e "${GREEN}Created new Authelia configuration file.${NC}" - return 0 - fi - - echo -e "${BLUE}This will update your Authelia configuration based on the example file${NC}" - echo -e "${BLUE}Backup will be created as: $AUTHELIA_CONFIG_BACKUP${NC}" - echo -e "${YELLOW}Continue? [y/N]:${NC}" - read -r answer - if [[ ! "$answer" =~ ^[Yy]$ ]]; then - echo -e "${RED}Authelia config update cancelled.${NC}" - return 0 - fi - - # Create backup of current config - create_backup "$AUTHELIA_CONFIG" "$AUTHELIA_CONFIG_BACKUP" - - # Copy the example file over the current one - cp "$AUTHELIA_CONFIG_EXAMPLE" "$AUTHELIA_CONFIG" - - # Get the tailnet domain from .env for proper configuration - if [ -f "$ENV_FILE" ]; then - TAILNET_DOMAIN=$(grep -o "TAILSCALE_TAILNET_DOMAIN=.*" "$ENV_FILE" | cut -d'=' -f2 | tr -d '"' | tr -d "'") - TAILSCALE_HOSTNAME=$(grep -o "TAILSCALE_HOSTNAME=.*" "$ENV_FILE" | cut -d'=' -f2 | tr -d '"' | tr -d "'") - - if [ -n "$TAILNET_DOMAIN" ] && [ -n "$TAILSCALE_HOSTNAME" ]; then - # Replace placeholders with actual values - sed -i "s/\*.ts.net/\*.$TAILNET_DOMAIN/g" "$AUTHELIA_CONFIG" - sed -i "s/tailscale-nas.ts.net/$TAILSCALE_HOSTNAME.$TAILNET_DOMAIN/g" "$AUTHELIA_CONFIG" - echo -e "${GREEN}Configured Authelia with your Tailscale domain: $TAILSCALE_HOSTNAME.$TAILNET_DOMAIN${NC}" + # Proceed to update the newly created file + else + echo -e "${BLUE}This will update your Authelia configuration '$AUTHELIA_CONFIG' based on '$AUTHELIA_CONFIG_EXAMPLE'${NC}" + echo -e "${BLUE}Your Tailscale domain settings from '$ENV_FILE' will be applied.${NC}" + echo -e "${BLUE}Backup will be created as: $AUTHELIA_CONFIG_BACKUP${NC}" + echo -e "${YELLOW}Continue? [y/N]:${NC}" + read -r answer + if [[ ! "$answer" =~ ^[Yy]$ ]]; then + echo -e "${RED}Authelia config update cancelled.${NC}" + return 0 fi + # Create backup of current config only if it exists + create_backup "$AUTHELIA_CONFIG" "$AUTHELIA_CONFIG_BACKUP" fi - + + # Check for yq + if check_yq; then + echo -e "${BLUE}Using 'yq' to update Authelia configuration...${NC}" + # Create a temporary file from the example + local TEMP_CONFIG="${AUTHELIA_CONFIG}.tmp" + cp "$AUTHELIA_CONFIG_EXAMPLE" "$TEMP_CONFIG" + + # Preserve specific existing values if the original config exists + if [ -f "$AUTHELIA_CONFIG_BACKUP" ]; then # Use backup as source of truth for existing values + echo -e "${BLUE}Attempting to preserve existing secrets and notifier settings...${NC}" + local existing_jwt_secret=$(yq e '.identity_validation.reset_password.jwt_secret // ""' "$AUTHELIA_CONFIG_BACKUP") + local existing_session_secret=$(yq e '.session.secret // ""' "$AUTHELIA_CONFIG_BACKUP") + local existing_storage_key=$(yq e '.storage.encryption_key // ""' "$AUTHELIA_CONFIG_BACKUP") + local existing_redis_pass=$(yq e '.session.redis.password // ""' "$AUTHELIA_CONFIG_BACKUP") + local existing_notifier=$(yq e '.notifier // ""' "$AUTHELIA_CONFIG_BACKUP") + + # Update secrets in temp file if they existed in the backup + if [[ -n "$existing_jwt_secret" && "$existing_jwt_secret" != '""' && "$existing_jwt_secret" != "null" ]]; then + yq e -i '.identity_validation.reset_password.jwt_secret = strenv(existing_jwt_secret)' --env existing_jwt_secret="$existing_jwt_secret" "$TEMP_CONFIG" + fi + if [[ -n "$existing_session_secret" && "$existing_session_secret" != '""' && "$existing_session_secret" != "null" ]]; then + yq e -i '.session.secret = strenv(existing_session_secret)' --env existing_session_secret="$existing_session_secret" "$TEMP_CONFIG" + fi + if [[ -n "$existing_storage_key" && "$existing_storage_key" != '""' && "$existing_storage_key" != "null" ]]; then + yq e -i '.storage.encryption_key = strenv(existing_storage_key)' --env existing_storage_key="$existing_storage_key" "$TEMP_CONFIG" + fi + if [[ -n "$existing_redis_pass" && "$existing_redis_pass" != '""' && "$existing_redis_pass" != "null" ]]; then + yq e -i '.session.redis.password = strenv(existing_redis_pass)' --env existing_redis_pass="$existing_redis_pass" "$TEMP_CONFIG" + fi + # Preserve entire notifier block if it existed + if [[ -n "$existing_notifier" && "$existing_notifier" != "{}" && "$existing_notifier" != "null" ]]; then + yq e -i '.notifier = load("'"$AUTHELIA_CONFIG_BACKUP"'").notifier' "$TEMP_CONFIG" + fi + fi + + # Apply domain settings from .env using yq + echo -e "${BLUE}Applying Tailscale domain settings: ${CYAN}$FULL_HOSTNAME${NC}" + yq e -i '.session.cookies[0].domain = strenv(TAILNET_DOMAIN)' --env TAILNET_DOMAIN="$TAILNET_DOMAIN" "$TEMP_CONFIG" + yq e -i '.session.cookies[0].authelia_url = "https://" + strenv(FULL_HOSTNAME)' --env FULL_HOSTNAME="$FULL_HOSTNAME" "$TEMP_CONFIG" + yq e -i '.session.cookies[0].default_redirection_url = "https://" + strenv(FULL_HOSTNAME) + "/home"' --env FULL_HOSTNAME="$FULL_HOSTNAME" "$TEMP_CONFIG" + yq e -i '.access_control.rules[0].domain = strenv(WILDCARD_DOMAIN)' --env WILDCARD_DOMAIN="$WILDCARD_DOMAIN" "$TEMP_CONFIG" + yq e -i '.access_control.rules[1].domain = strenv(TAILNET_DOMAIN)' --env TAILNET_DOMAIN="$TAILNET_DOMAIN" "$TEMP_CONFIG" + + # Replace the original file with the updated temporary file + mv "$TEMP_CONFIG" "$AUTHELIA_CONFIG" + echo -e "${GREEN}Authelia configuration updated using yq.${NC}" + + else + echo -e "${YELLOW}Warning: 'yq' not found. Falling back to 'sed' for Authelia configuration.${NC}" + echo -e "${YELLOW}This method is less robust and might not preserve all existing settings perfectly.${NC}" + + # Copy example over if updating existing file (backup already created) + if [ -f "$AUTHELIA_CONFIG_BACKUP" ]; then + cp "$AUTHELIA_CONFIG_EXAMPLE" "$AUTHELIA_CONFIG" + fi + + # Use sed to replace placeholders - less reliable than yq + # Note: This assumes the example file uses specific placeholders like 'your-tailnet.ts.net' + echo -e "${BLUE}Applying Tailscale domain settings using sed: ${CYAN}$FULL_HOSTNAME${NC}" + sed -i "s/\*.your-tailnet.ts.net/\*.$TAILNET_DOMAIN/g" "$AUTHELIA_CONFIG" + sed -i "s/your-tailnet.ts.net/$TAILNET_DOMAIN/g" "$AUTHELIA_CONFIG" # Replace base domain too + sed -i "s|tailscale-nas.your-tailnet.ts.net|$FULL_HOSTNAME|g" "$AUTHELIA_CONFIG" # Replace full hostname + + # Attempt to preserve secrets using sed (very fragile) + if [ -f "$AUTHELIA_CONFIG_BACKUP" ]; then + echo -e "${YELLOW}Attempting to preserve secrets using sed (may be unreliable)...${NC}" + local existing_jwt_secret=$(grep -oP 'jwt_secret:\s*\K\S+' "$AUTHELIA_CONFIG_BACKUP" || echo "") + local existing_session_secret=$(grep -oP 'session:\s*\n\s*secret:\s*\K\S+' "$AUTHELIA_CONFIG_BACKUP" || echo "") # More specific grep + local existing_storage_key=$(grep -oP 'storage:\s*\n\s*encryption_key:\s*\K\S+' "$AUTHELIA_CONFIG_BACKUP" || echo "") # More specific grep + local existing_redis_pass=$(grep -oP 'redis:\s*\n\s*host:.*\n\s*port:.*\n\s*password:\s*\K\S+' "$AUTHELIA_CONFIG_BACKUP" || echo "") # More specific grep + + if [[ -n "$existing_jwt_secret" ]]; then sed -i "s|jwt_secret:.*|jwt_secret: $existing_jwt_secret|" "$AUTHELIA_CONFIG"; fi + if [[ -n "$existing_session_secret" ]]; then sed -i "/session:/,/redis:/ s|secret:.*|secret: $existing_session_secret|" "$AUTHELIA_CONFIG"; fi # Target within session block + if [[ -n "$existing_storage_key" ]]; then sed -i "/storage:/,/authentication_backend:/ s|encryption_key:.*|encryption_key: $existing_storage_key|" "$AUTHELIA_CONFIG"; fi # Target within storage block + if [[ -n "$existing_redis_pass" ]]; then sed -i "/redis:/,/database_index:/ s|password:.*|password: $existing_redis_pass|" "$AUTHELIA_CONFIG"; fi # Target within redis block + fi + echo -e "${GREEN}Authelia configuration updated using sed.${NC}" + fi + echo -e "${GREEN}${BOLD}Authelia Configuration Update Complete!${NC}" - echo -e "${BLUE}${BOLD}Note:${NC} Original config backed up to: $AUTHELIA_CONFIG_BACKUP" + if [ -f "$AUTHELIA_CONFIG_BACKUP" ]; then + echo -e "${BLUE}${BOLD}Note:${NC} Original config backed up to: $AUTHELIA_CONFIG_BACKUP" + fi } ################################################## @@ -1027,145 +1107,147 @@ EOL # MAIN SCRIPT ################################################## -if [ $# -gt 0 ]; then - case "$1" in - "list-auth") - list_services - exit 0 - ;; - "enable-auth") - if [ -z "$2" ]; then - echo -e "${RED}Error: No service specified${NC}" - echo -e "Usage: $0 enable-auth " - exit 1 - fi - create_backup "$COMPOSE_FILE" "$COMPOSE_BACKUP" - enable_auth "$2" - - echo -e "\n${YELLOW}Remember to restart the stack for changes to take effect:${NC}" - echo -e " ${CYAN}docker compose down${NC}" - echo -e " ${CYAN}docker compose up -d${NC}" - exit 0 - ;; - "disable-auth") - if [ -z "$2" ]; then - echo -e "${RED}Error: No service specified${NC}" - echo -e "Usage: $0 disable-auth " - exit 1 - fi - create_backup "$COMPOSE_FILE" "$COMPOSE_BACKUP" - disable_auth "$2" - - echo -e "\n${YELLOW}Remember to restart the stack for changes to take effect:${NC}" - echo -e " ${CYAN}docker compose down${NC}" - echo -e " ${CYAN}docker compose up -d${NC}" - exit 0 - ;; - "enable-all-auth") - create_backup "$COMPOSE_FILE" "$COMPOSE_BACKUP" - - echo -e "${BLUE}Enabling authentication for all services...${NC}" - local services=$(grep "container_name:" "$COMPOSE_FILE" | awk '{print $3}') - for service in $services; do - if [[ "$service" == "redis" || "$service" == "authelia" || "$service" == "traefik" || "$service" == "tailscale" || "$service" == "watchtower" || "$service" == "autoheal" || "$service" == "middlewares" ]]; then - continue - fi - - enable_auth "$service" - done - - echo -e "\n${YELLOW}Remember to restart the stack for changes to take effect:${NC}" - echo -e " ${CYAN}docker compose down${NC}" - echo -e " ${CYAN}docker compose up -d${NC}" - exit 0 - ;; - "disable-all-auth") - create_backup "$COMPOSE_FILE" "$COMPOSE_BACKUP" - - echo -e "${BLUE}Disabling authentication for all services...${NC}" - local services=$(grep "container_name:" "$COMPOSE_FILE" | awk '{print $3}') - for service in $services; do - if [[ "$service" == "redis" || "$service" == "authelia" || "$service" == "traefik" || "$service" == "tailscale" || "$service" == "watchtower" || "$service" == "autoheal" || "$service" == "middlewares" ]]; then - continue - fi - - disable_auth "$service" - done - - echo -e "\n${YELLOW}Remember to restart the stack for changes to take effect:${NC}" - echo -e " ${CYAN}docker compose down${NC}" - echo -e " ${CYAN}docker compose up -d${NC}" - exit 0 - ;; - "cleanup") - cleanup_backups - exit 0 - ;; - "help") - print_header "Docker Compose NAS - Setup Tool" - echo -e "${BLUE}Usage: $0 [command] [arguments]${NC}" - echo -e "${BLUE}Commands:${NC}" - echo -e " ${CYAN}list-auth${NC} List authentication status for all services" - echo -e " ${CYAN}enable-auth ${NC} Enable authentication for a specific service" - echo -e " ${CYAN}disable-auth ${NC} Disable authentication for a specific service" - echo -e " ${CYAN}enable-all-auth${NC} Enable authentication for all services" - echo -e " ${CYAN}disable-all-auth${NC} Disable authentication for all services" - echo -e " ${CYAN}cleanup${NC} Clean up backup files" - echo -e " ${CYAN}help${NC} Show this help message" - echo -e "" - echo -e "${BLUE}Without arguments, the script will start in interactive mode.${NC}" - exit 0 - ;; - *) - echo -e "${RED}Unknown command: $1${NC}" - echo -e "${BLUE}Run '$0 help' for usage information${NC}" - exit 1 - ;; - esac +# Function to display help message +show_help() { + print_header "Docker Compose NAS - Setup Tool" + echo -e "${BLUE}Usage: $0 [command] [arguments]${NC}" + echo -e "" + echo -e "${BLUE}Available Commands:${NC}" + echo -e " ${CYAN}update-env${NC} Update .env file from .env.example, preserving values." + echo -e " ${CYAN}update-authelia${NC} Update Authelia configuration (configuration.yml) from example," + echo -e " applying domain settings from .env and preserving secrets." + echo -e " ${CYAN}update-services${NC} Update configurations for running *arr/qBittorrent/Bazarr containers" + echo -e " (sets URL base, extracts API keys to .env)." + echo -e " ${CYAN}manage-accounts${NC} Interactively add/update Authelia users in users_database.yml." + echo -e " ${CYAN}list-auth${NC} List authentication status for all services in docker-compose.yml." + echo -e " ${CYAN}enable-auth ${NC} Enable Authelia authentication for a specific service." + echo -e " ${CYAN}disable-auth ${NC} Disable Authelia authentication for a specific service." + echo -e " ${CYAN}enable-all-auth${NC} Enable Authelia authentication for all applicable services." + echo -e " ${CYAN}disable-all-auth${NC} Disable Authelia authentication for all applicable services." + echo -e " ${CYAN}cleanup${NC} Interactively clean up old backup files (.bak)." + echo -e " ${CYAN}all${NC} Run 'update-env', 'update-authelia', and 'update-services'." + echo -e " ${CYAN}help${NC} Show this help message." + echo -e "" + echo -e "${BLUE}Examples:${NC}" + echo -e " $0 update-authelia" + echo -e " $0 enable-auth sonarr" + echo -e " $0 all" + echo -e "" + echo -e "${YELLOW}Note:${NC} Some commands require Docker to be running and may restart containers." + echo -e "${YELLOW}Authentication changes require a stack restart ('docker compose down && docker compose up -d').${NC}" +} + +# Check if any arguments were provided +if [ $# -eq 0 ]; then + show_help + exit 0 fi -print_header "Docker Compose NAS - Setup Tool" -echo -e "${BLUE}This tool will help you configure your Docker Compose NAS setup${NC}" -echo -e "${BLUE}Choose one or more options to run:${NC}" -echo -e " ${CYAN}1. ${NC}Update .env file from .env.example" -echo -e " ${CYAN}2. ${NC}Update Authelia configuration" -echo -e " ${CYAN}3. ${NC}Update service configurations" -echo -e " ${CYAN}4. ${NC}Manage Authelia accounts" -echo -e " ${CYAN}5. ${NC}Manage service authentication" -echo -e " ${CYAN}6. ${NC}Clean up backup files" -echo -e " ${CYAN}7. ${NC}Run ALL updates" -echo -e " ${CYAN}q. ${NC}Quit" -echo +# Process command line arguments +case "$1" in + update-env) + update_env_file + ;; + update-authelia) + update_authelia_config + ;; + update-services) + update_service_configs + ;; + manage-accounts) + manage_authelia_accounts # This function remains interactive + ;; + list-auth) + list_services + ;; + enable-auth) + if [ -z "$2" ]; then + echo -e "${RED}Error: No service specified.${NC}" >&2 + echo -e "Usage: $0 enable-auth " >&2 + exit 1 + fi + if ! check_file "$COMPOSE_FILE"; then exit 1; fi + create_backup "$COMPOSE_FILE" "$COMPOSE_BACKUP" + enable_auth "$2" + echo -e "\n${YELLOW}Remember to restart the stack for changes to take effect:${NC}" + echo -e " ${CYAN}docker compose down && docker compose up -d${NC}" + ;; + disable-auth) + if [ -z "$2" ]; then + echo -e "${RED}Error: No service specified.${NC}" >&2 + echo -e "Usage: $0 disable-auth " >&2 + exit 1 + fi + if ! check_file "$COMPOSE_FILE"; then exit 1; fi + create_backup "$COMPOSE_FILE" "$COMPOSE_BACKUP" + disable_auth "$2" + echo -e "\n${YELLOW}Remember to restart the stack for changes to take effect:${NC}" + echo -e " ${CYAN}docker compose down && docker compose up -d${NC}" + ;; + enable-all-auth) + if ! check_file "$COMPOSE_FILE"; then exit 1; fi + create_backup "$COMPOSE_FILE" "$COMPOSE_BACKUP" + echo -e "${BLUE}Enabling authentication for all applicable services...${NC}" + # Use yq if available for more reliable service list, otherwise fallback to grep + local services_list + if check_yq; then + services_list=$(yq e '.services | keys | .[]' "$COMPOSE_FILE") + else + services_list=$(grep "container_name:" "$COMPOSE_FILE" | awk '{print $NF}') # Less reliable + fi -CHOICE="0" -while [[ "$CHOICE" != "q" ]]; do - echo -e "${YELLOW}Enter your choice [1-7 or q to quit]: ${NC}" - read -r CHOICE - - case "$CHOICE" in - 1) update_env_file ;; - 2) update_authelia_config ;; - 3) update_service_configs ;; - 4) manage_authelia_accounts ;; - 5) manage_auth ;; - 6) cleanup_backups ;; - 7) - update_env_file - update_authelia_config - update_service_configs - manage_authelia_accounts - CHOICE="q" - ;; - q|Q) - echo -e "${GREEN}Exiting setup tool.${NC}" - exit 0 - ;; - *) echo -e "${RED}Invalid choice. Please try again.${NC}" ;; - esac -done + for service in $services_list; do + # Skip infrastructure/excluded containers + if [[ "$service" == "redis" || "$service" == "authelia" || "$service" == "traefik" || "$service" == "tailscale" || "$service" == "watchtower" || "$service" == "autoheal" || "$service" == "middlewares" ]]; then + continue + fi + enable_auth "$service" + done + echo -e "\n${YELLOW}Remember to restart the stack for changes to take effect:${NC}" + echo -e " ${CYAN}docker compose down && docker compose up -d${NC}" + ;; + disable-all-auth) + if ! check_file "$COMPOSE_FILE"; then exit 1; fi + create_backup "$COMPOSE_FILE" "$COMPOSE_BACKUP" + echo -e "${BLUE}Disabling authentication for all applicable services...${NC}" + local services_list + if check_yq; then + services_list=$(yq e '.services | keys | .[]' "$COMPOSE_FILE") + else + services_list=$(grep "container_name:" "$COMPOSE_FILE" | awk '{print $NF}') # Less reliable + fi + + for service in $services_list; do + # Skip infrastructure/excluded containers + if [[ "$service" == "redis" || "$service" == "authelia" || "$service" == "traefik" || "$service" == "tailscale" || "$service" == "watchtower" || "$service" == "autoheal" || "$service" == "middlewares" ]]; then + continue + fi + disable_auth "$service" + done + echo -e "\n${YELLOW}Remember to restart the stack for changes to take effect:${NC}" + echo -e " ${CYAN}docker compose down && docker compose up -d${NC}" + ;; + cleanup) + cleanup_backups + ;; + all) + print_header "Running All Updates" + update_env_file + update_authelia_config + update_service_configs + echo -e "\n${GREEN}${BOLD}All core updates completed!${NC}" + echo -e "${BLUE}Review output for any required actions (e.g., setting new .env variables).${NC}" + echo -e "${BLUE}Consider running 'manage-accounts' if needed.${NC}" + echo -e "${YELLOW}Remember to restart relevant services or the full stack if necessary.${NC}" + ;; + help|-h|--help) + show_help + ;; + *) + echo -e "${RED}Unknown command: $1${NC}" >&2 + echo -e "${BLUE}Run '$0 help' for usage information.${NC}" >&2 + exit 1 + ;; +esac -echo -e "\n${GREEN}${BOLD}All updates completed!${NC}" -echo -e "${BLUE}Be sure to restart any services that were updated:${NC}" -echo -e " ${CYAN}docker compose restart${NC}" -echo -e "\n${BLUE}If you updated the Authelia configuration, restart Authelia:${NC}" -echo -e " ${CYAN}docker compose restart authelia${NC}" \ No newline at end of file +exit 0