feat(setup): Enhance update script and add user database example

This commit is contained in:
Jose Daniel G. Percy 2025-04-26 14:10:11 +08:00
parent f3fab15ffb
commit 2ae84f4481
5 changed files with 307 additions and 228 deletions

2
.gitignore vendored
View File

@ -2,7 +2,7 @@
.idea .idea
docker-compose.override.yml docker-compose.override.yml
/authelia/*.yml /authelia/*.yml
!/authelia/configuration.example.yml !/authelia/*.example.yml
/homepage/logs /homepage/logs
/homepage/*.yaml /homepage/*.yaml
/homepage/*.css /homepage/*.css

105
README.md
View File

@ -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) VPN Configuration](#optional-vpn-configuration)
- [(Optional) Traefik DNS Challenge](#optional-traefik-dns-challenge) - [(Optional) Traefik DNS Challenge](#optional-traefik-dns-challenge)
- [Service Access](#service-access) - [Service Access](#service-access)
- [Setup Script Commands (`update-setup.sh`)](#setup-script-commands-update-setupsh)
- [Managing Service Authentication](#managing-service-authentication) - [Managing Service Authentication](#managing-service-authentication)
- [Optional Services](#optional-services) - [Optional Services](#optional-services)
- [Troubleshooting](#troubleshooting) - [Troubleshooting](#troubleshooting)
@ -169,13 +170,15 @@ After completing all [Required Setup Steps](#required-setup-steps) above, follow
# Make the script executable # Make the script executable
chmod +x ./update-setup.sh chmod +x ./update-setup.sh
# Run the setup tool # Run the setup tool (use 'all' for initial setup)
./update-setup.sh ./update-setup.sh all
``` ```
This interactive script will guide you through: This script will:
- Updating your `.env` file while preserving existing values - Update your `.env` file while preserving existing values (`update-env`).
- Configuring Authelia with your Tailscale domain settings - Configure Authelia with your Tailscale domain settings (`update-authelia`).
- Setting up service configurations and retrieving API keys - 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:** 5. **Start the Stack:**
```bash ```bash
@ -327,21 +330,19 @@ Authelia uses the `authelia/users_database.yml` file to manage users.
groups: groups:
- users # Add to 'admins' group if needed - 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):** * **Enabling User Registration (Optional):**
1. Edit `authelia/configuration.yml`. 1. Edit `authelia/configuration.yml`.
2. Find the commented-out `registration:` section near the bottom. 2. Find the commented-out `registration:` section near the bottom.
3. Uncomment it and set `enable: true`: 3. Uncomment it and set `enable: true`.
```yaml
# registration:
# enable: false # Set to true to enable registration form
```
becomes:
```yaml
registration:
enable: true
```
4. Save the file and restart Authelia (`docker compose restart authelia`). 4. Save the file and restart Authelia (`docker compose restart authelia`).
5. A "Register" link will now appear on the Authelia login page. 5. A "Register" link will now appear on the Authelia login page.
@ -376,43 +377,43 @@ Replace `<TAILSCALE_NODE>` 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://<APP_HOSTNAME>/<service_path>`. If you configure DNS for your `APP_HOSTNAME` variable to point to the Tailscale IP, you can use `https://<APP_HOSTNAME>/<service_path>`.
### 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 <service>`: Enables Authelia authentication for the specified `<service>` by adding the `authelia-auth@docker` middleware label in `docker-compose.yml`.
* `./update-setup.sh disable-auth <service>`: Disables Authelia authentication for the specified `<service>` 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 ### Managing Service Authentication
You can control which services require authentication using the updated `update-setup.sh` script: 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.
```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.
## Optional Services ## Optional Services

View File

@ -15,7 +15,6 @@ services:
- --experimental.plugins.rewriteHeaders.version=v0.0.3 - --experimental.plugins.rewriteHeaders.version=v0.0.3
- --providers.docker.network=docker-compose-nas - --providers.docker.network=docker-compose-nas
- --providers.docker.endpoint=unix:///var/run/docker.sock - --providers.docker.endpoint=unix:///var/run/docker.sock
- --log.level=DEBUG
network_mode: service:tailscale network_mode: service:tailscale
volumes: volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro - /var/run/docker.sock:/var/run/docker.sock:ro
@ -23,9 +22,6 @@ services:
test: ["CMD", "traefik", "healthcheck", "--ping"] test: ["CMD", "traefik", "healthcheck", "--ping"]
interval: 30s interval: 30s
retries: 10 retries: 10
labels:
- traefik.enable=true
# Remove middleware definition from traefik service
redis: redis:
image: redis:alpine image: redis:alpine
container_name: redis container_name: redis

View File

@ -214,48 +214,128 @@ update_authelia_config() {
# Check if files exist # Check if files exist
if ! check_file "$AUTHELIA_CONFIG_EXAMPLE"; then 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 return 1
fi fi
# If config file doesn't exist, create it from example # If config file doesn't exist, create it from example
if [ ! -f "$AUTHELIA_CONFIG" ]; then 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" cp "$AUTHELIA_CONFIG_EXAMPLE" "$AUTHELIA_CONFIG"
echo -e "${GREEN}Created new Authelia configuration file.${NC}" echo -e "${GREEN}Created new Authelia configuration file.${NC}"
return 0 # Proceed to update the newly created file
fi else
echo -e "${BLUE}This will update your Authelia configuration '$AUTHELIA_CONFIG' based on '$AUTHELIA_CONFIG_EXAMPLE'${NC}"
echo -e "${BLUE}This will update your Authelia configuration based on the example file${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 "${BLUE}Backup will be created as: $AUTHELIA_CONFIG_BACKUP${NC}"
echo -e "${YELLOW}Continue? [y/N]:${NC}" echo -e "${YELLOW}Continue? [y/N]:${NC}"
read -r answer read -r answer
if [[ ! "$answer" =~ ^[Yy]$ ]]; then if [[ ! "$answer" =~ ^[Yy]$ ]]; then
echo -e "${RED}Authelia config update cancelled.${NC}" echo -e "${RED}Authelia config update cancelled.${NC}"
return 0 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}"
fi 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 fi
echo -e "${GREEN}${BOLD}Authelia Configuration Update Complete!${NC}" 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 # MAIN SCRIPT
################################################## ##################################################
if [ $# -gt 0 ]; then # Function to display help message
case "$1" in show_help() {
"list-auth") print_header "Docker Compose NAS - Setup Tool"
list_services echo -e "${BLUE}Usage: $0 [command] [arguments]${NC}"
exit 0 echo -e ""
;; echo -e "${BLUE}Available Commands:${NC}"
"enable-auth") echo -e " ${CYAN}update-env${NC} Update .env file from .env.example, preserving values."
if [ -z "$2" ]; then echo -e " ${CYAN}update-authelia${NC} Update Authelia configuration (configuration.yml) from example,"
echo -e "${RED}Error: No service specified${NC}" echo -e " applying domain settings from .env and preserving secrets."
echo -e "Usage: $0 enable-auth <service>" echo -e " ${CYAN}update-services${NC} Update configurations for running *arr/qBittorrent/Bazarr containers"
exit 1 echo -e " (sets URL base, extracts API keys to .env)."
fi echo -e " ${CYAN}manage-accounts${NC} Interactively add/update Authelia users in users_database.yml."
create_backup "$COMPOSE_FILE" "$COMPOSE_BACKUP" echo -e " ${CYAN}list-auth${NC} List authentication status for all services in docker-compose.yml."
enable_auth "$2" echo -e " ${CYAN}enable-auth <service>${NC} Enable Authelia authentication for a specific service."
echo -e " ${CYAN}disable-auth <service>${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}"
}
echo -e "\n${YELLOW}Remember to restart the stack for changes to take effect:${NC}" # Check if any arguments were provided
echo -e " ${CYAN}docker compose down${NC}" if [ $# -eq 0 ]; then
echo -e " ${CYAN}docker compose up -d${NC}" show_help
exit 0 exit 0
;;
"disable-auth")
if [ -z "$2" ]; then
echo -e "${RED}Error: No service specified${NC}"
echo -e "Usage: $0 disable-auth <service>"
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 <service>${NC} Enable authentication for a specific service"
echo -e " ${CYAN}disable-auth <service>${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
fi fi
print_header "Docker Compose NAS - Setup Tool" # Process command line arguments
echo -e "${BLUE}This tool will help you configure your Docker Compose NAS setup${NC}" case "$1" in
echo -e "${BLUE}Choose one or more options to run:${NC}" update-env)
echo -e " ${CYAN}1. ${NC}Update .env file from .env.example" update_env_file
echo -e " ${CYAN}2. ${NC}Update Authelia configuration" ;;
echo -e " ${CYAN}3. ${NC}Update service configurations" update-authelia)
echo -e " ${CYAN}4. ${NC}Manage Authelia accounts" update_authelia_config
echo -e " ${CYAN}5. ${NC}Manage service authentication" ;;
echo -e " ${CYAN}6. ${NC}Clean up backup files" update-services)
echo -e " ${CYAN}7. ${NC}Run ALL updates" update_service_configs
echo -e " ${CYAN}q. ${NC}Quit" ;;
echo 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 <service>" >&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 <service>" >&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" for service in $services_list; do
while [[ "$CHOICE" != "q" ]]; do # Skip infrastructure/excluded containers
echo -e "${YELLOW}Enter your choice [1-7 or q to quit]: ${NC}" if [[ "$service" == "redis" || "$service" == "authelia" || "$service" == "traefik" || "$service" == "tailscale" || "$service" == "watchtower" || "$service" == "autoheal" || "$service" == "middlewares" ]]; then
read -r CHOICE 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
case "$CHOICE" in for service in $services_list; do
1) update_env_file ;; # Skip infrastructure/excluded containers
2) update_authelia_config ;; if [[ "$service" == "redis" || "$service" == "authelia" || "$service" == "traefik" || "$service" == "tailscale" || "$service" == "watchtower" || "$service" == "autoheal" || "$service" == "middlewares" ]]; then
3) update_service_configs ;; continue
4) manage_authelia_accounts ;; fi
5) manage_auth ;; disable_auth "$service"
6) cleanup_backups ;; done
7) echo -e "\n${YELLOW}Remember to restart the stack for changes to take effect:${NC}"
update_env_file echo -e " ${CYAN}docker compose down && docker compose up -d${NC}"
update_authelia_config ;;
update_service_configs cleanup)
manage_authelia_accounts cleanup_backups
CHOICE="q" ;;
;; all)
q|Q) print_header "Running All Updates"
echo -e "${GREEN}Exiting setup tool.${NC}" update_env_file
exit 0 update_authelia_config
;; update_service_configs
*) echo -e "${RED}Invalid choice. Please try again.${NC}" ;; echo -e "\n${GREEN}${BOLD}All core updates completed!${NC}"
esac echo -e "${BLUE}Review output for any required actions (e.g., setting new .env variables).${NC}"
done 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}" exit 0
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}"