Compare commits

..

5 Commits

Author SHA1 Message Date
aki
79a7a0d4c6 fix(update-authelia): Use proper yq syntax since walk() does not exist like in jq
Some checks failed
/ validate-docker-compose (push) Has been cancelled
2025-04-27 00:05:43 +08:00
aki
93e709841b refactor(update-setup): Simplify Authelia configuration updates and improve placeholder replacements
Some checks failed
/ validate-docker-compose (push) Has been cancelled
2025-04-26 21:09:07 +08:00
aki
78338661b0 docs(README): Update README
- Add detailed setup instructions
- Clarify configuration variables
- Update sections on architecture, features, prerequisites, and troubleshooting to reflect recent changes.
2025-04-26 17:56:02 +08:00
aki
9f8ff41bf4 feat(update-setup)!: Replace update-config.sh with a new script to manage setup 2025-04-26 17:54:36 +08:00
aki
67ff6d585c feat!: Use Authelia authentication to protect endpoints
- Uses Authelia as an authentication middleware and access control, with sensible policy
- Redis as Authelia's backend for session data
- Add https-proto middleware
- Add/update example files
2025-04-26 17:53:18 +08:00
9 changed files with 1884 additions and 349 deletions

View File

@@ -36,9 +36,10 @@ TAILSCALE_TAGS=tag:nas
# Enable Tailscale Funnel (public access) for HTTPS? Set to 'true' or 'false'. 'false' uses Serve (Tailnet only, recommended).
ENABLE_FUNNEL_HTTPS=false
# --- Primary Hostname ---
# Primary hostname used by Traefik for routing. Derived from Tailscale settings by default.
HOSTNAME=${TAILSCALE_HOSTNAME}.${TAILSCALE_TAILNET_DOMAIN}
# --- Primary Application Hostname ---
# Primary hostname used by Traefik/Authelia. Derived from Tailscale settings by default.
# Renamed from HOSTNAME to avoid collision with host system environment variable.
APP_HOSTNAME=${TAILSCALE_HOSTNAME}.${TAILSCALE_TAILNET_DOMAIN}
# --- Application Credentials ---
# qBittorrent Web UI Credentials (change default!)
@@ -62,14 +63,16 @@ HOMEPAGE_VAR_WEATHER_UNIT=metric
# --- Authelia Settings ---
# Generate strong random secrets for these using tools like `openssl rand -hex 32`
AUTHELIA_JWT_SECRET= # Example: your_strong_jwt_secret
AUTHELIA_SESSION_SECRET= # Example: your_strong_session_secret
AUTHELIA_STORAGE_ENCRYPTION_KEY= # Example: your_strong_storage_encryption_key
AUTHELIA_REDIS_PASSWORD= # Example: your_strong_redis_password
# These are all REQUIRED for Authelia to function properly
AUTHELIA_JWT_SECRET= # Secret used for JWT tokens (password reset, etc)
AUTHELIA_SESSION_SECRET= # Secret for encrypting session cookies
AUTHELIA_STORAGE_ENCRYPTION_KEY= # Secret for encrypting stored data
AUTHELIA_REDIS_PASSWORD= # Password for Redis session storage
# Authelia Session Configuration
AUTHELIA_SESSION_DOMAIN=${HOSTNAME}
AUTHELIA_DEFAULT_REDIRECT_URL=https://${HOSTNAME}/home
# Note: The following variables are no longer needed with Authelia 4.38+ and the updated configuration
# They are preserved for backward compatibility but will be automatically mapped to the new structure
# AUTHELIA_SESSION_DOMAIN=${APP_HOSTNAME}
# AUTHELIA_DEFAULT_REDIRECT_URL=https://${APP_HOSTNAME}/home
# --- API Keys & Integration Tokens (Optional - Mainly for Homepage Widgets) ---
# Find API keys within each application's settings (usually Settings > General or Security)

3
.gitignore vendored
View File

@@ -1,6 +1,9 @@
*.env
*.bak
.idea
docker-compose.override.yml
/authelia/*.yml
!/authelia/*.example.yml
/homepage/logs
/homepage/*.yaml
/homepage/*.css

448
README.md
View File

@@ -11,22 +11,27 @@ The core idea is to manage media libraries (movies, TV shows, music), automate d
- [Architecture Overview](#architecture-overview)
- [Features](#features)
- [Prerequisites](#prerequisites)
- [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)
- [Optional Services](#optional-services)
- [Troubleshooting](#troubleshooting)
- [Middleware Not Found Errors](#middleware-not-found-errors)
- [SELinux Socket Permissions (Docker)](#selinux-socket-permissions-docker)
- [Authelia v4.38+ Configuration](#authelia-v438-configuration)
- [Tailscale Issues](#tailscale-issues)
- [File Permissions](#file-permissions)
- [Advanced Topics](#advanced-topics)
@@ -35,104 +40,175 @@ 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.
- **[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).
- **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).
## Required Setup Steps
These steps are **mandatory** for a working installation. Without properly completing these, the stack will not function correctly.
1. **⚠️ Required: System User Information**
- Set `USER_ID` and `GROUP_ID` in `.env` (run `id -u` and `id -g` to get yours)
- Incorrect values will cause permission errors with mounted volumes
2. **⚠️ Required: Directory Paths**
- Set `CONFIG_ROOT` (where service configurations will be stored)
- Set `DATA_ROOT` (where your media libraries will be stored)
- Set `DOWNLOAD_ROOT` (must be on same filesystem as DATA_ROOT for hardlinks)
3. **⚠️ Required: Tailscale Configuration**
- Create a Tailscale account at [tailscale.com](https://tailscale.com)
- Generate an Auth Key in the [Tailscale Admin Console](https://login.tailscale.com/admin/settings/keys)
- Set `TAILSCALE_AUTHKEY` in `.env`
- Set `TAILSCALE_TAILNET_DOMAIN` to your Tailnet domain (e.g., `your-name.ts.net`)
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**
- 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
## Quick Start Guide
This guide gets the core stack running quickly. **Read the full [Configuration](#configuration-env-variables) section afterwards for details.**
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
```
1. **Clone Repository:**
2. **Create `.env` File:**
```bash
cp .env.example .env
```
```bash
git clone https://github.com/AdrienPoupa/docker-compose-nas.git
cd docker-compose-nas
```
3. **Critical `.env` Edits:** Open `.env` and set **at minimum**:
* `USER_ID` & `GROUP_ID`: Run `id -u` and `id -g` on your host to find these.
* `TIMEZONE`: Your local timezone (e.g., `Asia/Manila`).
* `TAILSCALE_AUTHKEY`: Generate an auth key in your [Tailscale Admin Console](https://login.tailscale.com/admin/settings/keys).
* `TAILSCALE_TAILNET_DOMAIN`: Your unique Tailnet domain (e.g., `your-name.ts.net`).
* `AUTHELIA_JWT_SECRET`, `AUTHELIA_SESSION_SECRET`, `AUTHELIA_STORAGE_ENCRYPTION_KEY`, `AUTHELIA_REDIS_PASSWORD`: **Generate unique, strong secrets** for these (e.g., using `openssl rand -hex 32`). **Do not use the examples!**
2. **Configure Environment:**
4. **Set Authelia Admin Password:**
* Generate a password hash (replace `'your_secure_password'`):
```bash
docker run --rm authelia/authelia:latest authelia hash-password 'your_secure_password'
```
* Copy the **entire output hash** (starting with `$argon2id...`).
* Open `authelia/users_database.yml` and replace the example `password:` value under `admin:` with your generated hash.
```bash
# Create an .env file from the example
cp .env.example .env
5. **Start the Stack:**
```bash
# Make helper script executable (if needed)
chmod +x ./update-config.sh
# Start containers
docker compose up -d
```
*(Wait for containers to download and start)*
# Edit the .env file and fill in ALL required values
nano .env
```
6. **(Optional) Run Config Script:** This attempts to set API keys/URLs in *arr apps based on `.env`. May require manual adjustments in apps later.
```bash
./update-config.sh
```
3. **Configure Authelia Admin:**
7. **Access:** Navigate to `https://<TAILSCALE_HOSTNAME>.<TAILSCALE_TAILNET_DOMAIN>/`. You should be redirected to the Authelia login. Use `admin` and the password you set in step 4. After login, you'll land on the Homepage dashboard at `/home`.
```bash
# Generate a password hash
docker run --rm authelia/authelia:latest authelia hash-password 'your_secure_password'
# Edit the users_database.yml with the generated hash
nano authelia/users_database.yml
```
4. **Run the Setup Script:**
```bash
# Make the script executable
chmod +x ./update-setup.sh
# 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:**
- Open `https://<TAILSCALE_HOSTNAME>.<TAILSCALE_TAILNET_DOMAIN>/`
- Log in with username `admin` and the password you set
- After login, you'll land on the Homepage dashboard at `/home`
> ⚠️ **IMPORTANT:** If the stack fails to start, check the [Troubleshooting](#troubleshooting) section and verify you've properly completed all [Required Setup Steps](#required-setup-steps).
## Configuration (`.env` Variables)
@@ -159,18 +235,16 @@ This file controls essential settings. Copy `.env.example` to `.env` and modify
| `TAILSCALE_HOSTNAME` | Desired hostname for this NAS within Tailscale. | `tailscale-nas` |
| `TAILSCALE_TAGS` | Optional tags for the Tailscale node (e.g., `tag:nas`). | `tag:nas` |
| `ENABLE_FUNNEL_HTTPS` | Use Tailscale Funnel (`true` = public access via Tailscale domain) or Serve (`false` = Tailnet-only access, recommended). | `false` |
| `HOSTNAME` | Primary hostname used by Traefik/Authelia. Defaults to Tailscale FQDN. Can be overridden if using custom DNS pointing to Tailscale IP. | `${TAILSCALE_HOSTNAME}.${TAILSCALE_TAILNET_DOMAIN}` |
| `APP_HOSTNAME` | Primary hostname used by Traefik/Authelia. Defaults to Tailscale FQDN. Renamed from `HOSTNAME` to avoid host system conflicts. Can be overridden if using custom DNS. | `${TAILSCALE_HOSTNAME}.${TAILSCALE_TAILNET_DOMAIN}` |
#### Authentication (Authelia)
| Variable | Description | Default |
| :---------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------- |
| **`AUTHELIA_JWT_SECRET`** | **Required.** Random secret for signing JWTs. **Generate your own!** | *(None - Example in file)* |
| **`AUTHELIA_JWT_SECRET`** | **Required.** Random secret for Authelia (used for password reset JWT). **Generate your own!** | *(None - Example in file)* |
| **`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. **Generate your own!** | *(None - Example in file)* |
| **`AUTHELIA_REDIS_PASSWORD`** | **Required.** Password for the Redis database. **Generate your own!** | *(None - Example in file)* |
| `AUTHELIA_SESSION_DOMAIN` | Domain for session cookies. Should match `HOSTNAME`. | `${HOSTNAME}` |
| `AUTHELIA_DEFAULT_REDIRECT_URL` | Where users land after login. | `https://${HOSTNAME}/home` |
| **`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)* |
#### Service Credentials
@@ -233,20 +307,23 @@ 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.
* **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:
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:
```yaml
users:
admin:
@@ -258,30 +335,31 @@ Authelia uses the `authelia/users_database.yml` file to manage users.
groups:
- users # Add to 'admins' group if needed
```
4. Save the file. Authelia should pick up the changes automatically (or restart the Authelia container: `docker compose restart authelia`).
* **Enabling User Registration (Optional):**
1. Edit `authelia/configuration.yml`.
2. Find the commented-out `registration:` section near the bottom.
3. Uncomment it and set `enable: true`:
```yaml
# registration:
# enable: false # Set to true to enable registration form
```
becomes:
```yaml
registration:
enable: true
```
4. Save the file and restart Authelia (`docker compose restart authelia`).
5. A "Register" link will now appear on the Authelia login page.
4. Save the file and restart Authelia: `docker compose restart authelia`.
* **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.
- **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.
- **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
@@ -293,54 +371,103 @@ Authelia uses the `authelia/users_database.yml` file to manage users.
## Service Access
With the default Tailscale setup and Authelia enabled, services are securely accessible via HTTPS using your Tailscale node's name or IP. Access requires authentication via Authelia.
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)
* **Homepage Dashboard:** `https://<TAILSCALE_NODE>/home` (Accessible after login)
* **Sonarr:** `https://<TAILSCALE_NODE>/sonarr` (Requires login)
* **Radarr:** `https://<TAILSCALE_NODE>/radarr` (Requires login)
* **qBittorrent:** `https://<TAILSCALE_NODE>/qbittorrent`
* **Jellyfin:** `https://<TAILSCALE_NODE>/jellyfin`
* ...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.
If you configure DNS for your `HOSTNAME` variable to point to the Tailscale IP, you can use `https://<HOSTNAME>/<service_path>`.
If you configure DNS for your `APP_HOSTNAME` variable to point to the Tailscale IP, you can use `https://<APP_HOSTNAME>/<service_path>`.
### Setup Script Commands (`update-setup.sh`)
The `update-setup.sh` script provides various commands to manage your configuration. Run `./update-setup.sh help` to see all options.
**Core Setup & Updates:**
- `./update-setup.sh update-env`: Updates `.env` from `.env.example`, preserving existing values and highlighting new/deprecated keys.
- `./update-setup.sh update-authelia`: Updates `authelia/configuration.yml` from the example, applying domain settings from `.env` and attempting to preserve secrets (uses `yq` if available).
- `./update-setup.sh update-services`: Updates configurations for running *arr/qBittorrent/Bazarr containers (sets URL base, extracts API keys to `.env`). Restarts affected containers.
- `./update-setup.sh all`: Runs `update-env`, `update-authelia`, and `update-services` sequentially. Recommended for initial setup and major updates.
**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`).
> **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.
**Help:**
- `./update-setup.sh help`: Displays the full list of commands and usage instructions.
### Managing Service Authentication (Authelia Policies)
Use the `update-setup.sh` script to easily control which services require Authelia login and what level of authentication is needed. This is done by managing *access control rules* within Authelia's configuration (`authelia/configuration.yml`).
See the `Authelia Policy Management` commands in the [Setup Script Commands](#setup-script-commands-update-setupsh) section above for details on how to list and set policies like `one_factor`, `two_factor`, `bypass`, or `deny` for each service.
## Optional Services
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`
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
@@ -348,20 +475,61 @@ 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**:
- 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
2. **Required Secret Variables**: You must set these four variables in your `.env` file:
- `AUTHELIA_JWT_SECRET`: Used for password reset tokens
- `AUTHELIA_SESSION_SECRET`: Used for session cookie encryption
- `AUTHELIA_STORAGE_ENCRYPTION_KEY`: Used for database encryption
- `AUTHELIA_REDIS_PASSWORD`: Used for Redis authentication
Generate strong random values for these with: `openssl rand -hex 32`
3. **Automatic Domain Setup**: The `update-setup.sh` script automatically:
- Uses your specific Tailnet domain (e.g., `example.ts.net`) from your `.env` file
- 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:
```log
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:
```bash
docker compose restart authelia
```
See the [Authelia documentation](https://www.authelia.com/configuration/session/introduction/) for more details on the v4.38+ configuration structure.
### 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

@@ -0,0 +1,140 @@
# Authelia Configuration File v4.38+
# Documentation: https://www.authelia.com/configuration/
# Server settings
server:
address: 'tcp://0.0.0.0:9091'
# Logging configuration
log:
level: info
format: text
# Session configuration for v4.38+
session:
name: authelia_session
secret: ${AUTHELIA_SESSION_SECRET}
expiration: 1h
inactivity: 5m
redis:
host: redis
port: 6379
password: ${AUTHELIA_SESSION_REDIS_PASSWORD}
database_index: 0
cookies:
# Using your specific Tailscale domain (e.g. example.ts.net) not just ts.net
- domain: 'your-tailnet.ts.net'
authelia_url: 'https://tailscale-nas.your-tailnet.ts.net'
default_redirection_url: 'https://tailscale-nas.your-tailnet.ts.net/home'
same_site: lax
# Regulation (brute force protection)
regulation:
max_retries: 3
find_time: 2m
ban_time: 5m
# Storage (for user preferences, etc. - encrypted using storage key)
storage:
encryption_key: ${AUTHELIA_STORAGE_ENCRYPTION_KEY}
local:
path: /config/db.sqlite3
# Authentication backend (using file-based user database)
authentication_backend:
file:
path: /config/users_database.yml
password:
algorithm: argon2id
iterations: 1
memory: 1024
parallelism: 8
salt_length: 16
key_length: 32
# Access control rules
access_control:
default_policy: deny # Deny access by default
rules:
# Rules are processed in order. First match wins.
# It's recommended to put more specific rules first.
# 1. Bypass rules (No authentication required)
# Allow access to Authelia's own endpoints
- domain: '*.your-tailnet.ts.net'
path_regex: '^/auth.*' # Match /auth and anything after it
policy: bypass
# Allow access to the root path (will be redirected by Traefik later)
- domain: '*.your-tailnet.ts.net'
path: '/'
policy: bypass
# Allow access to API endpoints (as requested, review security implications)
- domain: '*.your-tailnet.ts.net'
path_regex: '^/api.*' # Match /api and anything after it
policy: bypass
# 2. One-Factor Authentication Rules (Requires login)
# Add rules for each service you want to protect.
# The domain should match your Tailscale domain.
# The path should match the Traefik PathPrefix for the service.
- domain: '*.your-tailnet.ts.net'
path_regex: '^/sonarr.*'
policy: one_factor
- domain: '*.your-tailnet.ts.net'
path_regex: '^/radarr.*'
policy: one_factor
- domain: '*.your-tailnet.ts.net'
path_regex: '^/lidarr.*'
policy: one_factor
- domain: '*.your-tailnet.ts.net'
path_regex: '^/bazarr.*'
policy: one_factor
- domain: '*.your-tailnet.ts.net'
path_regex: '^/qbittorrent.*'
policy: one_factor
- domain: '*.your-tailnet.ts.net'
path_regex: '^/sabnzbd.*'
policy: one_factor
- domain: '*.your-tailnet.ts.net'
path_regex: '^/calibre.*'
policy: one_factor
- domain: '*.your-tailnet.ts.net'
path_regex: '^/home.*' # Protect the homepage
policy: one_factor
- domain: '*.your-tailnet.ts.net'
path_regex: '^/jellyseerr.*'
policy: one_factor
- domain: '*.your-tailnet.ts.net'
path_regex: '^/prowlarr.*'
policy: one_factor
- domain: '*.your-tailnet.ts.net'
path_regex: '^/flaresolverr.*'
policy: one_factor
# Add other services here following the pattern:
# - domain: '*.your-tailnet.ts.net'
# path_regex: '^/<service_path>.*'
# policy: one_factor
# 3. Default rule for the domain (optional, if you want a catch-all)
# This rule will apply if no path-specific rule above matches.
# You might want to deny or require one_factor for unmatched paths.
# Example: Deny any other path on the domain
# - domain: '*.your-tailnet.ts.net'
# policy: deny
# Example: Require login for any other path
# - domain: '*.your-tailnet.ts.net'
# policy: one_factor
# Notifier configuration
notifier:
filesystem:
filename: /config/notification.txt
# Identity Validation (includes JWT secret for password reset)
identity_validation:
reset_password:
jwt_secret: ${AUTHELIA_JWT_SECRET}
# Identity Providers
identity_providers:
oidc: null

View File

@@ -1,83 +0,0 @@
# Authelia Configuration File
# Documentation: https://www.authelia.com/configuration/
# Default configuration options affecting multiple sections.
default_redirection_url: ${AUTHELIA_DEFAULT_REDIRECT_URL}
# Server settings (listening address, paths, etc.)
server:
host: 0.0.0.0
port: 9091
# Logging configuration
log:
level: info
format: text # or json
# Session configuration
session:
name: authelia_session
secret: ${AUTHELIA_SESSION_SECRET}
expiration: 1h # Adjust as needed
inactivity: 5m # Adjust as needed
domain: ${AUTHELIA_SESSION_DOMAIN} # Set from .env
redis:
host: redis
port: 6379
password: ${AUTHELIA_REDIS_PASSWORD}
database_index: 0
# Regulation (brute force protection)
regulation:
max_retries: 3
find_time: 2m
ban_time: 5m
# Storage (for user preferences, etc. - encrypted using storage key)
storage:
encryption_key: ${AUTHELIA_STORAGE_ENCRYPTION_KEY}
local:
path: /config/db.sqlite3 # Example using SQLite for simple storage needs
# Authentication backend (using file-based user database)
authentication_backend:
file:
path: /config/users_database.yml
password:
algorithm: argon2id # Recommended hashing algorithm
iterations: 1
memory: 1024 # MiB
parallelism: 8
salt_length: 16
key_length: 32
# Access control rules
access_control:
default_policy: deny # Deny access by default
rules:
# Rule to allow authenticated users access to the domain
- domain: ${AUTHELIA_SESSION_DOMAIN}
policy: one_factor # Requires username/password
# Notifier (Optional, for password resets, etc. - configure if needed)
# notifier:
# smtp:
# address: smtp.example.com:587
# username: user@example.com
# password: password
# sender: Authelia <authelia@example.com>
# subject: "[Authelia] {title}"
# startup_check_address: test@authelia.com
# JWT configuration (used for forwardAuth)
jwt_secret: ${AUTHELIA_JWT_SECRET}
# Identity Providers (None configured for this setup)
identity_providers:
oidc: null # Explicitly disable OIDC
# Enable registration (requires manual approval by editing users_database.yml)
# Set 'enable: true' to allow users to register.
# They will be added to users_database.yml commented out or with disabled: true.
# registration:
# enable: false # Set to true to enable registration form

View File

@@ -13,14 +13,11 @@ services:
- --experimental.plugins.rewrite-body.version=v1.2.0
- --experimental.plugins.rewriteHeaders.modulename=github.com/XciD/traefik-plugin-rewrite-headers
- --experimental.plugins.rewriteHeaders.version=v0.0.3
network_mode: service:tailscale # Add this line
# ports: # Remove this section
# - "80:80"
# - "443:443"
- --providers.docker.network=docker-compose-nas
- --providers.docker.endpoint=unix:///var/run/docker.sock
network_mode: service:tailscale
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
# extra_hosts: # Remove this section
# - host.docker.internal:172.17.0.1
healthcheck:
test: ["CMD", "traefik", "healthcheck", "--ping"]
interval: 30s
@@ -31,11 +28,11 @@ services:
restart: always
environment:
- REDIS_PASSWORD=${AUTHELIA_REDIS_PASSWORD}
command: ["redis-server", "--requirepass", "$$REDIS_PASSWORD"] # Use $$ to escape $ for compose
command: ["redis-server", "--requirepass", "${AUTHELIA_REDIS_PASSWORD}"]
volumes:
- ${CONFIG_ROOT:-.}/redis:/data:Z
healthcheck:
test: ["CMD", "redis-cli", "-a", "$$REDIS_PASSWORD", "ping"] # Use $$ to escape $ for compose
test: ["CMD", "redis-cli", "-a", "${AUTHELIA_REDIS_PASSWORD}", "ping"]
interval: 5s
timeout: 3s
retries: 5
@@ -43,32 +40,29 @@ services:
image: authelia/authelia:latest
container_name: authelia
restart: always
user: ${USER_ID}:${GROUP_ID}
volumes:
- ${CONFIG_ROOT:-.}/authelia:/config:Z
environment:
- AUTHELIA_JWT_SECRET=${AUTHELIA_JWT_SECRET}
- AUTHELIA_SESSION_SECRET=${AUTHELIA_SESSION_SECRET}
- AUTHELIA_STORAGE_ENCRYPTION_KEY=${AUTHELIA_STORAGE_ENCRYPTION_KEY}
- AUTHELIA_REDIS_PASSWORD=${AUTHELIA_REDIS_PASSWORD}
- AUTHELIA_SESSION_DOMAIN=${AUTHELIA_SESSION_DOMAIN}
- AUTHELIA_DEFAULT_REDIRECT_URL=${AUTHELIA_DEFAULT_REDIRECT_URL}
- AUTHELIA_SESSION_REDIS_PASSWORD=${AUTHELIA_REDIS_PASSWORD}
- AUTHELIA_IDENTITY_VALIDATION_RESET_PASSWORD_JWT_SECRET=${AUTHELIA_JWT_SECRET}
- TZ=${TIMEZONE}
labels:
- traefik.enable=true
# Rule for Authelia portal itself (handles internal paths like /api, /logout etc.)
- traefik.http.routers.authelia.rule=Host(`${HOSTNAME}`)
- traefik.http.routers.authelia.rule=Host(`${APP_HOSTNAME}`) && PathPrefix(`/auth`) # Changed rule
- traefik.http.routers.authelia.entrypoints=web
- traefik.http.routers.authelia.priority=100 # High priority to catch root path
# - traefik.http.routers.authelia.priority=100 # Removed priority
- traefik.http.services.authelia.loadbalancer.server.port=9091
# Define the forwardAuth middleware
- traefik.http.middlewares.authelia-auth.forwardAuth.address=http://authelia:9091/api/verify?rd=https://${HOSTNAME}/
- traefik.http.middlewares.authelia-auth.forwardAuth.address=http://authelia:9091/api/verify # Simplified forwardAuth address
- traefik.http.routers.authelia.middlewares=https-proto@docker
- traefik.http.middlewares.authelia-auth.forwardAuth.trustForwardHeader=true
- traefik.http.middlewares.authelia-auth.forwardAuth.authResponseHeaders=Remote-User,Remote-Groups,Remote-Name,Remote-Email
# Homepage labels for Authelia itself (optional, but can be nice)
- homepage.group=Security
- homepage.name=Authelia
- homepage.icon=authelia.png # You might need to add this icon
- homepage.href=https://${HOSTNAME}/ # Link to the login portal
- homepage.icon=authelia.png
- homepage.href=/auth # Updated href
- homepage.description=Authentication Portal
sonarr:
image: lscr.io/linuxserver/sonarr
@@ -87,9 +81,9 @@ services:
retries: 10
labels:
- traefik.enable=true
- traefik.http.routers.sonarr.rule=PathPrefix(`/sonarr`)
- traefik.http.routers.sonarr.rule=Host(`${APP_HOSTNAME}`) && PathPrefix(`/sonarr`) # Added Host check
- traefik.http.routers.sonarr.entrypoints=web
- traefik.http.routers.sonarr.middlewares=authelia-auth@docker
- traefik.http.routers.sonarr.middlewares=https-proto@docker,authelia-auth@docker
- traefik.http.services.sonarr.loadbalancer.server.port=8989
- homepage.group=Media
- homepage.name=Sonarr
@@ -117,9 +111,9 @@ services:
retries: 10
labels:
- traefik.enable=true
- traefik.http.routers.radarr.rule=PathPrefix(`/radarr`)
- traefik.http.routers.radarr.rule=Host(`${APP_HOSTNAME}`) && PathPrefix(`/radarr`) # Added Host check
- traefik.http.routers.radarr.entrypoints=web
- traefik.http.routers.radarr.middlewares=authelia-auth@docker
- traefik.http.routers.radarr.middlewares=https-proto@docker,authelia-auth@docker
- traefik.http.services.radarr.loadbalancer.server.port=7878
- homepage.group=Media
- homepage.name=Radarr
@@ -147,9 +141,9 @@ services:
retries: 10
labels:
- traefik.enable=true
- traefik.http.routers.lidarr.rule=PathPrefix(`/lidarr`)
- traefik.http.routers.lidarr.rule=Host(`${APP_HOSTNAME}`) && PathPrefix(`/lidarr`) # Added Host check
- traefik.http.routers.lidarr.entrypoints=web
- traefik.http.routers.lidarr.middlewares=authelia-auth@docker
- traefik.http.routers.lidarr.middlewares=https-proto@docker,authelia-auth@docker
- traefik.http.services.lidarr.loadbalancer.server.port=8686
- homepage.group=Media
- homepage.name=Lidarr
@@ -179,9 +173,9 @@ services:
retries: 10
labels:
- traefik.enable=true
- traefik.http.routers.bazarr.rule=PathPrefix(`/bazarr`)
- traefik.http.routers.bazarr.rule=Host(`${APP_HOSTNAME}`) && PathPrefix(`/bazarr`) # Added Host check
- traefik.http.routers.bazarr.entrypoints=web
- traefik.http.routers.bazarr.middlewares=authelia-auth@docker
- traefik.http.routers.bazarr.middlewares=https-proto@docker,authelia-auth@docker
- traefik.http.services.bazarr.loadbalancer.server.port=6767
- homepage.group=Download
- homepage.name=Bazarr
@@ -214,10 +208,10 @@ services:
retries: 10
labels:
- traefik.enable=true
- traefik.http.routers.jellyseerr.rule=PathPrefix(`/jellyseerr`)
- traefik.http.routers.jellyseerr.rule=Host(`${APP_HOSTNAME}`) && PathPrefix(`/jellyseerr`) # Added Host check
- traefik.http.routers.jellyseerr.entrypoints=web
- traefik.http.services.jellyseerr.loadbalancer.server.port=5055
- traefik.http.routers.jellyseerr.middlewares=jellyseerr-stripprefix,jellyseerr-rewrite,jellyseerr-rewriteHeaders,authelia-auth@docker
- traefik.http.routers.jellyseerr.middlewares=https-proto@docker,jellyseerr-stripprefix,jellyseerr-rewrite,jellyseerr-rewriteHeaders,authelia-auth@docker
- traefik.http.middlewares.jellyseerr-stripprefix.stripPrefix.prefixes=/jellyseerr
- traefik.http.middlewares.jellyseerr-rewriteHeaders.plugin.rewriteHeaders.rewrites[0].header=location
- traefik.http.middlewares.jellyseerr-rewriteHeaders.plugin.rewriteHeaders.rewrites[0].regex=^/(.+)$
@@ -288,9 +282,9 @@ services:
retries: 10
labels:
- traefik.enable=true
- traefik.http.routers.prowlarr.rule=PathPrefix(`/prowlarr`)
- traefik.http.routers.prowlarr.rule=Host(`${APP_HOSTNAME}`) && PathPrefix(`/prowlarr`) # Added Host check
- traefik.http.routers.prowlarr.entrypoints=web
- traefik.http.routers.prowlarr.middlewares=authelia-auth@docker
- traefik.http.routers.prowlarr.middlewares=https-proto@docker,authelia-auth@docker
- traefik.http.services.prowlarr.loadbalancer.server.port=9696
- homepage.group=Download
- homepage.name=Prowlarr
@@ -312,9 +306,9 @@ services:
- TZ=${TIMEZONE}
labels:
- traefik.enable=true
- traefik.http.routers.flaresolverr.rule=PathPrefix(`/flaresolverr`)
- traefik.http.routers.flaresolverr.rule=Host(`${APP_HOSTNAME}`) && PathPrefix(`/flaresolverr`) # Added Host check
- traefik.http.routers.flaresolverr.entrypoints=web
- traefik.http.routers.flaresolverr.middlewares=authelia-auth@docker
- traefik.http.routers.flaresolverr.middlewares=https-proto@docker,authelia-auth@docker
- traefik.http.services.flaresolverr.loadbalancer.server.port=8191
profiles:
- flaresolverr
@@ -332,25 +326,20 @@ services:
- ${DOWNLOAD_ROOT}:/data/torrents:Z
restart: always
healthcheck:
# Container may fail if the PIA's token expired, so mark as unhealthy when there is no internet connection
# see: https://github.com/qdm12/gluetun/issues/641#issuecomment-933856220
test:
["CMD", "curl", "--fail", "http://127.0.0.1:8080", "https://google.com"]
interval: 30s
retries: 10
labels:
- traefik.enable=true
- traefik.http.routers.qbittorrent.rule=PathPrefix(`/qbittorrent`)
- traefik.http.routers.qbittorrent.rule=Host(`${APP_HOSTNAME}`) && PathPrefix(`/qbittorrent`) # Added Host check
- traefik.http.routers.qbittorrent.entrypoints=web
- traefik.http.services.qbittorrent.loadbalancer.server.port=8080
- traefik.http.routers.qbittorrent.middlewares=qbittorrent-strip-slash,qbittorrent-stripprefix,authelia-auth@docker
# https://github.com/qbittorrent/qBittorrent/issues/5693#issuecomment-552146296
- traefik.http.routers.qbittorrent.middlewares=https-proto@docker,qbittorrent-strip-slash,qbittorrent-stripprefix,authelia-auth@docker
- traefik.http.middlewares.qbittorrent-stripprefix.stripPrefix.prefixes=/qbittorrent
# https://community.traefik.io/t/middleware-to-add-the-if-needed/1895/19
- traefik.http.middlewares.qbittorrent-strip-slash.redirectregex.regex=(^.*\/qbittorrent$$)
- traefik.http.middlewares.qbittorrent-strip-slash.redirectregex.replacement=$$1/
- traefik.http.middlewares.qbittorrent-strip-slash.redirectregex.permanent=false
#- com.centurylinklabs.watchtower.depends-on=/vpn
- homepage.group=Download
- homepage.name=qBittorrent
- homepage.icon=qbittorrent.png
@@ -389,9 +378,9 @@ services:
restart: always
labels:
- traefik.enable=true
- traefik.http.routers.sabnzbd.rule=PathPrefix(`/sabnzbd`) # Simplified rule
- traefik.http.routers.sabnzbd.rule=Host(`${APP_HOSTNAME}`) && PathPrefix(`/sabnzbd`) # Added Host check
- traefik.http.routers.sabnzbd.entrypoints=web
- traefik.http.routers.sabnzbd.middlewares=authelia-auth@docker
- traefik.http.routers.sabnzbd.middlewares=https-proto@docker,authelia-auth@docker
- traefik.http.services.sabnzbd.loadbalancer.server.port=8080
- homepage.group=Download
- homepage.name=Sabnzbd
@@ -411,7 +400,7 @@ services:
- PUID=${USER_ID}
- PGID=${GROUP_ID}
- TZ=${TIMEZONE}
- JELLYFIN_PublishedServerUrl=${TAILSCALE_HOSTNAME}.${TAILSCALE_TAILNET_DOMAIN}/jellyfin
- JELLYFIN_PublishedServerUrl=https://${TAILSCALE_HOSTNAME}.${TAILSCALE_TAILNET_DOMAIN}/jellyfin
volumes:
- ${CONFIG_ROOT:-.}/jellyfin:/config:Z
- ${DATA_ROOT}:/data:Z
@@ -425,9 +414,9 @@ services:
retries: 10
labels:
- traefik.enable=true
- traefik.http.routers.jellyfin.rule=PathPrefix(`/jellyfin`)
- traefik.http.routers.jellyfin.rule=Host(`${APP_HOSTNAME}`) && PathPrefix(`/jellyfin`) # Added Host check
- traefik.http.routers.jellyfin.entrypoints=web
- traefik.http.routers.jellyfin.middlewares=authelia-auth@docker
- traefik.http.routers.jellyfin.middlewares=https-proto@docker # Only HTTPS, no auth
- traefik.http.services.jellyfin.loadbalancer.server.port=8096
- homepage.group=Media
- homepage.name=Jellyfin
@@ -456,8 +445,8 @@ services:
- traefik.http.middlewares.calibre-headers.headers.customRequestHeaders.X-Scheme=https
- traefik.http.middlewares.calibre-headers.headers.customRequestHeaders.X-Script-Name=/calibre
- traefik.http.middlewares.calibre-stripprefixregex.stripPrefixRegex.regex=/calibre
- traefik.http.routers.calibre.middlewares=calibre-headers,calibre-stripprefixregex,authelia-auth@docker
- traefik.http.routers.calibre.rule=PathPrefix(`/calibre`)
- traefik.http.routers.calibre.middlewares=https-proto@docker,calibre-headers,calibre-stripprefixregex,authelia-auth@docker
- traefik.http.routers.calibre.rule=Host(`${APP_HOSTNAME}`) && PathPrefix(`/calibre`) # Added Host check
- traefik.http.routers.calibre.entrypoints=web
- traefik.http.services.calibre.loadbalancer.server.port=8083
- homepage.group=Media
@@ -520,7 +509,6 @@ services:
- HOMEPAGE_VAR_WEATHER_LONG=${HOMEPAGE_VAR_WEATHER_LONG}
- HOMEPAGE_VAR_WEATHER_TIME=${TIMEZONE}
- HOMEPAGE_VAR_WEATHER_UNIT=${HOMEPAGE_VAR_WEATHER_UNIT}
# Explicitly allow the hostname constructed from Tailscale variables
- HOMEPAGE_ALLOWED_HOSTS=${TAILSCALE_HOSTNAME}.${TAILSCALE_TAILNET_DOMAIN}
volumes:
- ${CONFIG_ROOT:-.}/homepage:/app/config:Z
@@ -531,17 +519,16 @@ services:
[sh, -c, "cp -n /app/config/tpl/*.yaml /app/config && node server.js"]
labels:
- traefik.enable=true
# Rule for homepage, now at /home, needs auth
- traefik.http.routers.homepage.rule=Host(`${HOSTNAME}`) && PathPrefix(`/home`)
- traefik.http.routers.homepage.rule=Host(`${APP_HOSTNAME}`) && PathPrefix(`/home`) # Changed rule to root
- traefik.http.routers.homepage.entrypoints=web
- traefik.http.routers.homepage.priority=10 # Lower priority than Authelia's root rule
- traefik.http.middlewares.homepage-stripprefix.stripPrefix.prefixes=/home
- traefik.http.routers.homepage.middlewares=homepage-stripprefix,authelia-auth@docker
# Homepage's own labels for discovery (unchanged)
# - traefik.http.routers.homepage.priority=10 # Removed priority
# Global middleware for setting HTTPS header
- traefik.http.middlewares.https-proto.headers.customrequestheaders.X-Forwarded-Proto=https
- traefik.http.routers.homepage.middlewares=https-proto@docker,authelia-auth@docker
- homepage.group=Dashboard
- homepage.name=Homepage
- homepage.icon=homepage.png
- homepage.href=/home # Update link to new path
- homepage.href=/ # Updated href
- homepage.description=Service Dashboard
watchtower:
image: ghcr.io/containrrr/watchtower:latest
@@ -562,23 +549,22 @@ services:
tailscale:
image: tailscale/tailscale:latest
container_name: tailscale
hostname: ${TAILSCALE_HOSTNAME:-tailscale-nas} # Hostname for Tailscale access
hostname: ${TAILSCALE_HOSTNAME:-tailscale-nas}
environment:
TS_AUTHKEY: ${TAILSCALE_AUTHKEY} # Needs to be set in .env
TS_EXTRA_ARGS: "--advertise-tags=${TAILSCALE_TAGS:-tag:nas}" # Keep tags if desired
TS_AUTHKEY: ${TAILSCALE_AUTHKEY}
TS_EXTRA_ARGS: "--advertise-tags=${TAILSCALE_TAGS:-tag:nas}"
TS_STATE_DIR: "/var/lib/tailscale"
TS_USERSPACE: "false"
# Switch to enable Funnel (public access) or Serve (Tailnet only)
ENABLE_FUNNEL_HTTPS: ${ENABLE_FUNNEL_HTTPS:-false}
volumes:
- ${CONFIG_ROOT:-.}/tailscale/state:/var/lib/tailscale:Z # Persist state
- /var/run/docker.sock:/var/run/docker.sock # Optional, keep if needed
- ${CONFIG_ROOT:-.}/tailscale/state:/var/lib/tailscale:Z
- /var/run/docker.sock:/var/run/docker.sock
devices:
- /dev/net/tun:/dev/net/tun
cap_add:
- NET_ADMIN
- NET_RAW
extra_hosts: # Add this section
extra_hosts:
- host.docker.internal:172.17.0.1
restart: always
command:
@@ -602,8 +588,6 @@ services:
done
echo " Tailscaled is running."
# --- Start Tailscale Funnel/Serve ---
# Check the ENABLE_FUNNEL_HTTPS variable
if [ "${ENABLE_FUNNEL_HTTPS}" = "true" ]; then
echo "ENABLE_FUNNEL_HTTPS is true. Setting up Funnel -> http://localhost:80..."
tailscale funnel --bg http://localhost:80
@@ -613,10 +597,9 @@ services:
tailscale serve --bg http://localhost:80
echo "Tailscale Serve configured."
fi
# --- End Tailscale Funnel/Serve ---
echo "Tailscale forwarding configured. Container will remain running."
wait # Wait indefinitely for background processes
wait
networks:
default:

View File

@@ -1,49 +0,0 @@
#!/bin/bash
# See https://stackoverflow.com/a/44864004 for the sed GNU/BSD compatible hack
function update_arr_config {
echo "Updating ${container} configuration..."
until [ -f "${CONFIG_ROOT:-.}"/"$container"/config.xml ]; do sleep 1; done
sed -i.bak "s/<UrlBase><\/UrlBase>/<UrlBase>\/$1<\/UrlBase>/" "${CONFIG_ROOT:-.}"/"$container"/config.xml && rm "${CONFIG_ROOT:-.}"/"$container"/config.xml.bak
CONTAINER_NAME_UPPER=$(echo "$container" | tr '[:lower:]' '[:upper:]')
sed -i.bak 's/^'"${CONTAINER_NAME_UPPER}"'_API_KEY=.*/'"${CONTAINER_NAME_UPPER}"'_API_KEY='"$(sed -n 's/.*<ApiKey>\(.*\)<\/ApiKey>.*/\1/p' "${CONFIG_ROOT:-.}"/"$container"/config.xml)"'/' .env && rm .env.bak
echo "Update of ${container} configuration complete, restarting..."
docker compose restart "$container"
}
function update_qbittorrent_config {
echo "Updating ${container} configuration..."
docker compose stop "$container"
until [ -f "${CONFIG_ROOT:-.}"/"$container"/qBittorrent/qBittorrent.conf ]; do sleep 1; done
sed -i.bak '/WebUI\\ServerDomains=*/a WebUI\\Password_PBKDF2="@ByteArray(ARQ77eY1NUZaQsuDHbIMCA==:0WMRkYTUWVT9wVvdDtHAjU9b3b7uB8NR1Gur2hmQCvCDpm39Q+PsJRJPaCU51dEiz+dTzh8qbPsL8WkFljQYFQ==)"' "${CONFIG_ROOT:-.}"/"$container"/qBittorrent/qBittorrent.conf && rm "${CONFIG_ROOT:-.}"/"$container"/qBittorrent/qBittorrent.conf.bak
echo "Update of ${container} configuration complete, restarting..."
docker compose start "$container"
}
function update_bazarr_config {
echo "Updating ${container} configuration..."
until [ -f "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml ]; do sleep 1; done
sed -i.bak "s/base_url: ''/base_url: '\/$container'/" "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml && rm "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml.bak
sed -i.bak "s/use_radarr: false/use_radarr: true/" "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml && rm "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml.bak
sed -i.bak "s/use_sonarr: false/use_sonarr: true/" "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml && rm "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml.bak
until [ -f "${CONFIG_ROOT:-.}"/sonarr/config.xml ]; do sleep 1; done
SONARR_API_KEY=$(sed -n 's/.*<ApiKey>\(.*\)<\/ApiKey>.*/\1/p' "${CONFIG_ROOT:-.}"/sonarr/config.xml)
sed -i.bak "/sonarr:/,/^radarr:/ { s/apikey: .*/apikey: $SONARR_API_KEY/; s/base_url: .*/base_url: \/sonarr/; s/ip: .*/ip: sonarr/ }" "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml && rm "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml.bak
until [ -f "${CONFIG_ROOT:-.}"/radarr/config.xml ]; do sleep 1; done
RADARR_API_KEY=$(sed -n 's/.*<ApiKey>\(.*\)<\/ApiKey>.*/\1/p' "${CONFIG_ROOT:-.}"/radarr/config.xml)
sed -i.bak "/radarr:/,/^sonarr:/ { s/apikey: .*/apikey: $RADARR_API_KEY/; s/base_url: .*/base_url: \/radarr/; s/ip: .*/ip: radarr/ }" "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml && rm "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml.bak
sed -i.bak 's/^BAZARR_API_KEY=.*/BAZARR_API_KEY='"$(sed -n 's/.*apikey: \(.*\)*/\1/p' "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml | head -n 1)"'/' .env && rm .env.bak
echo "Update of ${container} configuration complete, restarting..."
docker compose restart "$container"
}
for container in $(docker ps --format '{{.Names}}'); do
if [[ "$container" =~ ^(radarr|sonarr|lidarr|prowlarr)$ ]]; then
update_arr_config "$container"
elif [[ "$container" =~ ^(bazarr)$ ]]; then
update_bazarr_config "$container"
elif [[ "$container" =~ ^(qbittorrent)$ ]]; then
update_qbittorrent_config "$container"
fi
done

1370
update-setup.sh Executable file

File diff suppressed because it is too large Load Diff