← Blog

Auto-hospedar Castopod para publicar un podcast

Railyard

6 de septiembre de 2026 · 7 min de lectura

Sigue esto en tu propio servidor. Empieza gratis, sin tarjeta

La mayoría de los servicios de podcast te rentan un feed RSS: dejas de pagar y tus episodios, tus estadísticas y hasta la URL de tu propio feed pueden desaparecer junto con la cuenta. Castopod es un servicio de podcast de código abierto, construido sobre CodeIgniter, que te da el mismo flujo de publicación, estadísticas reales de oyentes, y funciones de Podcasting 2.0 como transcripciones y capítulos, con el feed viviendo en tu propio dominio en lugar del de un proveedor. Al final de esta guía lo tendrás corriendo con MariaDB y Redis detrás de HTTPS, tu primer programa publicado, y un respaldo que realmente cubre los archivos de audio, no solo la base de datos.

Lo que necesitas

  • Un servidor con Docker y el plugin de Compose. Un Hetzner CX23 (2 vCPU, 4 GB de RAM, 40 GB NVMe, 5,99 €/mes sin IVA) corre Castopod cómodamente; planea disco real más allá de los 40 GB por defecto en cuanto hospedes más que un puñado de episodios, los archivos de audio se acumulan más rápido que en la mayoría de las apps auto-hospedadas.
  • Un nombre de dominio al que puedas apuntar un registro A. Castopod requiere HTTPS para federar correctamente con el fediverso (seguidores y comentarios de podcasts), así que esto no es opcional de la forma en que podría serlo para una herramienta interna.
  • Acceso SSH al servidor.

Paso 1: apuntar el DNS y abrir el firewall

ufw allow OpenSSH
ufw allow 80
ufw allow 443
ufw --force enable

Crea un registro A para tu dominio apuntando a la IP pública del servidor, y dale unos minutos antes del Paso 5.

Paso 2: generar los secretos

openssl rand -hex 24   # MYSQL_ROOT_PASSWORD
openssl rand -hex 24   # MYSQL_PASSWORD
openssl rand -hex 24   # REDIS_PASSWORD
openssl rand -hex 16   # CP_ANALYTICS_SALT
mkdir -p /opt/castopod
cat > /opt/castopod/.env <<'EOF'
MYSQL_ROOT_PASSWORD=paste-the-first-value-here
MYSQL_PASSWORD=paste-the-second-value-here
REDIS_PASSWORD=paste-the-third-value-here
CP_ANALYTICS_SALT=paste-the-fourth-value-here
EOF
chmod 600 /opt/castopod/.env

CP_ANALYTICS_SALT es con lo que Castopod convierte en hash las direcciones IP de los oyentes antes de contar una descarga, dándote estadísticas agregadas reales sin guardar las IP crudas; tiene que mantenerse con el mismo valor durante toda la vida de la instancia, cambiarla reinicia cómo se deduplican los oyentes recurrentes.

Paso 3: escribir el archivo Compose

services:
  castopod:
    image: castopod/castopod:1.15.5
    restart: unless-stopped
    env_file: .env
    security_opt:
      - no-new-privileges:false
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started
    environment:
      CP_BASEURL: https://podcast.yourdomain.com
      CP_DATABASE_HOSTNAME: db
      CP_DATABASE_NAME: castopod
      CP_DATABASE_USERNAME: castopod
      CP_DATABASE_PASSWORD: ${MYSQL_PASSWORD}
      CP_REDIS_HOST: redis
      CP_REDIS_PASSWORD: ${REDIS_PASSWORD}
    volumes:
      - castopod_media:/app/public/media
    expose:
      - "8080"

  db:
    image: mariadb:12.1
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: castopod
      MYSQL_USER: castopod
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
    volumes:
      - castopod_db_data:/var/lib/mysql
    healthcheck:
      test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
      interval: 10s
      timeout: 5s
      retries: 10

  redis:
    image: redis:7.2.5-alpine
    restart: unless-stopped
    command: redis-server --requirepass ${REDIS_PASSWORD}
    volumes:
      - castopod_redis_data:/data

  caddy:
    image: caddy:2
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data
      - caddy_config:/config
    depends_on:
      - castopod

volumes:
  castopod_media:
  castopod_db_data:
  castopod_redis_data:
  caddy_data:
  caddy_config:

Esta guía fija 1.15.5, la versión estable vigente al momento de escribir esto, y mariadb:12.1, el motor de base de datos que documenta el propio Castopod en lugar de Postgres. security_opt: no-new-privileges:false es obligatorio, no opcional: la imagen de Castopod corre como un usuario www-data que no es root y necesita hacer chown sobre /run durante su propio arranque, algo que la protección por defecto no-new-privileges del kernel bloquea, lo que hace que el contenedor falle con s6-overlay-suexec: child failed with exit code 100 si se deja activada. El propio script de entrada de Castopod, no un archivo de configuración que tú escribas, genera su .env real internamente a partir de las variables CP_* que define esta guía, en cada arranque.

Verifica que el archivo se analiza:

docker compose config

Paso 4: agregar Caddy y arrancar la pila

podcast.yourdomain.com {
	reverse_proxy castopod:8080
}
docker compose up -d
docker compose ps
curl -I https://podcast.yourdomain.com

Deberías ver cada servicio en Up (db como healthy) y el curl devolver HTTP/2 200.

Paso 5: crear tu cuenta y tu primer podcast

Visita https://podcast.yourdomain.com/cp-install y sigue el asistente de configuración para crear la primera cuenta de administrador, nada viene pre-cargado. Desde el panel de administración, crea un podcast, completa sus metadatos, y publica tu primer episodio subiendo un archivo de audio; Castopod transcodifica y genera la entrada RSS automáticamente. Tu feed se publica en https://podcast.yourdomain.com/@<your-podcast-handle>/feed.xml, la URL para enviar a Apple Podcasts, Spotify y cualquier otro directorio.

Paso 6: respaldar la base de datos y el volumen de medios

Los archivos de audio y una base de datos MariaDB que crece importan ambos aquí, y el volumen de medios normalmente es el más grande:

cat > /opt/castopod/backup.sh <<'EOF'
#!/bin/sh
cd /opt/castopod
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
docker compose exec -T db mariadb-dump -u root -p"${MYSQL_ROOT_PASSWORD}" castopod | gzip > backups/db-$TIMESTAMP.sql.gz
find backups -mtime +14 -delete
EOF
mkdir -p /opt/castopod/backups
chmod +x /opt/castopod/backup.sh
(crontab -l 2>/dev/null; echo "0 3 * * * /opt/castopod/backup.sh") | crontab -

Ejecútalo una vez a mano y verifica que ls -lh backups muestre un archivo con fecha. El dump de la base de datos por sí solo no cubre el audio subido en castopod_media; respáldalo con cualquier herramienta de snapshot de disco completo que ofrezca tu proveedor de servidor, o un rsync periódico a otra máquina, ya que un tar de medios que se están sirviendo activamente mientras los episodios están en vivo es algo que vale la pena programar para horas de poco tráfico.

Paso 7: actualizar

docker compose pull castopod
docker compose up -d castopod

Castopod corre sus propias migraciones de base de datos automáticamente al arrancar cuando cambia la versión de la imagen. Revisa las notas de la versión a la que te mudas, y confirma que docker compose logs castopod muestre un arranque limpio sin errores de migración antes de dar por terminada la actualización.

El atajo: hazlo con Railyard

Todo lo anterior, MariaDB y Redis conectados automáticamente, el ajuste de no-new-privileges que la propia imagen de Castopod necesita para arrancar limpiamente, un volumen dedicado para el audio subido, es también lo que configura por ti la plantilla de pila Castopod de Railyard. Conecta un servidor, y luego elige Castopod en el catálogo de plantillas: app.railyard.run/deploy?stack=castopod. El HTTPS se maneja de la misma forma que lo hace a mano el Paso 4, lo cual también satisface el propio requisito de Castopod para la federación con el fediverso.

Consulta desplegar con un botón y bases de datos y copias de seguridad para ver cómo funcionan las plantillas y los datos persistentes en la plataforma de forma más general.

Solución de problemas

El contenedor se cierra con s6-overlay-suexec: child failed with exit code 100. no-new-privileges todavía está activado, revisa que security_opt del Paso 3 realmente esté definido como no-new-privileges:false específicamente en el servicio castopod, este es el único ajuste de hardening que hay que relajar para esta imagen.

MariaDB registra “Host X is not allowed to connect” solo en el primer arranque. Esto aparece si la CPU del servidor está muy cargada justo cuando MariaDB está creando sus usuarios y permisos iniciales, interrumpiendo ese proceso. Detén la pila, elimina el volumen castopod_db_data, y vuelve a correr docker compose up -d en un momento más tranquilo; no hay datos reales que perder todavía si esto pasa en una instalación genuinamente nueva.

El audio subido falla con un error de permisos. Revisa la propiedad dentro del contenedor con docker compose exec castopod ls -la /app/public/media; esto aparece más que nada después de restaurar un respaldo como root cuando el contenedor corre como www-data.

El HTTPS no se emite. Que docker compose logs caddy muestre errores de ACME repetidos casi siempre significa que el DNS del Paso 1 no se ha propagado o apunta a la IP equivocada.

El disco se llena más rápido de lo esperado. Los archivos de audio se acumulan rápido entre episodios; du -sh castopod_media (o la ruta equivalente de docker volume inspect) muestra qué está consumiendo espacio realmente, y aumentar el disco del servidor antes de quedarte sin espacio es más simple que migrar un volumen completo bajo presión.

Preguntas frecuentes

¿Castopod requiere un proveedor SMTP como otras apps auto-hospedadas? No para publicar un podcast ni para que la moderación central funcione; el SMTP solo hace falta si activas las notificaciones por correo opcionales, un requisito mucho más ligero que en apps donde la confirmación de cuenta en sí depende de él.

¿Puedo migrar el feed RSS de un podcast existente a Castopod? Sí, Castopod admite importar episodios desde una URL de feed existente durante la creación del podcast, lo cual conserva el historial de episodios en lugar de empezar de cero.

¿La integración con el fediverso es obligatoria? No, los podcasts funcionan como un feed RSS normal y un reproductor web sin ella; la federación (seguidores y comentarios desde apps al estilo Mastodon) es una función adicional encima, no un requisito para publicar.

¿Cómo funcionan las estadísticas reales sin rastrear a los oyentes individualmente? Castopod implementa la especificación de estadísticas de Podcasting 2.0, convirtiendo en hash datos identificables como direcciones IP con la sal del Paso 2 antes de contar una descarga, así que obtienes cifras reales de descargas y geografía sin guardar nada que identifique a un oyente en particular.

¿Cuál es el crecimiento de disco realista para un programa activo? Un episodio semanal de una hora a un bitrate razonable son decenas de megabytes por episodio; se acumula lento para la mayoría de los programas, pero el video o el audio de bitrate muy alto cambia esa cuenta rápidamente, compara los tamaños de archivo reales contra el servidor de “Lo que necesitas” antes de asumir que los 40 GB por defecto alcanzan para un año.

Una vez que MariaDB, Redis y el HTTPS están en su lugar, publicar un episodio son los mismos pocos clics que sería en una plataforma gestionada, el trabajo continuo real es el hábito de respaldo del Paso 6 y vigilar el espacio en disco a medida que el programa crece.

Por qué eligen Railyard para esto

  • Tu propia cuenta en la nube. Despliega en DigitalOcean, Hetzner, Vultr, AWS, OVHcloud, o cualquier servidor Linux por SSH, facturado directamente por tu proveedor, sin márgenes adicionales.
  • Un precio fijo por equipo. El plan Free es gratis para siempre: un servidor más un servidor de base de datos, tres apps, sin tarjeta. Pro cuesta $19 al mes por hasta cinco servidores y apps ilimitadas. Team cuesta $49 al mes con servidores ilimitados. Sin cargos por app, por despliegue, por asiento ni por gigabyte.
  • Plantillas de un clic. Despliega apps de código abierto, como bases de datos, analítica y herramientas de desarrollo, en tu propio servidor con un clic.
  • Bases de datos administradas. Postgres, MySQL y Redis, con copias de seguridad programadas y verificadas por restauración, y recuperación a un punto en el tiempo.
  • Despliegue con git push. Despliega desde GitHub, GitLab o la CLI, con HTTPS automático y lanzamientos sin tiempo de inactividad.

Despliega Castopod en un clic

Elige Castopod en el catálogo de plantillas de Railyard y obtén MariaDB y Redis ya conectados para tu programa.

Plan gratis, sin tarjeta, y 14 días de Pro para cada equipo nuevo. Un precio fijo por equipo.