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 automatically routes traffic to services.
- Media Management:
- Indexers & Downloads:
- Prowlarr: Indexer management for *arr apps.
- qBittorrent: Bittorrent client (can be configured to run through a VPN).
- SABnzbd (Optional): Usenet download client.
- Media Server: Jellyfin organizes and streams your media.
- Request Management: Jellyseerr allows users (including Jellyfin users) to request media.
- Dashboard: Homepage provides a central dashboard to access all services.
- Remote Access: Tailscale provides secure access to your services from anywhere without opening firewall ports. It handles HTTPS termination.
- Utilities:
- Watchtower: Automatically updates running containers to the latest image.
- Autoheal: Monitors and restarts unhealthy containers.
- Unpackerr: 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.
- Docker Compose V2: Ensure you have Docker Compose V2 (usually installed as a Docker plugin, invoked via
docker compose). Official Installation Guide. - User Permissions: You'll need a user account that can run
dockercommands (usually by adding the user to thedockergroup) or rundocker composeviasudo. - SELinux (If Enabled): If your host uses SELinux (e.g., Fedora, CentOS, RHEL), you might need additional host configuration. See the Troubleshooting section.
Quick Start
-
Clone the Repository:
git clone https://github.com/AdrienPoupa/docker-compose-nas.git cd docker-compose-nas -
Create Configuration File: Copy the example environment file:
cp .env.example .env -
Edit
.envFile: Open the.envfile with a text editor and configure it according to your system and preferences. This is the most crucial step. See the detailed Configuration (.envFile) section below for explanations of each variable. Minimally, you must setUSER_ID,GROUP_ID,TIMEZONE,HOSTNAME, andTAILSCALE_AUTHKEY. -
Start the Stack: Run Docker Compose (use
sudoif your user isn't in thedockergroup):docker compose up -dThis will pull the necessary images and start all the core services in the background.
-
Run Initial Configuration Script: This script helps configure base URLs and API keys within the running *arr applications based on your
.envfile../update-config.sh(Note: You might need to make it executable first:
chmod +x ./update-config.sh) -
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>orhttps://<TAILSCALE_IP>/<service_path>. If you set up DNS for yourHOSTNAME, you can usehttps://<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 withid -u.- Default:
1000
- Default:
GROUP_ID: The Linux group ID that the containers will run as. Find yours withid -g.- Default:
1000 - Note: Using the correct IDs is crucial for file permissions, especially for accessing media files on the host.
- Default:
TIMEZONE: Your local timezone (e.g.,America/New_York,Europe/London,Asia/Manila). Find yours from this list.- Default:
America/New_York
- Default:
HOSTNAME: (Deprecated - Now derived) The primary hostname used by Traefik for routing. This is now automatically constructed fromTAILSCALE_HOSTNAMEandTAILSCALE_TAILNET_DOMAIN. You generally don't need to set this directly unless overriding the default behavior.- Default:
${TAILSCALE_HOSTNAME}.${TAILSCALE_TAILNET_DOMAIN}
- Default:
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:
.
- Default:
DATA_ROOT: The main directory on your host containing your media libraries (movies, TV shows, music, books).- Default:
/mnt/data
- Default:
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_ROOTis on the same filesystem asDATA_ROOT(e.g.,/mnt/data/torrentsis inside/mnt/data). This allows instant moves via hardlinks instead of slow copies.
- Default:
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
- Default:
TAILSCALE_TAILNET_DOMAIN: Required. The domain of your Tailnet, including your Tailnet's unique name- Default:
your-tailnet.ts.net(Must be set)
- Default:
TAILSCALE_TAGS: Optional tags to apply to the Tailscale node (e.g.,tag:nas).- Default:
tag:nas
- Default:
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_KEYRADARR_API_KEYLIDARR_API_KEY(If Lidarr profile is enabled)BAZARR_API_KEYPROWLARR_API_KEYJELLYFIN_API_KEYJELLYSEERR_API_KEYSABNZBD_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
- Default:
HOMEPAGE_VAR_SEARCH_PROVIDER: Default search engine. See options.- Default:
google
- Default:
HOMEPAGE_VAR_HEADER_STYLE: Dashboard header style. See options.- Default:
boxed
- Default:
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
- Default:
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.envvariable accordingly.
- Default:
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.- Default:
ca
- Default:
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
- Default:
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 totrueto enable DNS challenge.- Default:
true(Consider setting tofalseif using Tailscale for HTTPS)
- Default:
DNS_CHALLENGE_PROVIDER: Your DNS provider supported by Traefik/Lego (e.g.,cloudflare,godaddy). See providers.- Default:
cloudflare
- Default:
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)
- Default:
- Provider-Specific Variables (e.g.,
CLOUDFLARE_EMAIL,CLOUDFLARE_DNS_API_TOKEN,CLOUDFLARE_ZONE_API_TOKEN): Credentials required by your chosenDNS_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.COMPOSE_FILE: Colon-separated list of compose files to use. Allows extending the base configuration.- Default:
docker-compose.yml
- Default:
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
COMPOSE_PROFILES=lidarr,sabnzbd
Available Profiles:
lidarr: Music management.sabnzbd: Usenet download client.flaresolverr: Bypasses Cloudflare challenges for Prowlarr.adguardhome: Network-wide ad blocking (seeadguardhome/README.md).calibre-web: E-book library management.decluttarr: Automated download cleanup.tandoor: Recipe management (seetandoor/README.md).joplin: Note-taking server (seejoplin/README.md).homeassistant: Home automation (seehomeassistant/README.md).immich: Photo management (seeimmich/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:
-
Check Audit Logs: Immediately after seeing the error, check the SELinux audit log on the host:
sudo ausearch -m avc -ts recentLook for lines containing
denied,docker.sock, and the name of the failing service (e.g.,traefik,watchtower). -
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:# 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.ppThis 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_AUTHKEYin.envis valid and hasn't expired (especially if using ephemeral keys). Check thetailscalecontainer logs (docker compose logs tailscale) for authentication errors. - Connectivity: Verify the
tailscalecontainer 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 funnelortailscale serveis correct.
File Permissions
If services report permission errors when accessing /config or /data directories, double-check that:
- The
USER_IDandGROUP_IDin your.envfile match the owner/group of the correspondingCONFIG_ROOTandDATA_ROOTdirectories on your host. - The host directories have appropriate read/write permissions for that user/group.
- If using SELinux, the
:Zflag on the volume mounts indocker-compose.ymlis 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.