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 Compatibility✅ Universal❌ Conflicts
Docker Desktop Extensions✅ No conflicts❌ Subnet conflicts
Maintenance✅ Zero config❌ Subnet 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 stack✅ Recommended❌ Unnecessary❌ Overkill
Multi-host deployment❌ Single host only❌ Single host only✅ Required
Microservices with isolation❌ All services communicate✅ Recommended✅ Recommended
Development environments✅ Recommended❌ Maintenance overhead❌ Unnecessary
Production single-node✅ Recommended⚠️ 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, start from the landing pages:

TierURLNotes
Public/friendshttps://joe-steambox.alai-opaleye.ts.netFriend-safe media dashboard
Admin/adulthttps://joe-steambox.alai-opaleye.ts.net:8443Admin + adult dashboard, two-factor gated

Most direct service links now use Tailscale Serve HTTPS rather than raw http://100.115.21.9:<port> links:

text
https://joe-steambox.alai-opaleye.ts.net:8989   # Sonarr
https://joe-steambox.alai-opaleye.ts.net:7878   # Radarr
https://joe-steambox.alai-opaleye.ts.net:8180   # SABnzbd
https://100-115-21-9.a45a678d4702421bbeb6c7623deb3eff.plex.direct:32400/web  # Plex
https://joe-steambox.alai-opaleye.ts.net:9696   # Prowlarr
https://joe-steambox.alai-opaleye.ts.net:8265   # Tdarr

Exception: Transmission/Gluetun currently remains direct-tailnet only at http://100.115.21.9:9092 because port 9092 has no Tailscale Serve mapping.

Plex Configuration for Tailscale ​

In Plex Settings → Network:

  1. Custom server access URLs: Prefer the current plex.direct tailnet URL: https://100-115-21-9.a45a678d4702421bbeb6c7623deb3eff.plex.direct:32400
  2. LAN Networks: Add 100.64.0.0/10 (Tailscale CGNAT range)
  3. Secure connections: Set to "Preferred" or "Required" once clients are confirmed compatible
  4. Remote access: Can disable public 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 through Tailscale Serve
curl -I https://joe-steambox.alai-opaleye.ts.net:8989  # Sonarr

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