Compare commits

..

29 Commits

Author SHA1 Message Date
aki
ba889f9c38 feat(update-setup): Update to support the new authelia/configuration.yml
Some checks failed
/ validate-docker-compose (push) Has been cancelled
2025-04-26 15:20:06 +08:00
aki
026d24a3ae fix(authelia): Update access control rules and remove non-existing trusted proxies configuration 2025-04-26 15:19:33 +08:00
aki
2ae84f4481 feat(setup): Enhance update script and add user database example 2025-04-26 14:10:11 +08:00
aki
f3fab15ffb fix(traefik): Remove unnecessary middleware definitions and update HTTPS header configuration
Some checks failed
/ validate-docker-compose (push) Has been cancelled
2025-04-26 12:33:11 +08:00
aki
db968ba5ca fix(traefik): Update middleware configuration for HTTPS and routing rules
Some checks failed
/ validate-docker-compose (push) Has been cancelled
2025-04-26 12:27:09 +08:00
aki
191d25e281 fix(authelia): Add trusted proxies configuration
Some checks failed
/ validate-docker-compose (push) Has been cancelled
2025-04-26 12:10:42 +08:00
aki
f07d0937d9 refactor(docker-compose): Move authelia to /auth, then bring back host checks
Some checks failed
/ validate-docker-compose (push) Has been cancelled
2025-04-26 11:16:37 +08:00
aki
749aa6f1cf fix(auth): Refactor service authentication status check 2025-04-26 03:27:49 +08:00
aki
f4409eb258 feat(auth): Enhance authentication management with yq support for YAML parsing
Some checks failed
/ validate-docker-compose (push) Has been cancelled
2025-04-26 03:17:22 +08:00
aki
a74707dc1f fix(authelia): Authentication management and middleware errors
Some checks failed
/ validate-docker-compose (push) Has been cancelled
- Fix middleware "true@docker" does not exist errors
- Integrate authentication management directly into update-setup.sh
- Add command-line support for managing service authentication
- Add backup file cleanup functionality
- Update README with new authentication management instructions
- Remove standalone manage-auth.sh script
2025-04-26 02:59:46 +08:00
aki
5d7a162647 feat(auth): Add authentication management script and update permissions for setup script
Some checks failed
/ validate-docker-compose (push) Has been cancelled
2025-04-26 02:45:09 +08:00
aki
a0e63e2e2b feat(auth): Implement conditional authentication middleware for services in docker-compose.yml
Some checks failed
/ validate-docker-compose (push) Has been cancelled
2025-04-26 01:58:42 +08:00
aki
2fadb08c72 feat(auth): Add additional service authentication settings in .env.example and update docker-compose.yml for conditional middlewares
Some checks failed
/ validate-docker-compose (push) Has been cancelled
2025-04-26 01:32:13 +08:00
aki
6d2baa7300 fix(update-setup): Enhance password hash verification in Authelia account management
Some checks failed
/ validate-docker-compose (push) Has been cancelled
2025-04-26 01:20:15 +08:00
aki
13b73671f8 feat(authelia): Add account management functionality to update users and passwords
Some checks failed
/ validate-docker-compose (push) Has been cancelled
2025-04-26 01:11:16 +08:00
aki
2217377ae8 refactor(update-setup): Enhance configuration update process with error handling and summary reporting
Some checks failed
/ validate-docker-compose (push) Has been cancelled
2025-04-26 00:51:17 +08:00
aki
ca4c3e92f0 fix(docker-compose): Update Redis command and healthcheck to use actual password variable 2025-04-26 00:51:12 +08:00
aki
3ce92b7394 fix(authelia): Add Redis password configuration to Authelia setup script
Some checks failed
/ validate-docker-compose (push) Has been cancelled
2025-04-26 00:45:53 +08:00
aki
4ad7bf0a38 fix(authelia): Update configuration and setup script for Tailscale domain handling in Authelia v4.38+
Some checks failed
/ validate-docker-compose (push) Has been cancelled
2025-04-26 00:41:41 +08:00
aki
6d9139408d refactor: Consolidate Authelia configuration management and update setup scripts
Some checks failed
/ validate-docker-compose (push) Has been cancelled
- Removed outdated configuration files and scripts.
- Introduced a new setup script to streamline environment and Authelia configuration updates.
- Enhanced .gitignore to exclude unnecessary files.
- Updated README to reflect new setup process and configuration details for Authelia v4.38+.
2025-04-26 00:32:24 +08:00
aki
6e17920cfd docs: Update README with required setup steps and configuration details for Authelia v4.38+
Some checks failed
/ validate-docker-compose (push) Has been cancelled
2025-04-26 00:18:59 +08:00
aki
6b1a8b7d45 fix(authelia): Adjust configuration for Tailscale domain handling and simplify session settings 2025-04-26 00:18:57 +08:00
aki
09b20f71fc fix(authelia): Add user configuration for Authelia container
Some checks failed
/ validate-docker-compose (push) Has been cancelled
2025-04-26 00:08:32 +08:00
aki
afbffb97e3 fix(authelia): Update configuration for v4.38+ with required variables and improved domain handling
Some checks failed
/ validate-docker-compose (push) Has been cancelled
2025-04-26 00:04:49 +08:00
aki
1c5959cafb fix(env): Enhance environment variable tracking by adding current key presence check
Some checks failed
/ validate-docker-compose (push) Has been cancelled
2025-04-25 23:52:33 +08:00
aki
73e40af91a feat: Add environment update script to manage .env variables and preserve existing values
Some checks failed
/ validate-docker-compose (push) Has been cancelled
2025-04-25 23:48:09 +08:00
aki
461a0dc110 fix(authelia): Update configuration for v4.38+ compatibility and remove deprecated variables
Some checks failed
/ validate-docker-compose (push) Has been cancelled
2025-04-25 23:40:25 +08:00
aki
91873062c9 fix(env): Rename HOSTNAME to APP_HOSTNAME to avoid conflicts and update related configurations
Some checks failed
/ validate-docker-compose (push) Has been cancelled
2025-04-25 21:52:38 +08:00
aki
8a52e6894f feat!: Add Authelia for authentication and Redis for session storage
Some checks failed
/ validate-docker-compose (push) Has been cancelled
- Introduced Redis service for session management with health checks.
- Added Authelia service for user authentication with necessary environment variables.
- Configured Traefik to use Authelia as middleware for various services.
- Created Authelia configuration file with session, storage, and access control settings.
- Added user database for Authelia with an example admin user.
2025-04-25 17:33:09 +08:00
3 changed files with 143 additions and 587 deletions

286
README.md
View File

@ -14,19 +14,19 @@ The core idea is to manage media libraries (movies, TV shows, music), automate d
- [Required Setup Steps](#required-setup-steps)
- [Quick Start Guide](#quick-start-guide)
- [Configuration (`.env` Variables)](#configuration-env-variables)
- [Core System \& Paths](#core-system--paths)
- [Networking \& Access (Tailscale)](#networking--access-tailscale)
- [Authentication (Authelia)](#authentication-authelia)
- [Service Credentials](#service-credentials)
- [Homepage Customization \& Widgets](#homepage-customization--widgets)
- [Optional Features \& Services](#optional-features--services)
- [Core System \& Paths](#core-system--paths)
- [Networking \& Access (Tailscale)](#networking--access-tailscale)
- [Authentication (Authelia)](#authentication-authelia)
- [Service Credentials](#service-credentials)
- [Homepage Customization \& Widgets](#homepage-customization--widgets)
- [Optional Features \& Services](#optional-features--services)
- [Detailed Setup \& Usage](#detailed-setup--usage)
- [Authelia User Management](#authelia-user-management)
- [(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-authelia-policies)
- [Managing Service Authentication](#managing-service-authentication)
- [Optional Services](#optional-services)
- [Troubleshooting](#troubleshooting)
- [Middleware Not Found Errors](#middleware-not-found-errors)
@ -40,64 +40,58 @@ The core idea is to manage media libraries (movies, TV shows, music), automate d
This stack uses a combination of key services for routing, access, and security:
- **[Tailscale](https://tailscale.com):** Provides a secure overlay network (WireGuard-based VPN) connecting your devices. It allows access to the NAS services from anywhere without opening firewall ports and handles HTTPS termination via its built-in `tailscale serve` or `tailscale funnel` features. All other services run within Tailscale's network namespace.
- **[Traefik](https://traefik.io):** Acts as a reverse proxy *within* the Tailscale network. It discovers services via Docker labels and routes incoming requests (from Tailscale) to the appropriate container based on paths (e.g., `/sonarr`, `/radarr`).
- **[Authelia](https://www.authelia.com):** Serves as the authentication gateway. Traefik forwards requests to Authelia for verification. If a user isn't logged in, they are redirected to the Authelia portal (`/`). Once authenticated, Authelia sets a session cookie (stored in Redis), and Traefik allows access to the requested service. You can configure which services require authentication via environment variables.
* **[Tailscale](https://tailscale.com):** Provides a secure overlay network (WireGuard-based VPN) connecting your devices. It allows access to the NAS services from anywhere without opening firewall ports and handles HTTPS termination via its built-in `tailscale serve` or `tailscale funnel` features. All other services run within Tailscale's network namespace.
* **[Traefik](https://traefik.io):** Acts as a reverse proxy *within* the Tailscale network. It discovers services via Docker labels and routes incoming requests (from Tailscale) to the appropriate container based on paths (e.g., `/sonarr`, `/radarr`).
* **[Authelia](https://www.authelia.com):** Serves as the authentication gateway. Traefik forwards requests to Authelia for verification. If a user isn't logged in, they are redirected to the Authelia portal (`/`). Once authenticated, Authelia sets a session cookie (stored in Redis), and Traefik allows access to the requested service. You can configure which services require authentication via environment variables.
## Features
This stack includes the following services, categorized for clarity:
**Core Infrastructure:**
- **Reverse Proxy:** [Traefik](https://traefik.io) - Manages internal routing and service discovery.
- **Secure Remote Access:** [Tailscale](https://tailscale.com) - Provides VPN access and HTTPS.
- **Authentication:** [Authelia](https://www.authelia.com) & [Redis](https://redis.io) - Single sign-on portal and session management.
- **Dashboard:** [Homepage](https://gethomepage.dev) - Centralized access point (at `/home`).
* **Reverse Proxy:** [Traefik](https://traefik.io) - Manages internal routing and service discovery.
* **Secure Remote Access:** [Tailscale](https://tailscale.com) - Provides VPN access and HTTPS.
* **Authentication:** [Authelia](https://www.authelia.com) & [Redis](https://redis.io) - Single sign-on portal and session management.
* **Dashboard:** [Homepage](https://gethomepage.dev) - Centralized access point (at `/home`).
**Media Management (\*Arr Suite):**
- [Sonarr](https://sonarr.tv): TV show management.
- [Radarr](https://radarr.video): Movie management.
- [Lidarr](https://lidarr.audio) (Optional): Music management.
- [Bazarr](https://www.bazarr.media/): Subtitle management.
- [Prowlarr](https://github.com/Prowlarr/Prowlarr): Indexer management for *arr apps.
* [Sonarr](https://sonarr.tv): TV show management.
* [Radarr](https://radarr.video): Movie management.
* [Lidarr](https://lidarr.audio) (Optional): Music management.
* [Bazarr](https://www.bazarr.media/): Subtitle management.
* [Prowlarr](https://github.com/Prowlarr/Prowlarr): Indexer management for *arr apps.
**Download Clients:**
- [qBittorrent](https://www.qbittorrent.org): Bittorrent client.
- [SABnzbd](https://sabnzbd.org/) (Optional): Usenet download client.
* [qBittorrent](https://www.qbittorrent.org): Bittorrent client.
* [SABnzbd](https://sabnzbd.org/) (Optional): Usenet download client.
**Media Serving & Requests:**
- [Jellyfin](https://jellyfin.org): Media server for streaming.
- [Jellyseerr](https://github.com/FallenBagel/jellyseerr): Media request management.
* [Jellyfin](https://jellyfin.org): Media server for streaming.
* [Jellyseerr](https://github.com/FallenBagel/jellyseerr): Media request management.
**Utilities:**
- [Watchtower](https://containrrr.dev/watchtower/): Automatic container updates.
- [Autoheal](https://github.com/willfarrell/docker-autoheal/): Automatic container restarts on failure.
- [Unpackerr](https://unpackerr.zip): Automated archive extraction.
* [Watchtower](https://containrrr.dev/watchtower/): Automatic container updates.
* [Autoheal](https://github.com/willfarrell/docker-autoheal/): Automatic container restarts on failure.
* [Unpackerr](https://unpackerr.zip): Automated archive extraction.
**Optional Services (Enabled via Profiles):**
- [AdGuard Home](https://adguard.com/en/adguard-home/overview.html): Network-wide ad blocking.
- [Calibre-Web](https://github.com/janeczku/calibre-web): E-book library management.
- [Decluttarr](https://github.com/manimatter/decluttarr): Automated download cleanup.
- [Tandoor Recipes](https://docs.tandoor.dev/): Recipe management.
- [Joplin Server](https://joplinapp.org/): Note-taking synchronization server.
- [Home Assistant](https://www.home-assistant.io/): Home automation platform.
- [Immich](https://immich.app/): Self-hosted photo and video backup.
- [FlareSolverr](https://github.com/FlareSolverr/FlareSolverr): Bypasses Cloudflare challenges (e.g., for Prowlarr).
* [AdGuard Home](https://adguard.com/en/adguard-home/overview.html): Network-wide ad blocking.
* [Calibre-Web](https://github.com/janeczku/calibre-web): E-book library management.
* [Decluttarr](https://github.com/manimatter/decluttarr): Automated download cleanup.
* [Tandoor Recipes](https://docs.tandoor.dev/): Recipe management.
* [Joplin Server](https://joplinapp.org/): Note-taking synchronization server.
* [Home Assistant](https://www.home-assistant.io/): Home automation platform.
* [Immich](https://immich.app/): Self-hosted photo and video backup.
* [FlareSolverr](https://github.com/FlareSolverr/FlareSolverr): Bypasses Cloudflare challenges (e.g., for Prowlarr).
## Prerequisites
- **Linux Host:** A system capable of running Docker (e.g., Ubuntu, Debian, Fedora).
- **Docker & Docker Compose:** Latest versions installed. See [Docker Engine Install](https://docs.docker.com/engine/install/) and [Docker Compose Install](https://docs.docker.com/compose/install/).
- **User Permissions:** Ability to run `docker` commands (user in `docker` group or use `sudo`).
- **Basic Linux Knowledge:** Familiarity with command line, text editors, and file permissions.
- **Tailscale Account:** Required for remote access. [Sign up here](https://tailscale.com/login).
- **(Optional) SELinux:** If enabled, see [Troubleshooting](#selinux-socket-permissions-docker).
* **Linux Host:** A system capable of running Docker (e.g., Ubuntu, Debian, Fedora).
* **Docker & Docker Compose:** Latest versions installed. See [Docker Engine Install](https://docs.docker.com/engine/install/) and [Docker Compose Install](https://docs.docker.com/compose/install/).
* **User Permissions:** Ability to run `docker` commands (user in `docker` group or use `sudo`).
* **Basic Linux Knowledge:** Familiarity with command line, text editors, and file permissions.
* **Tailscale Account:** Required for remote access. [Sign up here](https://tailscale.com/login).
* **(Optional) SELinux:** If enabled, see [Troubleshooting](#selinux-socket-permissions).
## Required Setup Steps
@ -120,45 +114,40 @@ These steps are **mandatory** for a working installation. Without properly compl
4. **⚠️ Required: Security Credentials**
- Generate four strong random secrets using `openssl rand -hex 32`:
```bash
echo "AUTHELIA_JWT_SECRET=$(openssl rand -hex 32)"
echo "AUTHELIA_SESSION_SECRET=$(openssl rand -hex 32)"
echo "AUTHELIA_STORAGE_ENCRYPTION_KEY=$(openssl rand -hex 32)"
echo "AUTHELIA_REDIS_PASSWORD=$(openssl rand -hex 32)"
```
- Add these to your `.env` file as shown
5. **⚠️ Required: Create Authelia Account**
- Create an Authelia account (only for yourself and those you trust!)
```bash
docker run --rm authelia/authelia:latest authelia hash-password 'your_secure_password'
```
6. ** Optional: Set up**
5. **⚠️ Required: Create Admin Password**
- Generate a password hash for Authelia:
```bash
docker run --rm authelia/authelia:latest authelia hash-password 'your_secure_password'
```
- Replace the example hash in `authelia/users_database.yml` with your generated hash
6. **⚠️ Optional: Authentication Configuration**
- Choose which services require authentication by setting the corresponding variables in your `.env` file:
```
AUTH_JELLYFIN=false # Example: Allow Jellyfin access without authentication
AUTH_SONARR=true # Example: Require authentication for Sonarr
```
- By default, all services require authentication if not specified otherwise
## Quick Start Guide
After completing all [Required Setup Steps](#required-setup-steps) above, follow these steps to get up and running:
1. **Clone Repository:**
```bash
git clone https://github.com/AdrienPoupa/docker-compose-nas.git
cd docker-compose-nas
```
2. **Configure Environment:**
```bash
# Create an .env file from the example
cp .env.example .env
@ -168,7 +157,6 @@ After completing all [Required Setup Steps](#required-setup-steps) above, follow
```
3. **Configure Authelia Admin:**
```bash
# Generate a password hash
docker run --rm authelia/authelia:latest authelia hash-password 'your_secure_password'
@ -178,7 +166,6 @@ After completing all [Required Setup Steps](#required-setup-steps) above, follow
```
4. **Run the Setup Script:**
```bash
# Make the script executable
chmod +x ./update-setup.sh
@ -186,21 +173,18 @@ After completing all [Required Setup Steps](#required-setup-steps) above, follow
# Run the setup tool (use 'all' for initial setup)
./update-setup.sh all
```
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
# Start containers
docker compose up -d
```
*(Wait for containers to download and start)*
6. **Access Your NAS:**
@ -245,6 +229,20 @@ This file controls essential settings. Copy `.env.example` to `.env` and modify
| **`AUTHELIA_SESSION_SECRET`** | **Required.** Random secret for session cookies. **Generate your own!** | *(None - Example in file)* |
| **`AUTHELIA_STORAGE_ENCRYPTION_KEY`** | **Required.** Random secret for encrypting data at rest (e.g., SQLite DB). **Generate your own!** | *(None - Example in file)* |
| **`AUTHELIA_REDIS_PASSWORD`** | **Required.** Password for the Redis database (used for session storage). **Generate your own!** | *(None - Example in file)* |
| `AUTH_SONARR` | Control whether Sonarr requires authentication (`true`/`false`). | `true` |
| `AUTH_RADARR` | Control whether Radarr requires authentication (`true`/`false`). | `true` |
| `AUTH_BAZARR` | Control whether Bazarr requires authentication (`true`/`false`). | `true` |
| `AUTH_PROWLARR` | Control whether Prowlarr requires authentication (`true`/`false`). | `true` |
| `AUTH_JELLYSEERR` | Control whether Jellyseerr requires authentication (`true`/`false`). | `true` |
| `AUTH_QBITTORRENT` | Control whether qBittorrent requires authentication (`true`/`false`). | `true` |
| `AUTH_LIDARR` | Control whether Lidarr requires authentication (`true`/`false`). | `true` |
| `AUTH_JELLYFIN` | Control whether Jellyfin requires authentication (`true`/`false`). | `false` |
| `AUTH_HOMEPAGE` | Control whether Homepage requires authentication (`true`/`false`). | `true` |
| `AUTH_FLARESOLVERR` | Control whether FlareSolverr requires authentication (`true`/`false`). | `true` |
| `AUTH_SABNZBD` | Control whether SABnzbd requires authentication (`true`/`false`). | `true` |
| `AUTH_CALIBRE` | Control whether Calibre-Web requires authentication (`true`/`false`). | `true` |
> **Note:** Authentication variables were introduced to give you fine-grained control over which services require login. Set to `false` for services you want to access without authentication.
#### Service Credentials
@ -307,23 +305,20 @@ This file controls essential settings. Copy `.env.example` to `.env` and modify
Authelia uses the `authelia/users_database.yml` file to manage users.
- **Setting the Initial Admin Password:**
1. As mentioned in the Quick Start, you **must** set a strong password for the default `admin` user.
2. Generate a hash using Docker (replace `'your_secure_password'`):
* **Setting the Initial Admin Password:**
1. As mentioned in the Quick Start, you **must** set a strong password for the default `admin` user.
2. Generate a hash using Docker (replace `'your_secure_password'`):
```bash
docker run --rm authelia/authelia:latest authelia hash-password 'your_secure_password'
```
3. Copy the **entire output hash** (starting with `$argon2id...`).
4. Open `authelia/users_database.yml` and replace the example `password:` value under `admin:` with your generated hash.
5. Ensure the `admin` user belongs to the `admins` and `users` groups as shown in the example.
3. Copy the **entire output hash** (starting with `$argon2id...`).
4. Open `authelia/users_database.yml` and replace the example `password:` value under `admin:` with your generated hash.
5. Ensure the `admin` user belongs to the `admins` and `users` groups as shown in the example.
- **Adding More Users:**
1. Generate a password hash for the new user as shown above.
2. Edit `authelia/users_database.yml`.
3. Add a new entry under `users:`, following the format of the `admin` user:
* **Adding More Users:**
1. Generate a password hash for the new user as shown above.
2. Edit `authelia/users_database.yml`.
3. Add a new entry under `users:`, following the format of the `admin` user:
```yaml
users:
admin:
@ -335,31 +330,28 @@ Authelia uses the `authelia/users_database.yml` file to manage users.
groups:
- users # Add to 'admins' group if needed
```
4. Save the file and restart Authelia: `docker compose restart authelia`.
4. Save the file and restart Authelia: `docker compose restart authelia`.
- **Adding/Updating Users (Recommended Method):**
* **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`.
4. Save the file and restart Authelia (`docker compose restart authelia`).
5. A "Register" link will now appear on the Authelia login page.
* **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`.
4. Save the file and restart Authelia (`docker compose restart authelia`).
5. A "Register" link will now appear on the Authelia login page.
- **Approving Registered Users:**
1. When a user registers (if enabled), their details are added to `authelia/users_database.yml` but marked as `disabled: true`.
2. To approve them, edit `authelia/users_database.yml`.
3. Find the new user's entry.
4. Change `disabled: true` to `disabled: false` (or simply remove the `disabled: true` line).
5. Save the file. The user should now be able to log in.
* **Approving Registered Users:**
1. When a user registers (if enabled), their details are added to `authelia/users_database.yml` but marked as `disabled: true`.
2. To approve them, edit `authelia/users_database.yml`.
3. Find the new user's entry.
4. Change `disabled: true` to `disabled: false` (or simply remove the `disabled: true` line).
5. Save the file. The user should now be able to log in.
### (Optional) VPN Configuration
@ -373,13 +365,13 @@ Authelia uses the `authelia/users_database.yml` file to manage users.
With the default Tailscale setup and Authelia enabled, services are securely accessible via HTTPS using your Tailscale node's name or IP. Authentication is controlled by the included `update-setup.sh` script.
- **Login Portal:** `https://<TAILSCALE_NODE>/` (Redirects unauthenticated users here for secured services)
- **Homepage Dashboard:** `https://<TAILSCALE_NODE>/home` (Requires login by default)
- **Sonarr:** `https://<TAILSCALE_NODE>/sonarr` (Requires login by default)
- **Radarr:** `https://<TAILSCALE_NODE>/radarr` (Requires login by default)
- **qBittorrent:** `https://<TAILSCALE_NODE>/qbittorrent` (Requires login by default)
- **Jellyfin:** `https://<TAILSCALE_NODE>/jellyfin` (Requires login by default)
- ...and so on.
* **Login Portal:** `https://<TAILSCALE_NODE>/` (Redirects unauthenticated users here for secured services)
* **Homepage Dashboard:** `https://<TAILSCALE_NODE>/home` (Requires login by default)
* **Sonarr:** `https://<TAILSCALE_NODE>/sonarr` (Requires login by default)
* **Radarr:** `https://<TAILSCALE_NODE>/radarr` (Requires login by default)
* **qBittorrent:** `https://<TAILSCALE_NODE>/qbittorrent` (Requires login by default)
* **Jellyfin:** `https://<TAILSCALE_NODE>/jellyfin` (Requires login by default)
* ...and so on.
Replace `<TAILSCALE_NODE>` with your Tailscale device name (e.g., `tailscale-nas.your-tailnet.ts.net`) or its Tailscale IP address.
@ -391,31 +383,30 @@ The `update-setup.sh` script provides various commands to manage your configurat
**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.
* `./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.
**Authelia Policy Management:**
- `./update-setup.sh manage-policies`: Starts an interactive menu to list or set Authelia access policies (`one_factor`, `two_factor`, `bypass`, `deny`) for specific services defined in `authelia/configuration.yml`.
- `./update-setup.sh list-policies`: Lists services defined in `authelia/configuration.yml` and their current access policy.
- `./update-setup.sh set-policy <service> <policy>`: Directly sets the Authelia access policy for the specified `<service>` to the given `<policy>` (e.g., `one_factor`, `two_factor`, `bypass`, `deny`).
* `./update-setup.sh manage-policies`: Starts an interactive menu to list or set Authelia access policies (`one_factor`, `two_factor`, `bypass`, `deny`) for specific services defined in `authelia/configuration.yml`.
* `./update-setup.sh list-policies`: Lists services defined in `authelia/configuration.yml` and their current access policy.
* `./update-setup.sh set-policy <service> <policy>`: Directly sets the Authelia access policy for the specified `<service>` to the given `<policy>` (e.g., `one_factor`, `two_factor`, `bypass`, `deny`).
> **Important:** After changing Authelia policies using `manage-policies` or `set-policy`, you **must** restart Authelia for the changes to take effect:
>
> ```bash
> docker compose restart authelia
> ```
**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.
* `./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.
* `./update-setup.sh help`: Displays the full list of commands and usage instructions.
### Managing Service Authentication (Authelia Policies)
@ -428,46 +419,49 @@ See the `Authelia Policy Management` commands in the [Setup Script Commands](#se
Several services are included but disabled by default. Enable them by adding their profile name to the `COMPOSE_PROFILES` variable in your `.env` file (separate multiple profiles with commas).
Example: Enable Lidarr and SABnzbd
```dotenv
COMPOSE_PROFILES=lidarr,sabnzbd
```
Available Profiles:
- `lidarr`: Music management.
- `sabnzbd`: Usenet download client.
- `flaresolverr`: Bypasses Cloudflare challenges for Prowlarr.
- `adguardhome`: Network-wide ad blocking (see `adguardhome/README.md`).
- `calibre-web`: E-book library management.
- `decluttarr`: Automated download cleanup.
- `tandoor`: Recipe management (see `tandoor/README.md`).
- `joplin`: Note-taking server (see `joplin/README.md`).
- `homeassistant`: Home automation (see `homeassistant/README.md`).
- `immich`: Photo management (see `immich/README.md`).
* `lidarr`: Music management.
* `sabnzbd`: Usenet download client.
* `flaresolverr`: Bypasses Cloudflare challenges for Prowlarr.
* `adguardhome`: Network-wide ad blocking (see `adguardhome/README.md`).
* `calibre-web`: E-book library management.
* `decluttarr`: Automated download cleanup.
* `tandoor`: Recipe management (see `tandoor/README.md`).
* `joplin`: Note-taking server (see `joplin/README.md`).
* `homeassistant`: Home automation (see `homeassistant/README.md`).
* `immich`: Photo management (see `immich/README.md`).
## Troubleshooting
### Middleware Not Found Errors
If you see error messages like `middleware "authelia-auth@docker" does not exist` in the Traefik logs, please check Authelia logs for any fatal errors. It is likely due to a misconfigured `configuration.yml` in `authelia/configuration.yml`
If you see error messages like `middleware "authelia-auth@docker" does not exist` in the Traefik logs, it could be due to one of these issues:
Make sure Traefik can access the Docker socket. See the [SELinux Socket Permissions](#selinux-socket-permissions-docker) section below for more details.
1. **Docker Network Issue:** The Traefik configuration has been updated to fix network discovery issues when running in Tailscale's network namespace. If you're still seeing this error, try restarting the stack with:
```bash
docker compose down
docker compose up -d
```
2. **Authentication Variable Missing:** Ensure you have properly configured the `AUTH_*` variables in your `.env` file for the services you want to control. If not specified, most services default to requiring authentication.
3. **Docker Socket Permissions:** Make sure Traefik can access the Docker socket. See the [SELinux Socket Permissions](#selinux-socket-permissions-docker) section below for more details.
### SELinux Socket Permissions (Docker)
If you are running Docker on a host with SELinux enabled (like Fedora, CentOS, RHEL) and services like Traefik, Watchtower, or Autoheal fail with "permission denied" errors when trying to access `/var/run/docker.sock`:
1. **Check Audit Logs:** Immediately after seeing the error, check the SELinux audit log on the host:
1. **Check Audit Logs:** Immediately after seeing the error, check the SELinux audit log on the host:
```bash
sudo ausearch -m avc -ts recent
```
Look for lines containing `denied`, `docker.sock`, and the name of the failing service (e.g., `traefik`, `watchtower`).
2. **Generate Custom Policy:** If denials are found, you may need to create a custom SELinux policy module using `audit2allow`. Pipe the denial messages into it:
2. **Generate Custom Policy:** If denials are found, you may need to create a custom SELinux policy module using `audit2allow`. Pipe the denial messages into it:
```bash
# Generate policy files (my-dockersock.te and my-dockersock.pp)
sudo ausearch -m avc -ts recent | audit2allow -M my-dockersock
@ -475,14 +469,13 @@ If you are running Docker on a host with SELinux enabled (like Fedora, CentOS, R
# Install the policy module
sudo semodule -i my-dockersock.pp
```
This allows the specific actions that were being denied. You might need to repeat this if different denials appear after applying the first policy.
### Authelia v4.38+ Configuration
Authelia v4.38+ introduces significant changes to its configuration structure, particularly for session domains and authentication flows. The setup in this repository has been carefully configured to work with these changes:
1. **Domain Configuration**:
1. **Domain Configuration**:
- You must use your specific Tailnet domain (e.g., `example.ts.net`) for cookies, not just `ts.net`
- The domain `ts.net` is part of the [Public Suffix List](https://publicsuffix.org/), which means browsers restrict cookies on it for security reasons
- Authelia will refuse to start if you try to use a domain from this list
@ -500,17 +493,17 @@ Authelia v4.38+ introduces significant changes to its configuration structure, p
- Configures cookie domains properly to avoid Public Suffix List issues
- Sets up proper access control rules for both your domain and its subdomains
If you encounter any of these common errors:
4. **File Permissions**: The Authelia container runs with your user ID and group ID, preventing permission issues when managing the configuration files with git or other tools.
```log
If you encounter any of these common errors, running the setup script should resolve them:
```
error: option 'domain' is not a valid cookie domain: the domain is part of the special public suffix list
error: option 'authelia_url' does not share a cookie scope with domain
error: can't be specified at the same time: option 'domain' and option 'cookies'
configuration key 'jwt_secret' is deprecated in 4.38.0
```
Running the setup script should resolve them. After making changes to the configuration, restart Authelia with:
After making changes to the configuration, restart Authelia with:
```bash
docker compose restart authelia
```
@ -519,17 +512,16 @@ See the [Authelia documentation](https://www.authelia.com/configuration/session/
### Tailscale Issues
- **Authentication:** Ensure your `TAILSCALE_AUTHKEY` in `.env` is valid and hasn't expired (especially if using ephemeral keys). Check the `tailscale` container logs (`docker compose logs tailscale`) for authentication errors.
- **Connectivity:** Verify the `tailscale` container is running and connected to your Tailnet (`docker compose exec tailscale tailscale status`).
- **Funnel/Serve Command:** If you modified the Tailscale command, ensure the syntax for `tailscale funnel` or `tailscale serve` is correct.
* **Authentication:** Ensure your `TAILSCALE_AUTHKEY` in `.env` is valid and hasn't expired (especially if using ephemeral keys). Check the `tailscale` container logs (`docker compose logs tailscale`) for authentication errors.
* **Connectivity:** Verify the `tailscale` container is running and connected to your Tailnet (`docker compose exec tailscale tailscale status`).
* **Funnel/Serve Command:** If you modified the Tailscale command, ensure the syntax for `tailscale funnel` or `tailscale serve` is correct.
### File Permissions
If services report permission errors when accessing `/config` or `/data` directories, double-check that:
- The `USER_ID` and `GROUP_ID` in your `.env` file match the owner/group of the corresponding `CONFIG_ROOT` and `DATA_ROOT` directories on your host.
- The host directories have appropriate read/write permissions for that user/group.
- If using SELinux, the `:Z` flag on the volume mounts in `docker-compose.yml` is correctly applied to allow the container to write to the host paths.
* The `USER_ID` and `GROUP_ID` in your `.env` file match the owner/group of the corresponding `CONFIG_ROOT` and `DATA_ROOT` directories on your host.
* The host directories have appropriate read/write permissions for that user/group.
* If using SELinux, the `:Z` flag on the volume mounts in `docker-compose.yml` is correctly applied to allow the container to write to the host paths.
## Advanced Topics

View File

@ -519,7 +519,7 @@ services:
[sh, -c, "cp -n /app/config/tpl/*.yaml /app/config && node server.js"]
labels:
- traefik.enable=true
- traefik.http.routers.homepage.rule=Host(`${APP_HOSTNAME}`) && PathPrefix(`/home`) # Changed rule to root
- traefik.http.routers.homepage.rule=Host(`${APP_HOSTNAME}`) && PathPrefix(`/`) # Changed rule to root
- traefik.http.routers.homepage.entrypoints=web
# - traefik.http.routers.homepage.priority=10 # Removed priority
# Global middleware for setting HTTPS header

View File

@ -62,7 +62,6 @@ create_backup() {
cp "$1" "$2"
}
##################################################
# PART 1: Update .env file from .env.example
##################################################
@ -206,7 +205,6 @@ update_env_file() {
echo -e "\n${BLUE}Review your updated $ENV_FILE file and adjust any values as needed.${NC}"
}
##################################################
# PART 2: Update Authelia configuration
##################################################
@ -273,427 +271,9 @@ update_authelia_config() {
# 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
if [[ -n "$existing_notifier" && "$existing_notifier" != '""' && "$existing_notifier" != "null" ]]; then
yq e -i '.notifier = strenv(existing_notifier)' --env existing_notifier="$existing_notifier" "$TEMP_CONFIG"
fi
fi
# Update domain settings from .env
echo -e "${BLUE}Applying Tailscale domain settings...${NC}"
# Update domain in session section
yq e -i ".session.cookies[0].domain = \"${TAILNET_DOMAIN}\"" "$TEMP_CONFIG"
# Update domain in access_control (find wildcard domain rule and update it)
# This assumes there's a rule with a wildcard domain like "*.example.com"
local domain_rule_index=$(yq e ".access_control.rules | map(.domain) | map(select(. == \"*.*\")) | indices" "$TEMP_CONFIG" | head -n 1 | tr -d '[]')
if [[ -n "$domain_rule_index" && "$domain_rule_index" != "null" ]]; then
yq e -i ".access_control.rules[$domain_rule_index].domain = \"${WILDCARD_DOMAIN}\"" "$TEMP_CONFIG"
fi
# Update authelia_url if it exists (it's a URL that must match cookie scope)
if yq e -e '.identity_validation.reset_password.authelia_url' "$TEMP_CONFIG" &>/dev/null; then
yq e -i ".identity_validation.reset_password.authelia_url = \"https://${FULL_HOSTNAME}\"" "$TEMP_CONFIG"
fi
# Move the temp file to the final location
mv "$TEMP_CONFIG" "$AUTHELIA_CONFIG"
echo -e "${GREEN}Authelia configuration updated successfully!${NC}"
else
echo -e "${YELLOW}Warning: 'yq' is not installed. Using sed to update configuration.${NC}"
echo -e "${YELLOW}This is less reliable and may not preserve all settings.${NC}"
# Create a new file from the example
cp "$AUTHELIA_CONFIG_EXAMPLE" "$AUTHELIA_CONFIG.new"
# Update domain settings with sed (more fragile)
sed -i "s/domain: \".*\"/domain: \"${TAILNET_DOMAIN}\"/" "$AUTHELIA_CONFIG.new"
sed -i "s/domain: \"\\*\\..*\"/domain: \"${WILDCARD_DOMAIN}\"/" "$AUTHELIA_CONFIG.new"
sed -i "s|authelia_url: \"https://.*\"|authelia_url: \"https://${FULL_HOSTNAME}\"|" "$AUTHELIA_CONFIG.new"
# Move the new file to the final location
mv "$AUTHELIA_CONFIG.new" "$AUTHELIA_CONFIG"
echo -e "${YELLOW}Authelia configuration updated with sed. Secret values might need to be manually transferred.${NC}"
fi
echo -e "${GREEN}Authelia configuration update completed.${NC}"
echo -e "${BLUE}Remember to restart Authelia for changes to take effect:${NC}"
echo -e "${CYAN} docker compose restart authelia${NC}"
}
yq e -i '.identity_validation.reset_password.jwt_secret = strenv(existing_jwt_secret)' --env existing_jwt_secret="$existing_jwt_secret" "$TEMP_CONFIG"
##################################################
# PART 3: Update service configurations
##################################################
update_service_configs() {
print_header "Service Configuration Update Tool"
# Check if Docker is running
if ! docker ps &> /dev/null; then
echo -e "${RED}Error: Docker is not running or you don't have permission to use it.${NC}"
echo -e "${YELLOW}Please start Docker and ensure your user has permission to run Docker commands.${NC}"
return 1
fi
if ! check_file "$ENV_FILE"; then
echo -e "${RED}Error: Environment file '$ENV_FILE' doesn't exist. Cannot update services.${NC}"
return 1
fi
# Get CONFIG_ROOT from .env if defined
CONFIG_ROOT=$(grep -oP "^CONFIG_ROOT=\K.*" "$ENV_FILE" | tr -d '"' | tr -d "'" || echo ".")
echo -e "${BLUE}This will update configurations for running containers and extract API keys.${NC}"
echo -e "${BLUE}Services may be restarted during this process.${NC}"
echo -e "${YELLOW}Continue? [y/N]:${NC}"
read -r answer
if [[ ! "$answer" =~ ^[Yy]$ ]]; then
echo -e "${RED}Service configuration update cancelled.${NC}"
return 0
fi
# Create a temporary .env file for updates
local ENV_TEMP="${ENV_FILE}.${TIMESTAMP}.tmp"
cp "$ENV_FILE" "$ENV_TEMP"
# Service update tracker
declare -A updated_services
declare -A api_keys_updated
# Function to restart a container if needed
restart_container() {
local service=$1
if [ "${updated_services[$service]}" == "1" ]; then
echo -e "${YELLOW}Restarting $service to apply changes...${NC}"
if docker compose restart "$service"; then
echo -e "${GREEN}$service restarted successfully!${NC}"
else
echo -e "${RED}Failed to restart $service. Please restart manually.${NC}"
fi
fi
}
# Function to extract API key from a container
extract_api_key() {
local service=$1
local config_path=$2
local api_key_pattern=$3
local env_var_name=$4
# Skip if service is not running
if ! docker compose ps "$service" 2>/dev/null | grep -q "Up"; then
echo -e "${YELLOW}Service $service is not running, skipping API key extraction.${NC}"
return 0
fi
echo -e "${BLUE}Attempting to extract API key for $service...${NC}"
# Try to get API key directly from the config file in the container
local api_key=""
if [ -n "$config_path" ] && [ -n "$api_key_pattern" ]; then
api_key=$(docker compose exec -T "$service" grep -oP "$api_key_pattern" "$config_path" 2>/dev/null | head -1 | sed 's/.*[":=]\s*\([^"]*\).*/\1/g')
fi
# If API key was found and is not empty
if [ -n "$api_key" ]; then
echo -e "${GREEN}API key for $service extracted successfully!${NC}"
# Check if the API key is already in the .env file
if grep -q "^$env_var_name=" "$ENV_TEMP"; then
local current_key=$(grep -oP "^$env_var_name=\K.*" "$ENV_TEMP" | tr -d '"' | tr -d "'")
# Only update if key is different and not empty
if [ "$current_key" != "$api_key" ] && [ -n "$current_key" ]; then
echo -e "${YELLOW}API key for $service in .env differs from extracted key.${NC}"
echo -e "${YELLOW}Would you like to update it? [y/N]:${NC}"
read -r update_key
if [[ ! "$update_key" =~ ^[Yy]$ ]]; then
echo -e "${BLUE}Keeping existing API key in .env file.${NC}"
return 0
fi
fi
# Update the existing entry
sed -i "s|^$env_var_name=.*|$env_var_name=$api_key|" "$ENV_TEMP"
else
# Add the new API key to the .env file
echo -e "\n# API key for $service (extracted $(date +"%Y-%m-%d"))" >> "$ENV_TEMP"
echo "$env_var_name=$api_key" >> "$ENV_TEMP"
fi
api_keys_updated["$service"]="1"
else
echo -e "${YELLOW}Could not extract API key for $service.${NC}"
fi
}
# Update *arr services with the correct URL base
for service in "sonarr" "radarr" "lidarr" "prowlarr" "bazarr"; do
# Skip if service is not running
if ! docker compose ps "$service" 2>/dev/null | grep -q "Up"; then
echo -e "${YELLOW}Service $service is not running, skipping.${NC}"
continue
fi
echo -e "${BLUE}Updating $service configuration...${NC}"
local config_file="/config/config.xml"
# Check if the service's config file exists
if ! docker compose exec "$service" test -f "$config_file"; then
echo -e "${YELLOW}Configuration file for $service not found, skipping.${NC}"
continue
fi
# Check current URLBase setting
local current_urlbase=$(docker compose exec -T "$service" grep -oP '<UrlBase>\K[^<]+' "$config_file" 2>/dev/null || echo "")
local desired_urlbase="/$service"
# Update URLBase if needed
if [ "$current_urlbase" != "$desired_urlbase" ]; then
echo -e "${YELLOW}$service URL base needs to be updated from '$current_urlbase' to '$desired_urlbase'.${NC}"
if [ -z "$current_urlbase" ]; then
# If URLBase tag doesn't exist, add it
docker compose exec "$service" sed -i "/<BaseUrl>/i\\ <UrlBase>$desired_urlbase</UrlBase>" "$config_file" || \
docker compose exec "$service" sed -i "/<Port>/i\\ <UrlBase>$desired_urlbase</UrlBase>" "$config_file"
else
# If URLBase exists, update it
docker compose exec "$service" sed -i "s|<UrlBase>[^<]*</UrlBase>|<UrlBase>$desired_urlbase</UrlBase>|g" "$config_file"
fi
if [ $? -eq 0 ]; then
echo -e "${GREEN}$service URL base updated to $desired_urlbase${NC}"
updated_services["$service"]="1"
else
echo -e "${RED}Failed to update $service URL base.${NC}"
fi
else
echo -e "${GREEN}$service URL base already set to $desired_urlbase${NC}"
fi
# Extract API key based on service
case "$service" in
"sonarr")
extract_api_key "$service" "$config_file" '<ApiKey>\K[^<]+' "SONARR_API_KEY"
;;
"radarr")
extract_api_key "$service" "$config_file" '<ApiKey>\K[^<]+' "RADARR_API_KEY"
;;
"lidarr")
extract_api_key "$service" "$config_file" '<ApiKey>\K[^<]+' "LIDARR_API_KEY"
;;
"prowlarr")
extract_api_key "$service" "$config_file" '<ApiKey>\K[^<]+' "PROWLARR_API_KEY"
;;
"bazarr")
# Bazarr uses a different config format (YAML/settings.ini)
extract_api_key "$service" "/config/config/config.ini" 'auth_apikey\s*=\s*\K[^#\n]+' "BAZARR_API_KEY"
;;
esac
done
# Update qBittorrent WebUI URL
if docker compose ps "qbittorrent" 2>/dev/null | grep -q "Up"; then
echo -e "${BLUE}Updating qBittorrent configuration...${NC}"
local qbit_config_dir="/config/qBittorrent"
local qbit_config_file="$qbit_config_dir/qBittorrent.conf"
# Check if the config file exists
if docker compose exec "qbittorrent" test -f "$qbit_config_file"; then
# Check current WebUI\RootFolder setting
local current_root=$(docker compose exec -T "qbittorrent" grep -oP '^WebUI\\RootFolder\s*=\s*\K.*' "$qbit_config_file" 2>/dev/null || echo "")
local desired_root="/qbittorrent"
# Update WebUI\RootFolder if needed
if [ "$current_root" != "$desired_root" ]; then
echo -e "${YELLOW}qBittorrent WebUI root needs to be updated from '$current_root' to '$desired_root'.${NC}"
if docker compose exec "qbittorrent" grep -q "^WebUI\\\\RootFolder=" "$qbit_config_file"; then
# If setting exists, update it
docker compose exec "qbittorrent" sed -i "s|^WebUI\\\\RootFolder=.*|WebUI\\\\RootFolder=$desired_root|g" "$qbit_config_file"
else
# If setting doesn't exist, add it to the [Preferences] section
if docker compose exec "qbittorrent" grep -q "^\[Preferences\]" "$qbit_config_file"; then
docker compose exec "qbittorrent" sed -i "/^\[Preferences\]/a WebUI\\\\RootFolder=$desired_root" "$qbit_config_file"
else
# Add [Preferences] section if it doesn't exist
docker compose exec "qbittorrent" bash -c "echo -e '\n[Preferences]\nWebUI\\\\RootFolder=$desired_root' >> $qbit_config_file"
fi
fi
if [ $? -eq 0 ]; then
echo -e "${GREEN}qBittorrent WebUI root updated to $desired_root${NC}"
updated_services["qbittorrent"]="1"
else
echo -e "${RED}Failed to update qBittorrent WebUI root.${NC}"
fi
else
echo -e "${GREEN}qBittorrent WebUI root already set to $desired_root${NC}"
fi
else
echo -e "${YELLOW}qBittorrent configuration file not found, skipping.${NC}"
fi
fi
# Extract Jellyfin API key
if docker compose ps "jellyfin" 2>/dev/null | grep -q "Up"; then
# Jellyfin API key is in a different location
extract_api_key "jellyfin" "/config/config/system.xml" '<ApiKey>\K[^<]+' "JELLYFIN_API_KEY"
fi
# Extract Jellyseerr API key
if docker compose ps "jellyseerr" 2>/dev/null | grep -q "Up"; then
# Jellyseerr stores API key in settings.json
extract_api_key "jellyseerr" "/app/config/settings.json" '"apiKey":\s*"\K[^"]+' "JELLYSEERR_API_KEY"
fi
# Check for optional services based on COMPOSE_PROFILES
local profiles=$(grep -oP "^COMPOSE_PROFILES=\K.*" "$ENV_FILE" | tr -d '"' | tr -d "'" || echo "")
# Process profiles as a comma-separated list
IFS=',' read -ra profile_array <<< "$profiles"
for profile in "${profile_array[@]}"; do
profile=$(echo "$profile" | xargs) # Trim whitespace
# Handle specific profiles
case "$profile" in
"sabnzbd")
if docker compose ps "sabnzbd" 2>/dev/null | grep -q "Up"; then
# Extract SABnzbd API key from its config
extract_api_key "sabnzbd" "/config/sabnzbd.ini" 'api_key\s*=\s*\K[0-9a-f]+' "SABNZBD_API_KEY"
fi
;;
"immich")
if docker compose ps "immich-server" 2>/dev/null | grep -q "Up"; then
# Extract Immich API key from user database
echo -e "${BLUE}Attempting to extract Immich API key...${NC}"
local immich_api_key=$(docker compose exec -T immich-server /usr/local/bin/cli api-key --show 2>/dev/null | grep -oP '[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}')
if [ -n "$immich_api_key" ]; then
echo -e "${GREEN}Immich API key extracted successfully!${NC}"
# Update or add the API key to the .env file
if grep -q "^IMMICH_API_KEY=" "$ENV_TEMP"; then
sed -i "s|^IMMICH_API_KEY=.*|IMMICH_API_KEY=$immich_api_key|" "$ENV_TEMP"
else
echo -e "\n# API key for Immich (extracted $(date +"%Y-%m-%d"))" >> "$ENV_TEMP"
echo "IMMICH_API_KEY=$immich_api_key" >> "$ENV_TEMP"
fi
api_keys_updated["immich"]="1"
else
echo -e "${YELLOW}Could not extract Immich API key.${NC}"
fi
fi
;;
"homeassistant")
if docker compose ps "homeassistant" 2>/dev/null | grep -q "Up"; then
echo -e "${BLUE}Home Assistant detected.${NC}"
echo -e "${YELLOW}Home Assistant requires a Long-Lived Access Token for API access.${NC}"
echo -e "${YELLOW}This must be generated manually in the Home Assistant UI:${NC}"
echo -e "${CYAN} Profile > Long-Lived Access Tokens > Create Token${NC}"
# Check if token already exists
if ! grep -q "^HOMEASSISTANT_ACCESS_TOKEN=" "$ENV_TEMP" || [ -z "$(grep -oP "^HOMEASSISTANT_ACCESS_TOKEN=\K.*" "$ENV_TEMP" | tr -d '"' | tr -d "'")" ]; then
echo -e "${YELLOW}Would you like to add a Home Assistant token now? [y/N]:${NC}"
read -r add_token
if [[ "$add_token" =~ ^[Yy]$ ]]; then
echo -e "${BLUE}Enter your Home Assistant Long-Lived Access Token:${NC}"
read -rs token
if [ -n "$token" ]; then
if grep -q "^HOMEASSISTANT_ACCESS_TOKEN=" "$ENV_TEMP"; then
sed -i "s|^HOMEASSISTANT_ACCESS_TOKEN=.*|HOMEASSISTANT_ACCESS_TOKEN=$token|" "$ENV_TEMP"
else
echo -e "\n# Home Assistant Access Token (added $(date +"%Y-%m-%d"))" >> "$ENV_TEMP"
echo "HOMEASSISTANT_ACCESS_TOKEN=$token" >> "$ENV_TEMP"
fi
api_keys_updated["homeassistant"]="1"
echo -e "${GREEN}Home Assistant token added!${NC}"
else
echo -e "${RED}No token provided. Skipping.${NC}"
fi
fi
else
echo -e "${GREEN}Home Assistant token already exists in .env${NC}"
fi
fi
;;
esac
done
# Apply changes to the .env file if any API keys were updated
if [ ${#api_keys_updated[@]} -gt 0 ]; then
echo -e "${YELLOW}API keys were extracted for these services:${NC}"
for service in "${!api_keys_updated[@]}"; do
echo -e " - ${CYAN}$service${NC}"
done
echo -e "${YELLOW}Update .env file with these API keys? [Y/n]:${NC}"
read -r update_env
if [[ ! "$update_env" =~ ^[Nn]$ ]]; then
# Backup the current .env before replacing
if [ ! -f "$ENV_BACKUP" ]; then
create_backup "$ENV_FILE" "$ENV_BACKUP"
fi
# Replace the .env file with the updated temp file
mv "$ENV_TEMP" "$ENV_FILE"
echo -e "${GREEN}API keys updated in $ENV_FILE${NC}"
else
echo -e "${YELLOW}API key updates were not saved to .env file.${NC}"
rm "$ENV_TEMP"
fi
else
echo -e "${BLUE}No API key updates were found.${NC}"
rm "$ENV_TEMP"
fi
# Restart services that were updated
if [ ${#updated_services[@]} -gt 0 ]; then
echo -e "${YELLOW}The following services had their configurations updated:${NC}"
for service in "${!updated_services[@]}"; do
echo -e " - ${CYAN}$service${NC}"
done
echo -e "${YELLOW}Would you like to restart these services now? [Y/n]:${NC}"
read -r restart_now
if [[ ! "$restart_now" =~ ^[Nn]$ ]]; then
for service in "${!updated_services[@]}"; do
restart_container "$service"
done
else
echo -e "${YELLOW}Remember to restart these services manually for changes to take effect:${NC}"
for service in "${!updated_services[@]}"; do
echo -e " ${CYAN}docker compose restart $service${NC}"
done
fi
fi
echo -e "\n${GREEN}${BOLD}Service Configuration Update Complete!${NC}"
if [ ${#updated_services[@]} -gt 0 ] || [ ${#api_keys_updated[@]} -gt 0 ]; then
echo -e "${GREEN}Services were successfully updated.${NC}"
else
echo -e "${BLUE}No changes were needed.${NC}"
fi
}
# PART 5: Authelia Account Management
##################################################
# PART 4: Authelia Policy Management
##################################################
@ -1098,22 +678,6 @@ manage_authelia_policies() {
# PART 5: Authelia Account Management
##################################################
# Function to generate a secure, random passphrase
generate_passphrase() {
# Generate a random passphrase using common words and numbers
local words=("apple" "banana" "orange" "grape" "melon" "cherry" "lemon" "peach" "plum" "kiwi"
"red" "blue" "green" "yellow" "purple" "cyan" "magenta" "white" "black" "grey"
"dog" "cat" "bird" "fish" "horse" "tiger" "lion" "bear" "wolf" "fox"
"river" "ocean" "mountain" "forest" "desert" "island" "valley" "canyon" "lake" "hill")
local w1=${words[$((RANDOM % ${#words[@]}))]}
local w2=${words[$((RANDOM % ${#words[@]}))]}
local w3=${words[$((RANDOM % ${#words[@]}))]}
local num=$((1000 + RANDOM % 9000)) # 4-digit number
echo "${w1^}${w2^}${w3^}${num}" # Capitalize first letter of each word
}
manage_authelia_accounts() {
print_header "Authelia Account Management"
@ -1369,4 +933,4 @@ case "$1" in
;;
esac
exit 0
exit 0