Post

Three Weeks Ago I Was Still Subbed To Apple Music Netflix Hbo Librofm Etc A Lot Happened In Those Weeks Lol

Three Weeks Ago I Was Still Subbed To Apple Music Netflix Hbo Librofm Etc A Lot Happened In Those Weeks Lol

From Subscriptions to Self-Hosted: Building Your Personal Media Empire

Three weeks ago, you were paying monthly subscriptions to Apple Music, Netflix, HBO, Libro.fm, and countless other services. Now, you’re running a self-hosted media server that gives you complete control over your content library. This transformation represents more than just cost savings—it’s a fundamental shift in how we consume and manage digital media.

The journey from subscription services to self-hosted solutions has become increasingly popular among tech-savvy users who value privacy, control, and long-term cost efficiency. With the rise of powerful yet affordable hardware like the Raspberry Pi 5 and mini PCs, combined with user-friendly software stacks, anyone can build their own media empire.

In this comprehensive guide, we’ll walk through the exact steps taken to migrate from subscription services to a fully self-hosted media ecosystem. We’ll cover hardware selection, software installation, configuration, and optimization—everything you need to know to take control of your digital media consumption.

Understanding Self-Hosted Media Solutions

Self-hosted media solutions represent a paradigm shift in how we consume digital content. Instead of paying recurring subscription fees and being subject to content availability changes, you maintain complete control over your media library. This approach offers several compelling advantages:

Cost Efficiency: While there’s an initial investment in hardware and setup time, the long-term savings are substantial. Consider that a typical household might spend $50-100 monthly on various streaming services. A well-configured media server can pay for itself within months.

Content Control: Your media library remains intact regardless of licensing changes or service discontinuations. You decide what to keep, how to organize it, and when to access it.

Privacy: Self-hosted solutions eliminate third-party tracking and data collection associated with commercial streaming services.

Customization: You can tailor your media experience to your exact preferences, from user interfaces to automated organization systems.

The technology stack for self-hosted media has matured significantly over the past few years. Modern solutions offer enterprise-grade features while maintaining user-friendly interfaces. The ARR (Automated Rarities) stack—comprising Sonarr, Radarr, and their companion tools—has become the de facto standard for automated media management.

Hardware Requirements and Selection

Core Server Hardware

The foundation of any self-hosted media server is reliable hardware. For this setup, we’ll focus on two primary options: the Raspberry Pi 5 and mini PCs.

Raspberry Pi 5 Configuration:

1
2
3
4
5
6
# Recommended specifications for media server
Raspberry Pi 5 Model
- 8GB RAM (minimum 4GB)
- 32GB or larger microSD card
- Active cooling solution (heatsink + fan)
- 5V/3A USB-C power supply

Mini PC Configuration:

1
2
3
4
5
6
7
# Higher-end option for demanding workloads
Mini PC Specifications
- Intel i3/i5 or AMD Ryzen 3/5 processor
- 16GB DDR4 RAM (minimum 8GB)
- 256GB NVMe SSD for OS
- 2.5" drive bays for storage
- Gigabit Ethernet port

Storage Considerations

Storage is critical for media servers. Calculate your needs based on current library size and expected growth:

1
2
3
4
5
6
7
# Storage calculation example
Movies: 4TB (1000+ films at 4GB each)
TV Shows: 6TB (200+ series at 30GB per season)
Music: 500GB (10,000+ albums)
Audiobooks: 200GB (500+ titles)
Podcasts: 100GB (10 years of subscriptions)
Total: ~11TB minimum

Recommended Storage Setup:

  • 2x 8TB WD Red NAS drives (RAID 1 for redundancy)
  • 1x 500GB SSD for cache and applications
  • Optional: Additional drives for future expansion

Network Infrastructure

A robust network is essential for media streaming:

1
2
3
4
5
6
7
Network Requirements:
  Bandwidth: Minimum 100Mbps, Recommended 1Gbps
  Router: Gigabit with QoS support
  Switch: Managed switch for VLAN separation
  WiFi: 802.11ac/ax for wireless clients
  Static IP: Recommended for server
  Port Forwarding: Required for remote access

Software Stack Installation

Operating System Setup

Raspberry Pi OS (64-bit) Installation:

1
2
3
4
5
6
7
8
9
10
11
# Flash the SD card with Raspberry Pi OS
wget https://downloads.raspberrypi.org/raspios_arm64/images/raspios_arm64-2024-01-08/2024-01-08-raspios-bullseye-arm64.img.xz
unzip 2024-01-08-raspios-bullseye-arm64.img.xz
sudo dd if=2024-01-08-raspios-bullseye-arm64.img of=/dev/sdX bs=4M status=progress conv=fsync

# Initial configuration
sudo raspi-config
# - Set locale and timezone
# - Expand filesystem
# - Enable SSH
# - Set hostname (plex-server)

Ubuntu Server Installation (for Mini PC):

1
2
3
4
5
6
7
8
# Create bootable USB
sudo mkusb -p /path/to/ubuntu-22.04.2-live-server-amd64.iso /dev/sdX

# During installation:
# - Select minimal installation
# - Configure static IP
# - Create user with sudo privileges
# - Install OpenSSH server

Docker and Docker Compose Setup

Containerization provides isolation and easy management:

1
2
3
4
5
6
7
8
9
10
11
12
# Install Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER

# Install Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/download/2.18.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

# Verify installation
docker --version
docker-compose --version

Media Server Applications

Plex Media Server Configuration:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# docker-compose.yml for Plex
version: '3.8'
services:
  plex:
    image: plexinc/pms-docker:latest
    container_name: plex
    restart: unless-stopped
    network_mode: host
    environment:
      - PLEX_UID=1000
      - PLEX_GID=1000
      - TZ=America/New_York
      - ADVERTISE_IP=http://server.local:32400/
    volumes:
      - ./config/plex:/config
      - ./transcode:/transcode
      - /path/to/movies:/data/movies
      - /path/to/tv:/data/tv
      - /path/to/music:/data/music

Sonarr (TV Shows) Setup:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# docker-compose.yml for Sonarr
version: '3.8'
services:
  sonarr:
    image: hotio/sonarr:latest
    container_name: sonarr
    restart: unless-stopped
    ports:
      - "8989:8989"
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=America/New_York
    volumes:
      - ./config/sonarr:/config
      - /path/to/tv:/tv
      - /path/to/downloads:/downloads

Radarr (Movies) Setup:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# docker-compose.yml for Radarr
version: '3.8'
services:
  radarr:
    image: hotio/radarr:latest
    container_name: radarr
    restart: unless-stopped
    ports:
      - "7878:7878"
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=America/New_York
    volumes:
      - ./config/radarr:/config
      - /path/to/movies:/movies
      - /path/to/downloads:/downloads

Lidarr (Music) Setup:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# docker-compose.yml for Lidarr
version: '3.8'
services:
  lidarr:
    image: hotio/lidarr:latest
    container_name: lidarr
    restart: unless-stopped
    ports:
      - "8686:8686"
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=America/New_York
    volumes:
      - ./config/lidarr:/config
      - /path/to/music:/music
      - /path/to/downloads:/downloads

Booksonic (Audiobooks) Setup:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# docker-compose.yml for Booksonic
version: '3.8'
services:
  booksonic:
    image: linuxserver/booksonic:latest
    container_name: booksonic
    restart: unless-stopped
    ports:
      - "4040:4040"
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=America/New_York
    volumes:
      - ./config/booksonic:/config
      - /path/to/audiobooks:/audiobooks

Download Client Configuration

Transmission Setup:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# docker-compose.yml for Transmission
version: '3.8'
services:
  transmission:
    image: linuxserver/transmission:latest
    container_name: transmission
    restart: unless-stopped
    ports:
      - "9091:9091"
      - "51413:51413"
      - "51413:51413/udp"
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=America/New_York
      - TRANSMISSION_WEB_HOME=/combustion-release/
      - USER=username
      - PASS=password
    volumes:
      - ./config/transmission:/config
      - /path/to/downloads:/downloads
      - /path/to/watch:/watch

Network Configuration and Security

Port Forwarding Setup

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Port forwarding configuration for router
# Plex Media Server
32400 (TCP) - Plex Web App
32469 (TCP/UDP) - DLNA
3005 (TCP) - Plex Companion
8324 (TCP) - Plex Companion
32412, 32413, 32414 (UDP) - Plex DLNA

# Sonarr
8989 (TCP) - Web Interface

# Radarr
7878 (TCP) - Web Interface

# Lidarr
8686 (TCP) - Web Interface

# Booksonic
4040 (TCP) - Web Interface

# Transmission
9091 (TCP) - Web Interface
51413 (TCP/UDP) - Peer Connections

Firewall Configuration

1
2
3
4
5
6
7
8
9
10
# UFW firewall rules
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 32400/tcp comment 'Plex Media Server'
sudo ufw allow 8989/tcp comment 'Sonarr'
sudo ufw allow 7878/tcp comment 'Radarr'
sudo ufw allow 8686/tcp comment 'Lidarr'
sudo ufw allow 4040/tcp comment 'Booksonic'
sudo ufw enable

SSL/TLS Setup with Let’s Encrypt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# docker-compose.yml with SSL
version: '3.8'
services:
  nginx-proxy:
    image: nginxproxy/nginx-proxy:latest
    container_name: nginx-proxy
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro
      - ./nginx/vhost.d:/etc/nginx/vhost.d
      - ./nginx/html:/usr/share/nginx/html
      - ./letsencrypt:/etc/nginx/certs:ro

  letsencrypt:
    image: jrcs/letsencrypt-nginx-proxy-companion:latest
    container_name: letsencrypt
    restart: unless-stopped
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./letsencrypt:/etc/nginx/certs:rw
      - ./nginx/vhost.d:/etc/nginx/vhost.d
      - ./nginx/html:/usr/share/nginx/html
    environment:
      - NGINX_PROXY_CONTAINER=nginx-proxy

Media Library Organization

Directory Structure

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# Recommended media directory structure
/media/
├── movies/
│   ├── Action/
│   ├── Comedy/
│   ├── Drama/
│   └── Sci-Fi/
├── tv/
│   ├── Show Name (2020)/
│   │   ├── Season 01/
│   │   ├── Season 02/
│   │   └── Specials/
│   └── Another Show/
├── music/
│   ├── Artist Name/
│   │   ├── Album Name/
│   │   └── Album Name/
│   └── Various Artists/
├── audiobooks/
│   ├── Author Name/
│   │   ├── Series Name/
│   │   └── Standalone Titles/
│   └── Various Authors/
└── podcasts/
    ├── Podcast Name/
    └── Podcast Name/

File Naming Conventions

Movies:

1
2
Movie.Name.(Year).Resolution.Codec.Audio.Extension
Example: Inception.(2010).1080p.BluRay.x264.DTS-HD.mkv

TV Shows:

1
2
Show.Name.S01E01.Episode.Title.Resolution.Codec.Extension
Example: Breaking.Bad.S01E01.Pilot.1080p.BluRay.x264.mkv

Music:

1
2
3
4
Artist - Album (Year)/
├── 01 - Track Name.flac
├── 02 - Track Name.flac
└── cover.jpg

Automation and Monitoring

Automated Downloads with Sonarr/Radarr

Sonarr Setup:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Sonarr indexers and download clients
Indexers:
- Jackett (NZB)
- Torrent RSS feeds
Quality Profiles:
- Any (SD)
- SD (480p)
- HD 720p
- HD 1080p
- HD 1080p (Proper)
- Ultra HD 4K

Automatic Processing:
- Rename files
- Move to correct location
- Update Plex library
- Download subtitles

Radarr Setup:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Radarr quality profiles
Profiles:
- Custom (1080p Bluray)
- Custom (4K Bluray)
- Custom (3D Bluray)

Monitored:
- All movies
- Specific titles
- By folder

Automatic Actions:
- Rename and organize
- Notify Plex
- Download metadata

Monitoring with Prometheus and Grafana

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# docker-compose.yml for monitoring
version: '3.8'
services:
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    restart: unless-stopped
    ports:
      - "9090:9090"
    volumes:
      - ./config/prometheus:/etc/prometheus
      - prometheus_data:/prometheus

  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    restart: unless-stopped
    ports:
      - "3000:3000"
    volumes:
      - grafana_data:/var/lib/grafana
      - ./config/grafana:/etc/grafana/provisioning

  node-exporter:
    image: prom/node-exporter:latest
    container_name: node-exporter
    restart: unless-stopped
    ports:
      - "9100:9100"
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro

Backup and Disaster Recovery

Backup Strategy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Automated backup script
#!/bin/bash
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/path/to/backups"
CONFIGS_DIR="/path/to/configs"
MEDIA_DIR="/path/to/media"

# Backup configurations
tar -czf $BACKUP_DIR/configs_$DATE.tar.gz $CONFIGS_DIR

# Backup media database
sqlite3 /path/to/plex/database.db .dump > $BACKUP_DIR/plex_db_$DATE.sql

# Sync to external drive
rsync -avh --delete $MEDIA_DIR /path/to/external_drive/

# Clean old backups (keep last 7 days)
find $BACKUP_DIR -name "configs_*.tar.gz" -mtime +7 -delete
find $BACKUP_DIR -name "plex_db_*.sql" -mtime +7 -delete

Disaster Recovery Plan

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Recovery Procedures:
  Primary Server Failure:
    - Restore from latest backup
    - Rebuild Docker containers
    - Restore configurations
    - Verify media integrity

  Data Corruption:
    - Check RAID status
    - Restore from backup
    - Verify file checksums
    - Rebuild media library

  Network Issues:
    - Check port forwarding
    - Verify firewall rules
    - Test connectivity
    - Restart services

Performance Optimization

Media Transcoding Optimization

1
2
3
4
5
6
7
8
# Plex transcoding settings
Transcoder settings:
  Hardware acceleration: Enabled (if supported)
  Transcoder temporary directory: SSD
  Maximum simultaneous transcodes: 2-3
  Transcoding quality: Prefer higher speed
  Allow video stream copying: Yes
  Allow audio stream copying: Yes

Storage Optimization

1
2
3
4
5
6
# ZFS pool configuration for optimal performance
zpool create media raidz2 /dev/disk1 /dev/disk2 /dev/disk3 /dev/disk4 /dev/disk5 /dev/disk6
zfs set compression=lz4 media
zfs set atime=off media
zfs set dedup=off media
zfs set recordsize=1M media

Network Optimization

1
2
3
4
5
6
# Network tuning for media streaming
sudo sysctl -w net.core.rmem_max=16777216
sudo sysctl -w net.core.wmem_max=16777216
sudo sysctl -w net.ipv4.tcp_rmem='4096 87380 16777216'
sudo sysctl -w net.ipv4.tcp_wmem='4096 65536 16777216'
sudo sysctl -w net.ipv4.tcp_congestion_control=bbr

Advanced Features and Integrations

Mobile Sync and Offline Access

1
2
3
4
5
6
Mobile Sync Configuration:
  Enable: Yes
  Quality: Original (WiFi), Optimized (Mobile)
  Download limit: 50GB per device
  Sync duration: 30 days
  Automatic cleanup: Yes

Smart Home Integration

1
2
3
4
5
6
7
8
9
10
11
12
# Home Assistant integration
media_player:
  - platform: plex
    host: 192.168.1.100
    port: 32400
    name: Plex Media Server
    username: !secret plex_username
    password: !secret plex_password
    timeout: 30
    show_all_controls: false
    include_non_clients: true
    scan_interval: 5

API Integration and Automation

1
2
3
4
5
6
7
# Python script for automated library management
import requests
import json
import time

PLEX_URL = "http://localhost:32400"
PLEX_TOKEN = "your_plex_token
This post is licensed under CC BY 4.0 by the author.