Tu Propio
Spotify Local
en Proxmox
Servidor de streaming musical autoalojado con descarga automática de las listas más escuchadas de EE.UU., España, México y más. Sin suscripciones, sin rastreo, 100% tuyo.
Introducción y Arquitectura
Esta guía cubre la instalación completa de un servidor de música tipo Spotify, autoalojado en Proxmox. Combinaremos dos herramientas potentes:
Navidrome — Servidor de streaming musical open source, ligero y compatible con el protocolo Subsonic. Interfaz web moderna con soporte para múltiples usuarios, playlists, favoritos, letras y transcodificación al vuelo.
spotDL — Herramienta CLI que busca canciones en YouTube a partir de metadatos de Spotify. Descarga con carátulas, letras y metadatos completos. Su función sync permite mantener playlists actualizadas automáticamente.
Arquitectura del Sistema
Host de virtualización
Debian 12 + Docker
Puerto 4533
Descarga automática
Volumen compartido
Requisitos Previos
Hardware
Navidrome es extremadamente ligero. Puede correr hasta en un Raspberry Pi.
| Componente | Mínimo | Recomendado |
|---|---|---|
| CPU | 1 core | 2 cores |
| RAM | 512 MB | 1-2 GB |
| Disco (SO) | 8 GB | 20 GB |
| Disco (música) | Según colección | 500 GB+ (HDD/NAS) |
Software
Proxmox VE 7.x o superior instalado y funcionando, acceso SSH al host, y conexión a internet en el contenedor para descargar música.
Creación del Contenedor LXC en Proxmox
Opción A: Interfaz Web
Abre la interfaz web de Proxmox en https://tu-ip:8006
Descarga el template de Debian 12 o Ubuntu 24.04 desde el repositorio
Crea un nuevo contenedor CT con los parámetros de la tabla
| Parámetro | Valor |
|---|---|
| Hostname | navidrome |
| Template | debian-12-standard o ubuntu-24.04 |
| Disco raíz | 16 GB |
| CPU | 2 cores |
| Memoria | 1024 MB |
| Swap | 512 MB |
| Red | DHCP o IP estática |
| Nesting | ✅ Habilitado (necesario para Docker) |
Opción B: Línea de Comandos SSH
# Descargar template (si no lo tienes) pveam download local debian-12-standard_12.7-1_amd64.tar.zst # Crear contenedor pct create 200 local:vztmpl/debian-12-standard_12.7-1_amd64.tar.zst \ --hostname navidrome \ --memory 1024 --swap 512 \ --cores 2 \ --rootfs local-lvm:16 \ --net0 name=eth0,bridge=vmbr0,ip=dhcp \ --features nesting=1 \ --unprivileged 1 \ --start 1
Es muy recomendable asignar una IP estática para acceder siempre a Navidrome en la misma dirección. Usa: --net0 name=eth0,bridge=vmbr0,ip=192.168.1.50/24,gw=192.168.1.1
Montar almacenamiento externo (NAS/disco)
# Editar /etc/pve/lxc/200.conf en el host Proxmox # Agregar línea para montar directorio: mp0: /mnt/nas/music,mp=/mnt/music
Instalación de Docker y Docker Compose
Entra al contenedor y ejecuta los siguientes comandos para instalar Docker desde el repositorio oficial:
# Entrar al contenedor desde Proxmox pct enter 200 # Actualizar paquetes apt update && apt upgrade -y # Instalar dependencias apt install -y ca-certificates curl gnupg lsb-release # Agregar repositorio oficial de Docker install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/debian/gpg \ | gpg --dearmor -o /etc/apt/keyrings/docker.gpg chmod a+r /etc/apt/keyrings/docker.gpg echo "deb [arch=$(dpkg --print-architecture) \ signed-by=/etc/apt/keyrings/docker.gpg] \ https://download.docker.com/linux/debian \ $(lsb_release -cs) stable" \ | tee /etc/apt/sources.list.d/docker.list > /dev/null # Instalar Docker apt update apt install -y docker-ce docker-ce-cli containerd.io \ docker-buildx-plugin docker-compose-plugin # Verificar instalación docker --version docker compose version
Si usas Ubuntu en lugar de Debian, cambia debian por ubuntu en la URL del repositorio de Docker.
Configuración de Navidrome
Primer acceso
Abre tu navegador → http://IP:4533
Crea tu cuenta de administrador
Navidrome escaneará /music automáticamente
Variables de entorno avanzadas
| Variable | Descripción |
|---|---|
| ND_SCANSCHEDULE | Frecuencia de escaneo (15m, 1h, @every 30m) |
| ND_ENABLETRANSCODING | Transcodificación al vuelo (true/false) |
| ND_TRANSCODINGCACHESIZE | Caché de transcodificación (ej: 1GB) |
| ND_ENABLESHARING | Permitir compartir enlaces públicos |
| ND_ENABLEDOWNLOADS | Permitir descargas desde la interfaz |
| ND_DEFAULTLANGUAGE | Idioma por defecto (es, en, pt) |
| ND_ENABLESTARRATING | Habilitar valoraciones con estrellas |
| ND_LASTFM_APIKEY | API key de Last.fm para scrobbling |
| ND_SPOTIFY_ID / SECRET | Para obtener carátulas desde Spotify |
Usuarios adicionales
Desde la interfaz web → Ajustes → Usuarios. Cada usuario tiene sus propias listas, favoritos e historial independiente.
Instalación de spotDL
spotDL es una herramienta de código abierto que busca canciones en YouTube a partir de metadatos de Spotify. Descarga todo con carátulas, artista, álbum, letras y género.
Instalación
# Instalar Python y dependencias apt install -y python3 python3-pip ffmpeg # Instalar spotDL pip3 install spotdl --break-system-packages # Verificar spotdl --version
Uso básico
# Descargar una canción spotdl download "https://open.spotify.com/track/ID_CANCION" # Descargar playlist completa con estructura de carpetas spotdl download "https://open.spotify.com/playlist/ID_PLAYLIST" \ --output "/mnt/music/{artist}/{album}/{title}.{output-ext}"
Función SYNC (clave para automatización)
La función sync compara el estado actual de una playlist con lo descargado: baja las nuevas y elimina las que ya no están.
# Primera vez: crear archivo de sincronización spotdl sync "URL_PLAYLIST" \ --save-file "/opt/spotdl/nombre.sync.spotdl" \ --output "/mnt/music/Playlists/Nombre/{title}.{output-ext}" # Ejecuciones posteriores: solo actualizar spotdl sync "/opt/spotdl/nombre.sync.spotdl"
No re-descarga toda la playlist cada vez. Solo baja canciones nuevas y elimina las que se quitaron. Perfecto para playlists que cambian semanalmente como los Top 50.
Automatización con Cron Jobs
Crear directorios de trabajo
mkdir -p /opt/spotdl mkdir -p /mnt/music/Playlists mkdir -p /var/log/spotdl
Inicializar sincronizaciones
Ejecuta una vez para crear los archivos .sync.spotdl:
# Top 50 Global spotdl sync "https://open.spotify.com/playlist/37i9dQZEVXbMDoHDwVN2tF" \ --save-file "/opt/spotdl/top50-global.sync.spotdl" \ --output "/mnt/music/Playlists/Top50-Global/{title}.{output-ext}" # Top 50 USA spotdl sync "https://open.spotify.com/playlist/37i9dQZEVXbLRQDuF5jeBp" \ --save-file "/opt/spotdl/top50-usa.sync.spotdl" \ --output "/mnt/music/Playlists/Top50-USA/{title}.{output-ext}" # Top 50 España spotdl sync "https://open.spotify.com/playlist/37i9dQZEVXbNFJfN1Vw8d9" \ --save-file "/opt/spotdl/top50-spain.sync.spotdl" \ --output "/mnt/music/Playlists/Top50-Spain/{title}.{output-ext}" # Top 50 México spotdl sync "https://open.spotify.com/playlist/37i9dQZEVXbO3qyFxbkOE1" \ --save-file "/opt/spotdl/top50-mexico.sync.spotdl" \ --output "/mnt/music/Playlists/Top50-Mexico/{title}.{output-ext}"
Configurar Cron
# Sincronizar playlists Top 50 cada día a las 3 AM 0 3 * * * /usr/local/bin/spotdl sync /opt/spotdl/top50-global.sync.spotdl >> /var/log/spotdl/global.log 2>&1 15 3 * * * /usr/local/bin/spotdl sync /opt/spotdl/top50-usa.sync.spotdl >> /var/log/spotdl/usa.log 2>&1 30 3 * * * /usr/local/bin/spotdl sync /opt/spotdl/top50-spain.sync.spotdl >> /var/log/spotdl/spain.log 2>&1 45 3 * * * /usr/local/bin/spotdl sync /opt/spotdl/top50-mexico.sync.spotdl >> /var/log/spotdl/mexico.log 2>&1
Ejecutar todo a la vez puede saturar tu conexión y provocar errores de throttling en YouTube. Escalonándolas se evitan bloqueos.
URLs Oficiales de Playlists Top 50
Estas son las playlists oficiales mantenidas por Spotify, actualizadas diariamente. Usa estas URLs con spotDL:
| País / Región | URL de Spotify |
|---|---|
| 🌍 Global | https://open.spotify.com/playlist/37i9dQZEVXbMDoHDwVN2tF |
| 🇺🇸 Estados Unidos | https://open.spotify.com/playlist/37i9dQZEVXbLRQDuF5jeBp |
| 🇪🇸 España | https://open.spotify.com/playlist/37i9dQZEVXbNFJfN1Vw8d9 |
| 🇲🇽 México | https://open.spotify.com/playlist/37i9dQZEVXbO3qyFxbkOE1 |
| 🇦🇷 Argentina | https://open.spotify.com/playlist/37i9dQZEVXbMMy2roB9myp |
| 🇨🇴 Colombia | https://open.spotify.com/playlist/37i9dQZEVXbOa2lmxNORXQ |
| 🇬🇧 Reino Unido | https://open.spotify.com/playlist/37i9dQZEVXbLnolsZ8PSNw |
| 🇫🇷 Francia | https://open.spotify.com/playlist/37i9dQZEVXbIPWwFssbupI |
| 🇩🇪 Alemania | https://open.spotify.com/playlist/37i9dQZEVXbJiZcmkrIHGU |
| 🇧🇷 Brasil | https://open.spotify.com/playlist/37i9dQZEVXbMXbN3EUUhlg |
| 🇮🇹 Italia | https://open.spotify.com/playlist/37i9dQZEVXbIQnj7RRhdSX |
| 🇨🇱 Chile | https://open.spotify.com/playlist/37i9dQZEVXbL0GavIqMTeb |
Todas las playlists oficiales siguen el patrón 37i9dQZEVXb + identificador del país.
Script Maestro de Sincronización
En lugar de múltiples entradas en cron, usa un solo script que gestione todas las playlists con pausas entre descargas:
#!/bin/bash # Script maestro de sincronización de playlists LOG_DIR="/var/log/spotdl" SYNC_DIR="/opt/spotdl" MUSIC_DIR="/mnt/music/Playlists" DATE=$(date '+%Y-%m-%d %H:%M:%S') echo "=== Inicio sincronización: $DATE ===" # Definir playlists declare -A PLAYLISTS=( ["Top50-Global"]="37i9dQZEVXbMDoHDwVN2tF" ["Top50-USA"]="37i9dQZEVXbLRQDuF5jeBp" ["Top50-Spain"]="37i9dQZEVXbNFJfN1Vw8d9" ["Top50-Mexico"]="37i9dQZEVXbO3qyFxbkOE1" ["Top50-Argentina"]="37i9dQZEVXbMMy2roB9myp" ["Top50-Colombia"]="37i9dQZEVXbOa2lmxNORXQ" ) for NAME in "${!PLAYLISTS[@]}"; do PLAYLIST_ID="${PLAYLISTS[$NAME]}" SYNC_FILE="$SYNC_DIR/$NAME.sync.spotdl" OUTPUT_DIR="$MUSIC_DIR/$NAME" URL="https://open.spotify.com/playlist/$PLAYLIST_ID" echo "--- Sincronizando: $NAME ---" if [ ! -f "$SYNC_FILE" ]; then spotdl sync "$URL" \ --save-file "$SYNC_FILE" \ --output "$OUTPUT_DIR/{title}.{output-ext}" else spotdl sync "$SYNC_FILE" fi # Pausa entre playlists para evitar throttling sleep 120 done echo "=== Sincronización completada ==="
# Dar permisos y agregar a cron chmod +x /opt/spotdl/sync-all.sh # Cron simplificado (una entrada) crontab -e 0 3 * * * /opt/spotdl/sync-all.sh >> /var/log/spotdl/sync.log 2>&1
spotDL descarga audio de YouTube, no de Spotify. Asegúrate de respetar las leyes de copyright de tu país. Este sistema está pensado para uso personal.
Acceso Remoto con Tailscale
Tailscale crea una red VPN mesh que te permite acceder a tu servidor desde cualquier lugar sin abrir puertos en tu router.
Instalar Tailscale
curl -fsSL https://tailscale.com/install.sh | sh tailscale up
Acceso desde fuera
Instala Tailscale en tu teléfono (App Store / Play Store)
Inicia sesión con la misma cuenta
Accede a Navidrome: http://100.x.y.z:4533
HTTPS automático con Tailscale Serve
tailscale serve https / http://localhost:4533 tailscale serve status # Tu URL será algo como: # https://navidrome.tu-tailnet.ts.net
Clientes Compatibles
Navidrome soporta la API Subsonic, haciéndolo compatible con más de 40 aplicaciones.
Apps Móviles
Symfonium
play:Sub
Amperfy
Substreamer
DSub
Tempo
Apps de Escritorio
Interfaz Web
Feishin
Sublime Music
Configurar un cliente
Servidor: http://IP:4533 (o tu URL de Tailscale)
Usuario: tu usuario de Navidrome
Contraseña: tu contraseña de Navidrome
La mayoría de clientes permiten descargar música para escucha offline.
Mantenimiento y Copias de Seguridad
Actualizar Navidrome
cd /opt/navidrome docker compose pull docker compose up -d
Backup
# Base de datos y config de Navidrome tar -czf /root/backup-navidrome-$(date +%Y%m%d).tar.gz /opt/navidrome/data/ # Archivos de sincronización de spotDL tar -czf /root/backup-spotdl-$(date +%Y%m%d).tar.gz /opt/spotdl/
Limpieza y monitoreo
# Limpiar logs viejos (agregar a cron semanal) 0 0 * * 0 find /var/log/spotdl/ -name '*.log' -mtime +30 -delete # Ver espacio usado por playlists du -sh /mnt/music/Playlists/* # Espacio total df -h /mnt/music
Cada playlist Top 50 ocupa aprox. 200-400 MB (50 canciones MP3). Con 6 países: ~1.5-2.5 GB renovándose semanalmente.
Solución de Problemas Comunes
| Problema | Solución |
|---|---|
| No aparece música nueva | Espera al escaneo (15 min) o fuerza desde Ajustes → Escanear |
| spotDL error 403 | YouTube limita tu IP. Espera unas horas o usa --audio youtube-music |
| Docker no arranca en LXC | Verifica nesting: pct set 200 --features nesting=1 |
| Permisos incorrectos | chown -R 1000:1000 /mnt/music o ajusta user en compose |
| Sin carátulas | spotDL las incluye automáticamente. Navidrome también busca online |
| Sin transcodificación | Instala ffmpeg: apt install ffmpeg |
| Cliente no conecta | Verifica puerto 4533 accesible. Con Tailscale: misma tailnet |
| Canciones equivocadas | Usa --only-verified-results para mayor precisión |
Comandos de diagnóstico
# Logs de Navidrome en tiempo real docker compose -f /opt/navidrome/docker-compose.yml logs -f # Estado del contenedor docker ps # Probar spotDL manualmente spotdl download "nombre de cancion" --output /tmp/test/ # Último log de sincronización tail -50 /var/log/spotdl/sync.log