2025-04-26 00:18:59 +08:00
2025-03-09 18:08:14 -04:00

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.

Table of Contents

Architecture Overview

This stack uses a combination of key services for routing, access, and security:

  • Tailscale: 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: 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: 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.

Features

This stack includes the following services, categorized for clarity:

Core Infrastructure:

  • Reverse Proxy: Traefik - Manages internal routing and service discovery.
  • Secure Remote Access: Tailscale - Provides VPN access and HTTPS.
  • Authentication: Authelia & Redis - Single sign-on portal and session management.
  • Dashboard: Homepage - Centralized access point (at /home).

Media Management (*Arr Suite):

  • Sonarr: TV show management.
  • Radarr: Movie management.
  • Lidarr (Optional): Music management.
  • Bazarr: Subtitle management.
  • Prowlarr: Indexer management for *arr apps.

Download Clients:

Media Serving & Requests:

Utilities:

Optional Services (Enabled via Profiles):

Prerequisites

  • Linux Host: A system capable of running Docker (e.g., Ubuntu, Debian, Fedora).
  • Docker & Docker Compose: Latest versions installed. See Docker Engine Install and Docker 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.
  • (Optional) SELinux: If enabled, see Troubleshooting.

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
    • Generate an Auth Key in the Tailscale Admin Console
    • 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:
      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 Admin Password

    • Generate a password hash for Authelia:
      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

After completing all Required Setup Steps above, follow these steps to get up and running:

  1. Clone Repository:

    git clone https://github.com/AdrienPoupa/docker-compose-nas.git
    cd docker-compose-nas
    
  2. Configure Environment:

    # Create an .env file from the example
    cp .env.example .env
    
    # Edit the .env file and fill in ALL required values
    nano .env
    
  3. Configure Authelia Admin:

    # 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. Start the Stack:

    # Make helper script executable (if needed)
    chmod +x ./update-config.sh
    chmod +x ./update-env.sh
    
    # Start containers
    docker compose up -d
    
  5. Configure Service API Keys (after stack is running):

    # Optional: Run config script to set API keys
    ./update-config.sh
    
  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 section and verify you've properly completed all Required Setup Steps.

Configuration (.env Variables)

This file controls essential settings. Copy .env.example to .env and modify the values. Bold variables are critical for initial setup.

Core System & Paths

Variable Description Default
USER_ID Linux user ID for container permissions. Find with id -u. 1000
GROUP_ID Linux group ID for container permissions. Find with id -g. 1000
TIMEZONE Your local timezone (e.g., America/New_York, Asia/Manila). List. America/New_York
CONFIG_ROOT Host base directory for service configurations. . = project subdirs. .
DATA_ROOT Host directory for media libraries (movies, TV, music, etc.). /mnt/data
DOWNLOAD_ROOT Host directory for downloads (in progress/completed). Must be on same filesystem as DATA_ROOT for hardlinks. /mnt/data/torrents
IMMICH_UPLOAD_LOCATION Host path for Immich uploads (if immich profile enabled). /mnt/data/photos

Networking & Access (Tailscale)

Variable Description Default
TAILSCALE_AUTHKEY Required. Auth key from Tailscale Admin Console. Use reusable or ephemeral. (None)
TAILSCALE_TAILNET_DOMAIN Required. Your unique Tailnet domain (e.g., your-name.ts.net). your-tailnet.ts.net
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
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 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 (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)
AUTHELIA_SESSION_DOMAIN Deprecated. Domain for session cookies. Should match APP_HOSTNAME. (Handled within authelia/configuration.yml in v4.38+) ${APP_HOSTNAME}
AUTHELIA_DEFAULT_REDIRECT_URL Deprecated. Where users land after login. (Handled within authelia/configuration.yml in v4.38+) https://${APP_HOSTNAME}/home

Service Credentials

Variable Description Default
QBITTORRENT_USERNAME Username for qBittorrent Web UI. admin
QBITTORRENT_PASSWORD Password for qBittorrent Web UI. Change default! (May need to use temp password from logs on first run, then change in UI & .env). adminadmin
CALIBRE_USERNAME Username for Calibre-Web (if calibre-web profile enabled). admin
CALIBRE_PASSWORD Password for Calibre-Web (if calibre-web profile enabled). admin123
IMMICH_DB_PASSWORD Password for Immich's internal database (if immich profile enabled). postgres
ADGUARD_USERNAME Username for AdGuard Home (if adguardhome profile enabled). (None)
ADGUARD_PASSWORD Password for AdGuard Home (if adguardhome profile enabled). (None)

Homepage Customization & Widgets

Variable Description Default
HOMEPAGE_VAR_TITLE Title shown on the dashboard. Docker-Compose NAS
HOMEPAGE_VAR_SEARCH_PROVIDER Default search engine. Options. google
HOMEPAGE_VAR_HEADER_STYLE Dashboard header style. Options. boxed
HOMEPAGE_VAR_WEATHER_CITY City for weather widget. (None)
HOMEPAGE_VAR_WEATHER_LAT Latitude for weather widget. (None)
HOMEPAGE_VAR_WEATHER_LONG Longitude for weather widget. (None)
HOMEPAGE_VAR_WEATHER_UNIT Weather units (metric or imperial). metric
SONARR_API_KEY API Keys for various services, primarily used for Homepage widgets. Find keys in each app's settings. (None)
RADARR_API_KEY " (None)
LIDARR_API_KEY " (if lidarr profile enabled) (None)
BAZARR_API_KEY " (None)
PROWLARR_API_KEY " (None)
JELLYFIN_API_KEY " (None)
JELLYSEERR_API_KEY " (None)
SABNZBD_API_KEY " (if sabnzbd profile enabled) (None)
IMMICH_API_KEY " (if immich profile enabled) (None)
HOMEASSISTANT_ACCESS_TOKEN " (if homeassistant profile enabled) (None)

Optional Features & Services

Variable Description Default
COMPOSE_PROFILES Comma-separated list of optional service profiles to enable (e.g., lidarr,sabnzbd). See Optional Services. (None)
COMPOSE_PATH_SEPARATOR Path separator for COMPOSE_FILE (use ; for Windows). :
COMPOSE_FILE Colon-separated list of compose files to use. Allows extending base config. docker-compose.yml:... (See .env.example)
DECLUTTARR_TEST_RUN Run Decluttarr in test mode (True/False)? (if decluttarr profile enabled). True
DECLUTTARR_... Other Decluttarr settings (see .env.example). (Varies)
PIA_USER / PIA_PASS Credentials for PIA VPN (if using default VPN setup for qBittorrent). (None)
PIA_LOCATION PIA server location (if using default VPN). List. ca
PIA_LOCAL_NETWORK Your local network CIDR (e.g., 192.168.1.0/24) to allow local access to VPN'd containers. 192.168.0.0/16
DNS_CHALLENGE Enable Traefik DNS challenge for Let's Encrypt (true/false). Not needed if using Tailscale for HTTPS. true
DNS_CHALLENGE_PROVIDER Your DNS provider (e.g., cloudflare). Providers. cloudflare
LETS_ENCRYPT_EMAIL Email for Let's Encrypt (if using DNS challenge). (None)
LETS_ENCRYPT_CA_SERVER Let's Encrypt server URL (if using DNS challenge). https://acme-v02.api.letsencrypt.org/directory
CLOUDFLARE_... / PROVIDER_... DNS provider API credentials (if using DNS challenge). (None)
HOMEASSISTANT_HOSTNAME Specific hostname for Home Assistant (if homeassistant profile enabled). (None)
IMMICH_HOSTNAME Specific hostname for Immich (if immich profile enabled). (None)
ADGUARD_HOSTNAME Specific hostname for AdGuard Home (if adguardhome profile enabled). (None)

Detailed Setup & Usage

Authelia User Management

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'):
      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:
      users:
        admin:
          # ... (admin details) ...
        newuser:
          displayname: "New User Name"
          password: "paste_generated_hash_here"
          email: newuser@example.com
          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:
      # registration:
      #   enable: false # Set to true to enable registration form
      
      becomes:
      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.
  • 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

(Details about configuring the PIA VPN or other VPN setups could go here if needed.)

(Optional) Traefik DNS Challenge

(Details about setting up DNS provider credentials for Let's Encrypt could go here if needed.)

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.

  • 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.

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 APP_HOSTNAME variable to point to the Tailscale IP, you can use https://<APP_HOSTNAME>/<service_path>.

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 (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:

    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:

    # 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.

Authelia v4.38+ Configuration

Authelia v4.38+ introduces significant changes to its configuration structure, particularly for session domains and authentication flows. This Docker Compose template has been updated to support these changes, making it easier to set up:

  1. Simplified Configuration: The setup now uses a more reliable approach with wildcard domain matching (*.ts.net) that works properly with Tailscale domains. This eliminates environment variable interpolation issues that were causing errors in previous versions.

  2. No Manual YAML Editing Required: You don't need to edit the Authelia configuration file manually. The important settings are configured through environment variables in the Docker Compose setup.

  3. Required Secret Variables: You only need to 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

  4. File Permissions Fixed: The Authelia container now runs with your user ID and group ID, preventing permission issues when managing the configuration files with git or other tools.

  5. Common Error Solutions: If you encounter configuration errors like these:

    error decoding 'session.cookies[0].authelia_url': could not decode 'https://${APP_HOSTNAME}'
    can't be specified at the same time: option 'domain' and option 'cookies'
    

    The solution is already implemented in the updated configuration. No manual fixes needed.

If you need to make changes to the domain settings for some reason, edit authelia/configuration.yml and modify the *.ts.net wildcard pattern to match your specific domain. For most setups using Tailscale, the default configuration will work without any changes.

After making changes to the configuration, restart Authelia with:

docker compose restart authelia

See the Authelia documentation 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.

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.

Description
Simple Tailscale Sidecar + Docker Compose NAS featuring Sonarr, Radarr, Prowlarr, Jellyfin, qBittorrent, and Traefik. Now with Authelia
Readme 880 KiB
Languages
Shell 87.6%
JavaScript 12.4%