Compare commits
29 Commits
b58a0346d1
...
ba889f9c38
| Author | SHA1 | Date | |
|---|---|---|---|
| ba889f9c38 | |||
| 026d24a3ae | |||
| 2ae84f4481 | |||
| f3fab15ffb | |||
| db968ba5ca | |||
| 191d25e281 | |||
| f07d0937d9 | |||
| 749aa6f1cf | |||
| f4409eb258 | |||
| a74707dc1f | |||
| 5d7a162647 | |||
| a0e63e2e2b | |||
| 2fadb08c72 | |||
| 6d2baa7300 | |||
| 13b73671f8 | |||
| 2217377ae8 | |||
| ca4c3e92f0 | |||
| 3ce92b7394 | |||
| 4ad7bf0a38 | |||
| 6d9139408d | |||
| 6e17920cfd | |||
| 6b1a8b7d45 | |||
| 09b20f71fc | |||
| afbffb97e3 | |||
| 1c5959cafb | |||
| 73e40af91a | |||
| 461a0dc110 | |||
| 91873062c9 | |||
| 8a52e6894f |
286
README.md
286
README.md
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
442
update-setup.sh
442
update-setup.sh
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user