Some checks failed
/ validate-docker-compose (push) Has been cancelled
- Integrate Traefik directly with Tailscale network using `network_mode: service:tailscale`.
- Remove direct port mappings for Traefik (80, 443).
- Configure Tailscale container to use `tailscale serve` (Tailnet only) or `tailscale funnel` (public HTTPS) based on `ENABLE_FUNNEL_HTTPS` env var.
- Update Traefik routing rules (`Host()`) to use `${TAILSCALE_HOSTNAME}.${TAILSCALE_TAILNET_DOMAIN}` for all services.
- Update Homepage path to `/home` and adjust its Traefik rule.
- Remove Homepage basic authentication variables (`HOMEPAGE_AUTH_USER`, `HOMEPAGE_AUTH_HASH`) from `.env.example` and `README.md`.
- Update `README.md` to reflect new access methods, hostname configuration, and removal of basic auth.
- Add `extra_hosts` to Tailscale service for `host.docker.internal`.
297 lines
17 KiB
Markdown
297 lines
17 KiB
Markdown
# Docker Compose NAS
|
|
|
|
This project provides a comprehensive, self-hosted media and utility server setup using Docker Compose. It aims to replicate and enhance the functionality of a typical NAS using containerized applications on a standard Linux host.
|
|
|
|
The core idea is to manage media libraries (movies, TV shows, music), automate downloads securely, provide easy access via a dashboard, and enable remote access through Tailscale.
|
|
|
|
## Features
|
|
|
|
This stack includes:
|
|
|
|
* **Reverse Proxy & Service Discovery:** [Traefik](https://traefik.io) automatically routes traffic to services.
|
|
* **Media Management:**
|
|
* [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.
|
|
* **Indexers & Downloads:**
|
|
* [Prowlarr](https://github.com/Prowlarr/Prowlarr): Indexer management for *arr apps.
|
|
* [qBittorrent](https://www.qbittorrent.org): Bittorrent client (can be configured to run through a VPN).
|
|
* [SABnzbd](https://sabnzbd.org/) (Optional): Usenet download client.
|
|
* **Media Server:** [Jellyfin](https://jellyfin.org) organizes and streams your media.
|
|
* **Request Management:** [Jellyseerr](https://github.com/FallenBagel/jellyseerr) allows users (including Jellyfin users) to request media.
|
|
* **Dashboard:** [Homepage](https://gethomepage.dev) provides a central dashboard to access all services.
|
|
* **Remote Access:** [Tailscale](https://tailscale.com) provides secure access to your services from anywhere without opening firewall ports. It handles HTTPS termination.
|
|
* **Utilities:**
|
|
* [Watchtower](https://containrrr.dev/watchtower/): Automatically updates running containers to the latest image.
|
|
* [Autoheal](https://github.com/willfarrell/docker-autoheal/): Monitors and restarts unhealthy containers.
|
|
* [Unpackerr](https://unpackerr.zip): Automatically extracts downloaded archives.
|
|
* **Other Optional Services:** AdGuard Home, Calibre-Web, Decluttarr, Tandoor Recipes, Joplin Server, Home Assistant, Immich Photos (enable via profiles).
|
|
|
|
## Prerequisites
|
|
|
|
* **Linux Host:** Any recent Linux distribution capable of running Docker. Tested on Ubuntu Server 22.04.
|
|
* **Docker Engine:** Install the latest version of Docker Engine. [Official Installation Guide](https://docs.docker.com/engine/install/).
|
|
* **Docker Compose V2:** Ensure you have Docker Compose V2 (usually installed as a Docker plugin, invoked via `docker compose`). [Official Installation Guide](https://docs.docker.com/compose/install/).
|
|
* **User Permissions:** You'll need a user account that can run `docker` commands (usually by adding the user to the `docker` group) or run `docker compose` via `sudo`.
|
|
* **SELinux (If Enabled):** If your host uses SELinux (e.g., Fedora, CentOS, RHEL), you might need additional host configuration. See the [Troubleshooting](#selinux-socket-permissions) section.
|
|
|
|
## Quick Start
|
|
|
|
1. **Clone the Repository:**
|
|
```bash
|
|
git clone https://github.com/AdrienPoupa/docker-compose-nas.git
|
|
cd docker-compose-nas
|
|
```
|
|
|
|
2. **Create Configuration File:**
|
|
Copy the example environment file:
|
|
```bash
|
|
cp .env.example .env
|
|
```
|
|
|
|
3. **Edit `.env` File:**
|
|
Open the `.env` file with a text editor and configure it according to your system and preferences. **This is the most crucial step.** See the detailed [Configuration (`.env` File)](#configuration-env-file) section below for explanations of each variable. Minimally, you **must** set `USER_ID`, `GROUP_ID`, `TIMEZONE`, `HOSTNAME`, and `TAILSCALE_AUTHKEY`.
|
|
|
|
4. **Start the Stack:**
|
|
Run Docker Compose (use `sudo` if your user isn't in the `docker` group):
|
|
```bash
|
|
docker compose up -d
|
|
```
|
|
This will pull the necessary images and start all the core services in the background.
|
|
|
|
5. **Run Initial Configuration Script:**
|
|
This script helps configure base URLs and API keys within the running *arr applications based on your `.env` file.
|
|
```bash
|
|
./update-config.sh
|
|
```
|
|
*(Note: You might need to make it executable first: `chmod +x ./update-config.sh`)*
|
|
|
|
6. **Access Services:** Once Tailscale is connected, you should be able to access your services via `https://<TAILSCALE_HOSTNAME>.<your-tailnet-name>.ts.net/<service_path>` or `https://<TAILSCALE_IP>/<service_path>`. If you set up DNS for your `HOSTNAME`, you can use `https://<HOSTNAME>/<service_path>`. The main dashboard is at `/`.
|
|
|
|
## Configuration (`.env` File)
|
|
|
|
This file controls all the essential settings for your Docker Compose stack. Copy `.env.example` to `.env` and edit the values.
|
|
|
|
---
|
|
|
|
### **Core Settings (Required)**
|
|
|
|
These are fundamental for basic operation and permissions.
|
|
|
|
* `USER_ID`: The Linux user ID that the containers will run as. Find yours with `id -u`.
|
|
* *Default:* `1000`
|
|
* `GROUP_ID`: The Linux group ID that the containers will run as. Find yours with `id -g`.
|
|
* *Default:* `1000`
|
|
* **Note:** Using the correct IDs is crucial for file permissions, especially for accessing media files on the host.
|
|
* `TIMEZONE`: Your local timezone (e.g., `America/New_York`, `Europe/London`, `Asia/Manila`). Find yours from [this list](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones).
|
|
* *Default:* `America/New_York`
|
|
* `HOSTNAME`: **(Deprecated - Now derived)** The primary hostname used by Traefik for routing. This is now automatically constructed from `TAILSCALE_HOSTNAME` and `TAILSCALE_TAILNET_DOMAIN`. You generally don't need to set this directly unless overriding the default behavior.
|
|
* *Default:* `${TAILSCALE_HOSTNAME}.${TAILSCALE_TAILNET_DOMAIN}`
|
|
|
|
---
|
|
|
|
### **Host Paths (Required)**
|
|
|
|
Define where container data and configuration are stored on your host machine.
|
|
|
|
* `CONFIG_ROOT`: The base directory on your host where configuration files for each service will be stored. Using `.` stores them in subdirectories within the project folder.
|
|
* *Default:* `.`
|
|
* `DATA_ROOT`: The main directory on your host containing your media libraries (movies, TV shows, music, books).
|
|
* *Default:* `/mnt/data`
|
|
* `DOWNLOAD_ROOT`: The directory on your host where the download client (qBittorrent/SABnzbd) will store downloads in progress and completed files *before* they are imported by *arr apps.
|
|
* *Default:* `/mnt/data/torrents`
|
|
* **Hardlink Note:** For efficient storage (avoiding duplicate files), it's highly recommended that `DOWNLOAD_ROOT` is on the **same filesystem** as `DATA_ROOT` (e.g., `/mnt/data/torrents` is inside `/mnt/data`). This allows instant moves via hardlinks instead of slow copies.
|
|
|
|
---
|
|
|
|
### **Tailscale Access (Required)**
|
|
|
|
Controls secure remote access via Tailscale.
|
|
|
|
* `TAILSCALE_AUTHKEY`: **Required.** An authentication key from your Tailscale account. Generate one in the Tailscale Admin Console under Settings > Keys. You can use a reusable key or an ephemeral key (recommended for containers).
|
|
* *Default:* (None - **Must be set**)
|
|
* `TAILSCALE_HOSTNAME`: The desired hostname for this NAS within your Tailscale network.
|
|
* *Default:* `tailscale-nas`
|
|
* `TAILSCALE_TAILNET_DOMAIN`: **Required.** The domain of your Tailnet, including your Tailnet's unique name
|
|
* *Default:* `your-tailnet.ts.net` (**Must be set**)
|
|
* `TAILSCALE_TAGS`: Optional tags to apply to the Tailscale node (e.g., `tag:nas`).
|
|
* *Default:* `tag:nas`
|
|
* `ENABLE_FUNNEL_HTTPS`: Controls Tailscale's public accessibility.
|
|
* `true`: Enables Tailscale Funnel, making services accessible publicly via the Tailscale domain (`<TAILSCALE_HOSTNAME>.<your-tailnet-name>.ts.net`). Use with caution.
|
|
* `false`: Uses Tailscale Serve, making services accessible *only* to devices logged into your Tailnet. (Recommended)
|
|
* *Default:* `false`
|
|
|
|
---
|
|
|
|
### **Homepage Widgets (Optional)**
|
|
|
|
API keys needed *only* if you want to display real-time information from these services on the Homepage dashboard. Find the API keys within each application's settings (usually under Settings > General or Settings > Security).
|
|
|
|
* `SONARR_API_KEY`
|
|
* `RADARR_API_KEY`
|
|
* `LIDARR_API_KEY` (If Lidarr profile is enabled)
|
|
* `BAZARR_API_KEY`
|
|
* `PROWLARR_API_KEY`
|
|
* `JELLYFIN_API_KEY`
|
|
* `JELLYSEERR_API_KEY`
|
|
* `SABNZBD_API_KEY` (If SABnzbd profile is enabled)
|
|
* `ADGUARD_USERNAME` / `ADGUARD_PASSWORD` (If AdGuard Home profile is enabled)
|
|
* `CALIBRE_USERNAME` / `CALIBRE_PASSWORD` (If Calibre-Web profile is enabled)
|
|
|
|
---
|
|
|
|
### **Homepage Customization (Optional)**
|
|
|
|
Control the appearance and behavior of the Homepage dashboard.
|
|
|
|
* `HOMEPAGE_VAR_TITLE`: Title shown on the dashboard.
|
|
* *Default:* `Docker-Compose NAS`
|
|
* `HOMEPAGE_VAR_SEARCH_PROVIDER`: Default search engine. [See options](https://gethomepage.dev/en/widgets/search/).
|
|
* *Default:* `google`
|
|
* `HOMEPAGE_VAR_HEADER_STYLE`: Dashboard header style. [See options](https://gethomepage.dev/en/configs/settings/#header-style).
|
|
* *Default:* `boxed`
|
|
* `HOMEPAGE_VAR_WEATHER_CITY`, `_LAT`, `_LONG`, `_UNIT`: Configure the weather widget.
|
|
|
|
---
|
|
|
|
### **Download Client Settings**
|
|
|
|
Credentials for included download clients.
|
|
|
|
* `QBITTORRENT_USERNAME`: Username for qBittorrent Web UI.
|
|
* *Default:* `admin`
|
|
* `QBITTORRENT_PASSWORD`: Password for qBittorrent Web UI.
|
|
* *Default:* `adminadmin`
|
|
* **Note:** On first run, qBittorrent might generate a temporary password shown in its logs (`docker compose logs qbittorrent`). Log in with that, change the password in qBittorrent settings, and update this `.env` variable accordingly.
|
|
|
|
---
|
|
|
|
### **VPN Configuration (Example: PIA - Optional)**
|
|
|
|
These variables are specific to the example `thrnz/docker-wireguard-pia` VPN container used for qBittorrent in the default setup. If you use a different VPN provider or container, you'll need different variables. **If you don't use the VPN, you can ignore these.**
|
|
|
|
* `PIA_USER`: Private Internet Access username.
|
|
* `PIA_PASS`: Private Internet Access password.
|
|
* `PIA_LOCATION`: PIA server location code (e.g., `ca_montreal`, `us_east`). [See list](https://serverlist.piaservers.net/vpninfo/servers/v6).
|
|
* *Default:* `ca`
|
|
* `PIA_LOCAL_NETWORK`: Your local network CIDR (e.g., `192.168.1.0/24`). Allows local access to the qBittorrent UI when the VPN is active.
|
|
* *Default:* `192.168.0.0/16`
|
|
|
|
---
|
|
|
|
### **Traefik DNS Challenge (Optional)**
|
|
|
|
These settings are for enabling automatic HTTPS certificate generation via Let's Encrypt using the DNS-01 challenge method. **This is generally NOT needed** because Tailscale handles HTTPS termination by default in this setup. Only configure this if you have a specific reason to manage your own certificates via Traefik (e.g., accessing services without Tailscale).
|
|
|
|
* `DNS_CHALLENGE`: Set to `true` to enable DNS challenge.
|
|
* *Default:* `true` (Consider setting to `false` if using Tailscale for HTTPS)
|
|
* `DNS_CHALLENGE_PROVIDER`: Your DNS provider supported by Traefik/Lego (e.g., `cloudflare`, `godaddy`). [See providers](https://doc.traefik.io/traefik/https/acme/#providers).
|
|
* *Default:* `cloudflare`
|
|
* `LETS_ENCRYPT_EMAIL`: Your email address for Let's Encrypt notifications.
|
|
* `LETS_ENCRYPT_CA_SERVER`: Let's Encrypt server URL (use staging for testing).
|
|
* *Default:* `https://acme-v02.api.letsencrypt.org/directory` (Production)
|
|
* Provider-Specific Variables (e.g., `CLOUDFLARE_EMAIL`, `CLOUDFLARE_DNS_API_TOKEN`, `CLOUDFLARE_ZONE_API_TOKEN`): Credentials required by your chosen `DNS_CHALLENGE_PROVIDER`. Refer to Traefik documentation.
|
|
|
|
---
|
|
|
|
### **Compose Profiles & Files (Advanced)**
|
|
|
|
* `COMPOSE_PROFILES`: Comma-separated list of optional service profiles to enable (e.g., `lidarr,sabnzbd,adguardhome`). See [Optional Services](#optional-services).
|
|
* `COMPOSE_FILE`: Colon-separated list of compose files to use. Allows extending the base configuration.
|
|
* *Default:* `docker-compose.yml`
|
|
|
|
## Service Access
|
|
|
|
With the default Tailscale setup, services are securely accessible via HTTPS using your Tailscale node's name or IP, followed by the service path. Replace `<TAILSCALE_NODE>` with your Tailscale device name (e.g., `tailscale-nas.your-tailnet.ts.net`) or its Tailscale IP address.
|
|
|
|
* **Homepage:** `https://<TAILSCALE_NODE>/home`
|
|
* **Sonarr:** `https://<TAILSCALE_NODE>/sonarr`
|
|
* **Radarr:** `https://<TAILSCALE_NODE>/radarr`
|
|
* **Lidarr:** `https://<TAILSCALE_NODE>/lidarr` (If profile enabled)
|
|
* **Bazarr:** `https://<TAILSCALE_NODE>/bazarr`
|
|
* **Jellyseerr:** `https://<TAILSCALE_NODE>/jellyseerr`
|
|
* **Prowlarr:** `https://<TAILSCALE_NODE>/prowlarr`
|
|
* **qBittorrent:** `https://<TAILSCALE_NODE>/qbittorrent`
|
|
* **SABnzbd:** `https://<TAILSCALE_NODE>/sabnzbd` (If profile enabled)
|
|
* **Jellyfin:** `https://<TAILSCALE_NODE>/jellyfin`
|
|
* **Calibre-Web:** `https://<TAILSCALE_NODE>/calibre` (If profile enabled)
|
|
* **AdGuard Home:** `http://<TAILSCALE_NODE_IP>:3000` (If profile enabled, access via IP/port initially)
|
|
* **Tandoor Recipes:** `https://<TAILSCALE_NODE>/recipes` (If profile enabled)
|
|
* **Joplin Server:** `https://<TAILSCALE_NODE>/joplin` (If profile enabled)
|
|
* **Home Assistant:** `http://<TAILSCALE_NODE_IP>:8123` (If profile enabled, access via IP/port initially)
|
|
* **Immich:** `http://<TAILSCALE_NODE_IP>:2283` (If profile enabled, access via IP/port initially)
|
|
|
|
**Note:**
|
|
* `<TAILSCALE_NODE>` refers to the full Tailscale name (e.g., `tailscale-nas.your-tailnet.ts.net`).
|
|
* `<TAILSCALE_NODE_IP>` refers to the Tailscale IP address of the NAS.
|
|
* Some services (AdGuard, HA, Immich) might require initial setup via their direct IP and port before Tailscale/Traefik routing is fully effective or configured within the application. Authentication for most services will be handled by Authelia (configured later).
|
|
|
|
## 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`).
|
|
|
|
## Troubleshooting
|
|
|
|
### 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:
|
|
```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:
|
|
```bash
|
|
# Generate policy files (my-dockersock.te and my-dockersock.pp)
|
|
sudo ausearch -m avc -ts recent | audit2allow -M my-dockersock
|
|
|
|
# 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.
|
|
|
|
### 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.
|
|
|
|
### 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.
|
|
|
|
## Advanced Topics
|
|
|
|
*(Relevant sections like Synology Quirks, NFS Share, Static IP, etc., can be kept here, but review them to ensure they align with a standard Docker setup rather than Podman specifics where applicable.)*
|
|
|
|
*(Example: Synology section should focus on Docker package setup, port conflicts, user IDs, etc., relevant to DSM.)*
|
|
|
|
*(Example: Remove Podman-specific commands or troubleshooting steps from these sections.)*
|
|
|
|
---
|
|
|
|
*Self-hosted media stack powered by Docker, Traefik, Tailscale, and the \*arr suite.*
|