Skip to content

Docker Networking Solution - Portable Media Stack

TL;DR: Removed custom networks with hardcoded subnets. Now uses default Docker bridge networking for universal compatibility across Linux/macOS/Windows without subnet conflicts.

Problem Analysis ✅ SOLVED

Your original docker-compose.yml defined custom networks with hardcoded subnets that conflicted with Docker Desktop extensions:

yaml
# ❌ PROBLEMATIC (Original)
networks:
  media_network:
    name: usenet_media_network
    driver: bridge
    ipam:
      config:
        - subnet: 172.20.0.0/16  # CONFLICT!
  sharing_network:
    name: usenet_sharing_network 
    driver: bridge
    ipam:
      config:
        - subnet: 172.21.0.0/16  # CONFLICT!

Docker Desktop Extension Conflicts Detected:

  • 172.17.0.0/16 - Default bridge network
  • 172.19.0.0/16 - Portainer extension
  • 172.20.0.0/16 - VS Code installer extension ← YOUR CONFLICT
  • 172.22.0.0/16 - AI tools extension

Modern Portable Solution ✅ IMPLEMENTED

1. Removed All Custom Networks

yaml
# ✅ SOLUTION: No networks section = uses default bridge
# NO hardcoded subnets
# NO extension conflicts  
# NO cross-platform issues

2. Why This Works Better

For Media Automation Stacks, Custom Networks Provide ZERO Benefits:

RequirementDefault BridgeCustom Networks
Service Discovery✅ Container names work✅ Container names work
Inter-service Communication✅ All services can reach each other✅ All services can reach each other
Port Publishing✅ Works identically✅ Works identically
DNS Resolution✅ Automatic✅ Automatic
Resource Isolation✅ Process isolation✅ Process isolation
Cross-platform CompatibilityUniversalConflicts
Docker Desktop ExtensionsNo conflictsSubnet conflicts
MaintenanceZero configSubnet management

3. Inter-Service Communication Examples

All your services communicate the same way as before:

yaml
# Sonarr connects to SABnzbd
SABNZBD_HOST: sabnzbd
SABNZBD_PORT: 8080

# Radarr connects to SABnzbd  
SABNZBD_HOST: sabnzbd
SABNZBD_PORT: 8080

# Bazarr connects to Sonarr/Radarr
SONARR_HOST: sonarr
SONARR_PORT: 8989
RADARR_HOST: radarr  
RADARR_PORT: 7878

Container names work identically on default bridge network.

Modern Docker Compose Best Practices

1. Network Architecture Principles

yaml
# ✅ MODERN APPROACH
services:
  sonarr:
    # NO networks: section
    # Uses default bridge automatically
    # Container name 'sonarr' is DNS resolvable
    
  radarr:
    # NO networks: section  
    # Can reach sonarr via 'sonarr:8989'
    
  sabnzbd:
    # NO networks: section
    # All *arr services reach via 'sabnzbd:8080'

2. When You SHOULD Use Custom Networks

Custom networks are beneficial for:

  • Complex multi-tier applications (web/app/db tiers)
  • Strict security isolation (DMZ, internal services)
  • External network integration (connecting to existing networks)
  • Advanced routing requirements (multiple external interfaces)

Custom networks are NOT beneficial for:

  • Media automation stacks (your use case)
  • Development environments
  • Single-host deployments
  • Docker Desktop usage

3. Cross-Platform Compatibility

PlatformDefault BridgeCustom Networks
Linux Docker✅ Always works⚠️ May conflict with host networks
macOS Docker Desktop✅ Always works⚠️ May conflict with extensions
Windows Docker Desktop✅ Always works⚠️ May conflict with extensions
Docker Swarm✅ Works with overlay⚠️ Requires careful network design

CLI Command Reliability

Before (Custom Networks)

bash
# ❌ Unreliable - subnet conflicts cause failures
docker compose up                    # "Pool overlaps" errors
usenet --start                      # Network creation failures  
usenet --stop                       # Inconsistent behavior

After (Default Bridge)

bash
# ✅ Reliable - no network conflicts possible
docker compose up                    # Always works
usenet --start                      # Always works
usenet --stop                       # Always works

Files Modified ✅

1. Main Configuration Fixed

  • File: docker-compose.yml
  • Change: Removed all networks: sections from services and networks definition
  • Result: Uses default bridge network automatically

2. Portable Reference Created

  • File: docker-compose.portable.yml
  • Purpose: Clean reference implementation with core services
  • Usage: Copy-paste template for new environments

Testing Results ✅

bash
# ✅ Configuration Valid
$ docker compose config --services
transmission
sabnzbd
radarr
sonarr
bazarr
# ... (all 20 services listed)

# ✅ Dry Run Successful
$ docker compose up --dry-run
DRY-RUN MODE - Network usenet_default Creating
DRY-RUN MODE - Network usenet_default Created
# ... (all containers create successfully)

1. Immediate Use

bash
# Your existing compose file now works without conflicts
cd /home/joe/usenet
docker compose up -d

# All services accessible at usual ports:
# http://localhost:8989 (Sonarr)
# http://localhost:7878 (Radarr)  
# http://localhost:8080 (SABnzbd)
# http://localhost:32400 (Plex)

2. Agent-Friendly CLI

bash
# These commands now work reliably
./usenet --start                    # Starts all services
./usenet --stop                     # Stops all services
./usenet status                     # Shows service health

3. Development/Testing

bash
# Use portable version for clean testing
docker compose -f docker-compose.portable.yml up -d

Network Security Notes

Q: Is removing custom networks less secure?

A: No security difference for your use case.

  • Process Isolation: Identical (Docker's core security model)
  • Port Access: Identical (services only accessible via published ports)
  • Host Access: Identical (containers cannot access host by default)
  • Inter-container: Identical (containers can reach each other via names)

Custom networks provide network-level isolation, which is irrelevant when:

  • All services need to communicate with each other (your media stack)
  • All services are trusted (your own applications)
  • External access is controlled via published ports (your setup)

Long-term Maintainability

✅ Benefits of Default Bridge Approach

  • Zero network configuration to maintain
  • No subnet planning required
  • Universal compatibility across Docker environments
  • Immune to Docker Desktop extension conflicts
  • Simpler troubleshooting (fewer moving parts)
  • Better documentation (standard Docker patterns)

❌ Problems Solved

  • ❌ No more "Pool overlaps with other one on this address space" errors
  • ❌ No more Docker Desktop extension conflicts
  • ❌ No more cross-platform networking issues
  • ❌ No more subnet management overhead
  • ❌ No more agent CLI networking failures

Advanced Troubleshooting Guide

Common Network Issues and Solutions

1. Service Discovery Problems

bash
# ❌ Problem: "curl: (6) Could not resolve host: sonarr"
# ✅ Solution: Check container names and ensure services are running

# Verify all containers are running
docker compose ps

# Test DNS resolution between containers
docker compose exec radarr nslookup sonarr
docker compose exec sonarr ping -c 3 sabnzbd

# Expected: Container names resolve to internal Docker IPs (172.17.x.x range)

2. Port Binding Conflicts

bash
# ❌ Problem: "Error starting userland proxy: listen tcp 0.0.0.0:8080: bind: address already in use"
# ✅ Solution: Find and stop conflicting services

# Find what's using the port
sudo netstat -tulpn | grep :8080
# or
sudo lsof -i :8080

# Change port mapping if needed (doesn't affect inter-service communication)
ports:
  - "8081:8080"  # External:Internal - internal stays 8080 for service discovery

3. Docker Desktop Extension Conflicts (Legacy)

bash
# ❌ Problem: "Pool overlaps with other one on this address space"  
# ✅ Solution: Already solved - no custom networks = no conflicts

# If you still see this error, you may have old custom networks:
docker network ls | grep usenet
docker network prune  # Remove unused networks

4. Cross-Platform DNS Resolution Issues

bash
# ❌ Problem: Services can't find each other on Windows/macOS
# ✅ Solution: Use container names (works identically across platforms)

# Inside any container, this works on all platforms:
curl http://sonarr:8989/api/v3/system/status
curl http://radarr:7878/api/v3/system/status  
curl http://sabnzbd:8080/api?mode=version

Network Debugging Commands

Container Network Inspection

bash
# View network configuration for all services
docker compose ps --format "table {{.Name}}\t{{.Ports}}"

# Inspect specific container network settings
docker inspect <container_name> | grep -A 20 '"NetworkSettings"'

# View default bridge network details
docker network inspect bridge

Inter-Service Communication Testing

bash
# Test communication between services (inside containers)
docker compose exec sonarr wget -qO- http://sabnzbd:8080/api?mode=version
docker compose exec radarr curl -s http://prowlarr:9696/api/v1/system/status
docker compose exec plex ping -c 1 sonarr

# Test from host to services
curl http://localhost:8989/api/v3/system/status  # Sonarr
curl http://localhost:7878/api/v3/system/status  # Radarr

Performance Optimization

Network Performance Best Practices

bash
# Monitor network usage between containers
docker stats --format "table {{.Container}}\t{{.NetIO}}"

# For high-throughput scenarios (large file transfers), consider:
# 1. Host networking for specific services (loses container isolation)
# 2. Optimized Docker daemon settings
# 3. SSD storage for Docker root directory

Memory and Connection Limits

yaml
# Optimize for large media libraries
services:
  sonarr:
    deploy:
      resources:
        limits:
          memory: 1G        # Increase if you have >10k episodes
    environment:
      - "DOCKER_MODS=linuxserver/mods:universal-tshoot"  # For debugging

Modern Docker Compose Networking Reference

When to Use Custom Networks (2024 Update)

Use CaseDefault BridgeCustom BridgeOverlay Networks
Single-host media stackRecommended❌ Unnecessary❌ Overkill
Multi-host deployment❌ Single host only❌ Single host onlyRequired
Microservices with isolation❌ All services communicateRecommendedRecommended
Development environmentsRecommended❌ Maintenance overhead❌ Unnecessary
Production single-nodeRecommended⚠️ Only if security requires⚠️ Only if scaling planned

Network Security Model Comparison

yaml
# DEFAULT BRIDGE (Current implementation)
# ✅ Process isolation via Docker
# ✅ Port-based access control  
# ✅ No network-level restrictions between containers
# ✅ Simplest security model - appropriate for trusted services

# CUSTOM BRIDGE (Previous implementation)  
# ✅ Process isolation via Docker
# ✅ Port-based access control
# ✅ Network-level isolation (can restrict container communication)
# ❌ Subnet management complexity
# ❌ Cross-platform compatibility issues

# OVERLAY NETWORKS (Multi-host)
# ✅ Process isolation via Docker
# ✅ Port-based access control
# ✅ Network-level isolation + encryption
# ✅ Multi-host service discovery
# ❌ Complex setup and troubleshooting

Container Communication Patterns

Service-to-Service API Calls

bash
# Pattern: http://<container_name>:<internal_port>/<path>
# Works identically on default bridge and custom networks

# Examples used by *arr services:
SONARR_URL: "http://sonarr:8989"
RADARR_URL: "http://radarr:7878"  
PROWLARR_URL: "http://prowlarr:9696"
SABNZBD_URL: "http://sabnzbd:8080"

Database Connections (if added)

yaml
# If you add a database service later:
postgres:
  image: postgres:15
  container_name: media-db
  environment:
    POSTGRES_DB: media
    
sonarr:
  environment:
    # Connect to database using container name
    - "ConnectionStrings__Main=Server=media-db;Database=sonarr;..."

Monitoring and Observability

Network Metrics Collection

bash
# Add to your monitoring stack for network insights:
# 1. Netdata (already included) - shows container network I/O
# 2. Docker stats - real-time container metrics  
# 3. Container logs - application-level network errors

# View real-time network usage
watch "docker stats --no-stream --format 'table {{.Container}}\t{{.NetIO}}'"

Log Analysis for Network Issues

bash
# Check for common network errors in container logs
docker compose logs | grep -i "connection refused\|timeout\|network\|dns"

# Service-specific network debugging
docker compose logs sonarr | grep -i "sabnzbd\|download"
docker compose logs radarr | grep -i "download\|indexer"

Future-Proofing Your Network Architecture

Scaling Considerations

Adding More Services

yaml
# New services automatically join default bridge
lidarr:  # Music automation
  image: lscr.io/linuxserver/lidarr:latest
  container_name: lidarr
  # No networks: section needed
  # Automatically discovers sonarr, radarr, prowlarr, etc.

Multi-Host Expansion (Docker Swarm)

bash
# If you later need multi-host deployment:
docker swarm init
# Services automatically get overlay networks
# Container name discovery works across hosts

Migration Strategies

From Custom Networks (Historical)

bash
# If migrating from old custom network setup:
1. Backup configuration: ./usenet --backup create
2. Stop services: docker compose down  
3. Remove custom networks: docker network prune
4. Update compose file (remove networks sections)
5. Start services: docker compose up -d
# No application configuration changes needed

To External Network Integration

bash
# If you later need to connect to external networks:
networks:
  default:  # Still use default for internal communication
    external: false
  external_network:  # Connect specific services to external networks
    external: true
    name: company_network
    
services:
  overseerr:  # Example: expose only request interface externally
    networks:
      - default              # Talk to other services
      - external_network     # Accept external requests

Summary: Your media automation stack now uses modern Docker networking best practices with universal compatibility and zero maintenance overhead. This foundation scales from single-node deployment to enterprise multi-host orchestration without architectural changes.


Remote Access with Tailscale

Why Tailscale (Configured: 2025-12-29)

Problem: ISP (Live Oak Fiber) rotates external IPs aggressively, breaking Plex remote access and any port-forwarding-based solutions.

Solution: Tailscale provides a stable mesh VPN with fixed IP addresses regardless of ISP changes.

How Tailscale Works

┌─────────────────────────────────────────────────────────────┐
│                     Tailscale Network                       │
│                                                             │
│   ┌──────────────┐         ┌──────────────┐                │
│   │ Media Server │◄───────►│ Phone/Laptop │                │
│   │ 100.x.x.x    │         │ 100.y.y.y    │                │
│   │ (Bazzite)    │ WireGuard│ (Any device) │                │
│   └──────────────┘  tunnel └──────────────┘                │
│                                                             │
└─────────────────────────────────────────────────────────────┘
         │                           │
         ▼                           ▼
   ┌──────────┐               ┌──────────┐
   │ ISP #1   │               │ ISP #2   │
   │ Dynamic  │               │ Different│
   │ IP       │               │ Network  │
   └──────────┘               └──────────┘

Key Benefits:

  • Stable IPs: Each device gets a fixed 100.x.x.x address
  • Zero port forwarding: No router configuration needed
  • ISP-agnostic: Works across any network (home, mobile, coffee shop)
  • Encrypted: WireGuard end-to-end encryption
  • More secure than port forwarding: No exposed services to the internet

Current Configuration

DeviceTailscale IPPurpose
Media Server (Bazzite)100.115.21.9Hosts all services
Additional devicesJoin network via tailscale upAccess services

Accessing Services via Tailscale

Once connected to your Tailscale network, access all services using the Tailscale IP:

bash
# From any Tailscale-connected device:
http://100.115.21.9:8989    # Sonarr
http://100.115.21.9:7878    # Radarr
http://100.115.21.9:8080    # SABnzbd
http://100.115.21.9:32400   # Plex
http://100.115.21.9:9696    # Prowlarr
http://100.115.21.9:8265    # Tdarr

Plex Configuration for Tailscale

In Plex Settings → Network:

  1. Custom server access URLs: Add http://100.115.21.9:32400
  2. LAN Networks: Add 100.64.0.0/10 (Tailscale CGNAT range)
  3. Secure connections: Set to "Preferred" (Tailscale handles encryption)
  4. Remote access: Can disable port forwarding entirely if using Tailscale exclusively

Security Model

Tailscale vs Port Forwarding:

AspectPort ForwardingTailscale
Attack surfaceExposed to internetOnly Tailscale network
AuthenticationService-level onlyNetwork-level + service
IP exposurePublic IP visiblePrivate 100.x.x.x only
Brute force riskHigh (internet-facing)Low (must join network first)
ISP dependencyRequires static IP or DDNSNone

Best Practice: Keep services bound to localhost or Tailscale IP only. No need to expose ports publicly.

Adding New Devices

bash
# On any device you want to connect:
# 1. Install Tailscale
# 2. Authenticate with same account
tailscale up

# Device automatically joins your network and can access services

Troubleshooting

bash
# Check Tailscale status
tailscale status

# Verify connectivity to media server
ping 100.115.21.9

# Check if services are reachable
curl -s http://100.115.21.9:8989/api/v3/system/status  # Sonarr

Built with ❤️ following Bell Labs standards. Dedicated to Stan Eisenstat.