Complete installation, setup, and configuration guide for NAS02 as the central media and storage server using QNAP NAS hardware.
## Power down NAS completely
## Install 4x WD Red drives in all bays
## Ensure drives are properly seated
## Power on and wait for boot
## Power down NAS
## Remove bottom panel
## Install 8GB DDR4 SO-DIMM module
## Power on and verify in QTS System Settings
Network Setup:
User Accounts:
Storage Configuration:
Access via https://192.168.1.102
Configure static IP: 192.168.1.102
Set DNS servers: 1.1.1.1, 8.8.8.8
Configure hostname: nas02
Create admin account with secure password
Create service account for automation
Configure user groups and permissions
Create RAID 5 array with 4 drives
Configure storage pool (12TB usable)
Create thick volumes for different purposes
## Via QTS Storage & Snapshots
## Create volumes:
## - Media: 8TB (movies, TV, music)
## - Surveillance: 2TB (camera recordings)
## - Backups: 1TB (server backups)
## - Projects: 1TB (development assets)
## Install via App Center:
## - Container Station (Docker support)
## - File Station (file management)
## - Network & Virtual Switch (networking)
## - Backup Station (backup management)
## - Surveillance Station (camera management)
Install Container Station via App Center
Configure Resources:
Network Setup:
CPU: 6 cores allocated
Memory: 6GB allocated
Storage: Enable on all volumes
Create custom networks for service isolation
Configure port mappings for external access
## Create on QNAP share: /share/Container/nas02/
mkdir -p /share/Container/nas02/{media,nvr,monitoring}
mkdir -p /share/Container/nas02/config/{caddy,secrets}
mkdir -p /share/Container/nas02/data/{jellyfin,frigate,sonarr,radarr}
Create /share/Container/nas02/.env:
## Domain Configuration
DOMAIN=speicher.family
SUBDOMAIN_NAS=nas02
## Plex/Jellyfin Configuration
JELLYFIN_DATA=/share/Container/nas02/data/jellyfin
MEDIA_ROOT=/share/Media
DOWNLOADS_ROOT=/share/Downloads
## Usenet Configuration
SABNZBD_API_KEY=<generated-key>
USENET_SERVER=<provider-server>
USENET_USER=<username>
USENET_PASS=<password>
## Indexer Configuration
SONARR_API_KEY=<generated-key>
RADARR_API_KEY=<generated-key>
JELLYSEERR_API_KEY=<generated-key>
## NVR Configuration
FRIGATE_CONFIG_PATH=/share/Container/nas02/config/frigate
FRIGATE_MEDIA_PATH=/share/Surveillance
CORAL_DEVICE=/dev/bus/usb
## Monitoring Configuration
BESZEL_AGENT_KEY=<agent-key>
BESZEL_SERVER=beszel.speicher.family:45876
## Network Configuration
TAILSCALE_AUTH_KEY=<auth-key>
LOCAL_NETWORK=192.168.1.0/24
## Authentication
AUTH_SECRET=<generated-secret>
ADMIN_USER=admin
ADMIN_PASS=<secure-password>
## Via QNAP App Center or manual installation
## Download Tailscale QNAP package
## Install via App Center > Install Manually
## Configure with auth key from Tailscale admin console
## Verify installation
tailscale status
tailscale ip -4 # Should show 100.92.167.34
## Via QTS Control Panel > Network & File Services > Security
## Allow services:
## - SSH (port 22) from Tailscale network
## - HTTP/HTTPS (80/443) from local network + Tailscale
## - Media services (8096, 8989, 7878) from local network
## - NVR (5000) from local network + Tailscale
## - Container Station (8080) from local network only
## Via Control Panel > Privilege > Shared Folders
## Create shares:
## - Media (read/write for media services)
## - Downloads (read/write for downloaders)
## - Backups (read/write for backup services)
## - TimeMachine (macOS backup destination)
## - Projects (development file storage)
## Configure SMB settings:
## - Enable SMB v2/v3
## - Disable SMB v1 for security
## - Configure guest access restrictions
Create /share/Container/nas02/media/docker-compose.yml:
version: '3.8'
services:
jellyfin:
image: linuxserver/jellyfin:latest
container_name: jellyfin
environment:
- PUID=1000
- PGID=1000
- TZ=America/New_York
volumes:
- ${JELLYFIN_DATA}:/config
- ${MEDIA_ROOT}:/media:ro
- /dev/dri:/dev/dri # Intel QuickSync
ports:
- "8096:8096"
restart: unless-stopped
networks:
- media
sonarr:
image: linuxserver/sonarr:latest
container_name: sonarr
environment:
- PUID=1000
- PGID=1000
- TZ=America/New_York
volumes:
- ${JELLYFIN_DATA}/sonarr:/config
- ${MEDIA_ROOT}/TV:/tv
- ${DOWNLOADS_ROOT}:/downloads
ports:
- "8989:8989"
restart: unless-stopped
networks:
- media
radarr:
image: linuxserver/radarr:latest
container_name: radarr
environment:
- PUID=1000
- PGID=1000
- TZ=America/New_York
volumes:
- ${JELLYFIN_DATA}/radarr:/config
- ${MEDIA_ROOT}/Movies:/movies
- ${DOWNLOADS_ROOT}:/downloads
ports:
- "7878:7878"
restart: unless-stopped
networks:
- media
jellyseerr:
image: fallenbagel/jellyseerr:latest
container_name: jellyseerr
environment:
- LOG_LEVEL=debug
- TZ=America/New_York
volumes:
- ${JELLYFIN_DATA}/jellyseerr:/app/config
ports:
- "5055:5055"
restart: unless-stopped
networks:
- media
sabnzbd:
image: linuxserver/sabnzbd:latest
container_name: sabnzbd
environment:
- PUID=1000
- PGID=1000
- TZ=America/New_York
volumes:
- ${JELLYFIN_DATA}/sabnzbd:/config
- ${DOWNLOADS_ROOT}:/downloads
- ${DOWNLOADS_ROOT}/incomplete:/incomplete-downloads
ports:
- "8080:8080"
restart: unless-stopped
networks:
- media
networks:
media:
driver: bridge
cd /share/Container/nas02/media
docker compose pull
docker compose up -d
## Verify services
docker ps
docker logs jellyfin
metube:
image: alexta69/metube:latest
container_name: metube
environment:
- UID=1000
- GID=1000
volumes:
- ${DOWNLOADS_ROOT}/youtube:/downloads
ports:
- "8081:8081"
restart: unless-stopped
networks:
- media
calibre-web:
image: linuxserver/calibre-web:latest
container_name: calibre-web
environment:
- PUID=1000
- PGID=1000
- TZ=America/New_York
volumes:
- ${JELLYFIN_DATA}/calibre-web:/config
- ${MEDIA_ROOT}/Books:/books
ports:
- "8083:8083"
restart: unless-stopped
networks:
- media
## Configure cameras with static IPs:
## Camera 1: 192.168.1.201 (Front Door)
## Camera 2: 192.168.1.202 (Backyard)
## Camera 3: 192.168.1.203 (Garage)
## Camera 4: 192.168.1.204 (Side Yard)
## Ensure cameras support:
## - RTSP streams
## - H.264 encoding
## - Multiple stream qualities
## Connect Google Coral USB accelerator
## Verify detection in QNAP
lsusb # Should show Google Coral device
## Add device to container access
## Configure in Container Station device access
Create /share/Container/nas02/nvr/docker-compose.yml:
version: '3.8'
services:
frigate:
image: ghcr.io/blakeblackshear/frigate:stable
container_name: frigate
restart: unless-stopped
privileged: true
environment:
- TZ=America/New_York
volumes:
- ${FRIGATE_CONFIG_PATH}:/config
- ${FRIGATE_MEDIA_PATH}:/media/frigate
- /dev/bus/usb:/dev/bus/usb # Coral USB
ports:
- "5000:5000"
- "8554:8554" # RTSP restream
- "8555:8555/tcp" # WebRTC
networks:
- nvr
networks:
nvr:
driver: bridge
Create /share/Container/nas02/config/frigate/config.yml:
mqtt:
enabled: false
detectors:
coral:
type: edgetpu
device: usb
cameras:
front_door:
ffmpeg:
inputs:
- path: rtsp://192.168.1.201/stream1
roles:
- record
- detect
detect:
width: 1920
height: 1080
fps: 5
zones:
entrance:
coordinates: 100,100,800,100,800,600,100,600
driveway:
coordinates: 800,400,1200,400,1200,800,800,800
objects:
track:
- person
- car
- bicycle
backyard:
ffmpeg:
inputs:
- path: rtsp://192.168.1.202/stream1
roles:
- record
- detect
detect:
width: 1920
height: 1080
fps: 5
zones:
yard:
coordinates: 0,300,1920,300,1920,1080,0,1080
objects:
track:
- person
- dog
- cat
record:
enabled: true
retain:
days: 30
mode: motion
events:
retain:
default: 30
mode: motion
snapshots:
enabled: true
timestamp: false
bounding_box: true
crop: false
retain:
default: 30
go2rtc:
streams:
front_door: rtsp://192.168.1.201/stream1
backyard: rtsp://192.168.1.202/stream1
Create /share/Container/nas02/monitoring/docker-compose.yml:
version: '3.8'
services:
beszel-agent:
image: henrygd/beszel-agent:latest
container_name: beszel-agent
restart: unless-stopped
network_mode: host
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
environment:
- KEY=${BESZEL_AGENT_KEY}
- URL=${BESZEL_SERVER}
dozzle:
image: amir20/dozzle:latest
container_name: dozzle-agent
restart: unless-stopped
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
ports:
- "9999:8080"
environment:
- DOZZLE_LEVEL=info
- DOZZLE_TAILSIZE=300
## Add to each service in docker-compose files:
logging:
driver: gelf
options:
gelf-address: "udp://192.168.1.4:12201"
tag: "nas02-{{.Name}}"
Create /share/Container/nas02/proxy/docker-compose.yml:
version: '3.8'
services:
caddy:
image: caddy:alpine
container_name: caddy-proxy
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ${CADDY_CONFIG_PATH}/Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
- caddy_config:/config
networks:
- proxy
- media
- nvr
volumes:
caddy_data:
caddy_config:
networks:
proxy:
driver: bridge
media:
external: true
nvr:
external: true
Create /share/Container/nas02/config/caddy/Caddyfile:
nas02.speicher.family {
handle /jellyfin* {
reverse_proxy jellyfin:8096
}
handle /sonarr* {
reverse_proxy sonarr:8989
}
handle /radarr* {
reverse_proxy radarr:7878
}
handle /jellyseerr* {
reverse_proxy jellyseerr:5055
}
handle /frigate* {
reverse_proxy frigate:5000
}
handle /sabnzbd* {
reverse_proxy sabnzbd:8080
}
handle {
respond "NAS02 Services Available"
}
}
Access http://nas02.speicher.family/jellyfin
Complete setup wizard
Add media libraries:
Configure hardware transcoding (Intel QuickSync)
Set up user accounts
/media/Movies/media/TV/media/Musichttp://nas02.speicher.family/frigate
#!/bin/bash
## /share/Container/nas02/scripts/backup-config.sh
BACKUP_DIR="/share/Backups/nas02-config"
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_PATH="$BACKUP_DIR/$DATE"
mkdir -p "$BACKUP_PATH"
## Backup Docker configurations
cp -r /share/Container/nas02 "$BACKUP_PATH/docker-configs"
## Backup QNAP configuration
/usr/bin/getcfg > "$BACKUP_PATH/qnap-config.conf"
## Cleanup old backups (keep 30 days)
find "$BACKUP_DIR" -type d -mtime +30 -exec rm -rf {} +
echo "Configuration backup completed: $BACKUP_PATH"
#!/bin/bash
## /share/Container/nas02/scripts/weekly-maintenance.sh
## Update all containers
cd /share/Container/nas02/media && docker compose pull && docker compose up -d
cd /share/Container/nas02/nvr && docker compose pull && docker compose up -d
cd /share/Container/nas02/monitoring && docker compose pull && docker compose up -d
## Clean Docker system
docker system prune -f
## QNAP system maintenance
/sbin/check_disk
/usr/bin/log_tool --export --output /share/Logs/qnap-logs-$(date +%Y%m%d).txt
echo "Weekly maintenance completed"
For daily operations and media management workflows, refer to the service configuration sections above.