← Blog

Castopod selbst hosten, um einen Podcast zu veröffentlichen

Railyard

6. September 2026 · 6 Min. Lesezeit

Folge dem auf deinem eigenen Server. Kostenlos starten, keine Karte nötig

Die meisten Podcast-Hoster vermieten dir einen RSS-Feed: Hörst du auf zu zahlen, können deine Episoden, deine Analytics und deine eigene Feed-URL mit dem Account verschwinden. Castopod ist ein Open-Source-Podcast-Host auf Basis von CodeIgniter, der dir denselben Publishing-Workflow, echte Hörer-Analytics und Podcasting-2.0-Features wie Transkripte und Kapitel bietet, wobei der Feed auf deiner eigenen Domain liegt statt bei einem Anbieter. Am Ende dieser Anleitung läuft er mit MariaDB und Redis hinter HTTPS, deine erste Show ist veröffentlicht, und ein Backup deckt tatsächlich die Audiodateien ab, nicht nur die Datenbank.

Was du brauchst

  • Einen Server mit Docker und dem Compose-Plugin. Ein Hetzner CX23 (2 vCPU, 4 GB RAM, 40 GB NVMe, 5,99 €/Monat exkl. MwSt.) betreibt Castopod komfortabel; plane über die Standard-40-GB hinaus mehr Speicherplatz ein, sobald du mehr als eine Handvoll Episoden hostest, Audiodateien summieren sich schneller als bei den meisten selbst gehosteten Apps.
  • Einen Domainnamen, auf den du einen A-Record zeigen lassen kannst. Castopod braucht HTTPS, um korrekt mit dem Fediverse zu föderieren (Podcast-Follows und -Kommentare), das ist also nicht optional, wie es bei einem internen Tool sein könnte.
  • SSH-Zugang zum Server.

Schritt 1: DNS setzen und die Firewall öffnen

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

Lege einen A-Record für deine Domain an, der auf die öffentliche IP des Servers zeigt, und gib ihm vor Schritt 5 ein paar Minuten Zeit.

Schritt 2: Die Secrets generieren

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 ist der Wert, mit dem Castopod die IP-Adressen der Hörer hasht, bevor ein Download gezählt wird, was dir echte aggregierte Analytics liefert, ohne rohe IPs zu speichern; er muss über die gesamte Lebensdauer der Instanz gleich bleiben, eine Änderung setzt zurück, wie wiederkehrende Hörer dedupliziert werden.

Schritt 3: Die Compose-Datei schreiben

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:

Diese Anleitung pinnt 1.15.5, zum Zeitpunkt der Erstellung die aktuelle stabile Version, und mariadb:12.1, die Datenbank-Engine, die Castopods eigene Dokumentation anstelle von Postgres dokumentiert. security_opt: no-new-privileges:false ist erforderlich, nicht optional: Castopods Image läuft als Nicht-Root-Benutzer www-data und muss beim eigenen Boot /run selbst chownen, was der Standard-no-new-privileges-Schutz des Kernels blockiert und den Container mit s6-overlay-suexec: child failed with exit code 100 fatal abbrechen lässt, wenn die Option aktiv bleibt. Castopods eigenes Entrypoint-Skript, keine Konfigurationsdatei, die du schreibst, generiert bei jedem Boot intern die echte .env aus den hier gesetzten CP_*-Variablen.

Prüfe, ob die Datei parst:

docker compose config

Schritt 4: Caddy hinzufügen und den Stack starten

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

Du solltest jeden Dienst als Up sehen (db als healthy) und curl sollte HTTP/2 200 zurückgeben.

Schritt 5: Deinen Account und die erste Podcast anlegen

Öffne https://podcast.yourdomain.com/cp-install und folge dem Setup-Assistenten, um den ersten Administrator-Account anzulegen, nichts ist vorab befüllt. Lege im Admin-Dashboard einen Podcast an, fülle seine Metadaten aus und veröffentliche deine erste Episode, indem du eine Audiodatei hochlädst; Castopod transkodiert und erzeugt den RSS-Eintrag automatisch. Dein Feed wird unter https://podcast.yourdomain.com/@<your-podcast-handle>/feed.xml veröffentlicht, der URL, die du bei Apple Podcasts, Spotify und jedem anderen Verzeichnis einreichst.

Schritt 6: Datenbank und Media-Volume sichern

Hier zählen sowohl die Audiodateien als auch eine wachsende MariaDB-Datenbank, und das Media-Volume ist meist das größere:

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 -

Führe es einmal manuell aus und prüfe, dass ls -lh backups eine datierte Datei zeigt. Der Datenbank-Dump allein deckt nicht die hochgeladenen Audiodateien in castopod_media ab; sichere die separat mit welchem Full-Disk-Snapshot-Tooling dein Server-Anbieter auch bietet, oder per periodischem rsync auf eine andere Maschine, denn ein tar von aktiv ausgelieferten Mediendateien während laufende Episoden live sind, sollte man besser für verkehrsarme Stunden einplanen.

Schritt 7: Upgrade

docker compose pull castopod
docker compose up -d castopod

Castopod führt seine eigenen Datenbank-Migrationen automatisch beim Boot aus, wenn sich die Image-Version ändert. Prüfe die Release-Notes der Version, zu der du wechselst, und bestätige, dass docker compose logs castopod einen saubereren Start ohne Migrationsfehler zeigt, bevor du das Upgrade als abgeschlossen betrachtest.

Die Abkürzung: mit Railyard

Alles oben, MariaDB und Redis automatisch verdrahtet, der no-new-privileges-Fix, den Castopods eigenes Image zum saubereren Booten braucht, ein dediziertes Volume für hochgeladenes Audio, ist auch das, was Railyards Castopod-Stack-Vorlage für dich einrichtet. Verbinde einen Server, wähle dann Castopod im Vorlagenkatalog: app.railyard.run/deploy?stack=castopod. HTTPS wird genauso gehandhabt wie in Schritt 4 von Hand, was auch Castopods eigene Anforderung für die Fediverse-Föderation erfüllt.

Siehe Deploy per Knopfdruck und Datenbanken und Backups für mehr darüber, wie Vorlagen und persistente Daten auf der Plattform generell funktionieren.

Troubleshooting

Der Container beendet sich mit s6-overlay-suexec: child failed with exit code 100. no-new-privileges ist noch aktiv, prüfe, ob security_opt in Schritt 3 wirklich speziell für den Dienst castopod auf no-new-privileges:false gesetzt ist, das ist die eine Hardening-Vorgabe, die für dieses Image gelockert werden muss.

MariaDB loggt “Host X is not allowed to connect” nur beim ersten Boot. Das tritt auf, wenn die CPU des Servers genau dann stark ausgelastet ist, wenn MariaDB die initialen Nutzer und Grants anlegt, und diesen Prozess unterbricht. Stoppe den Stack, entferne das Volume castopod_db_data, und führe docker compose up -d zu einem ruhigeren Zeitpunkt erneut aus; es gibt noch keine echten Daten zu verlieren, wenn das bei einer wirklich frischen Installation passiert.

Hochgeladenes Audio schlägt mit einem Berechtigungsfehler fehl. Prüfe die Eigentümerschaft im Container mit docker compose exec castopod ls -la /app/public/media; das tritt am häufigsten nach dem Wiederherstellen eines Backups als Root auf, während der Container als www-data läuft.

HTTPS wird nicht ausgestellt. docker compose logs caddy mit wiederholten ACME-Fehlern bedeutet fast immer, dass das DNS aus Schritt 1 noch nicht propagiert ist oder auf die falsche IP zeigt.

Die Festplatte füllt sich schneller als erwartet. Audiodateien sammeln sich über Episoden hinweg schnell an; du -sh castopod_media (oder der entsprechende docker volume inspect-Pfad) zeigt, was tatsächlich Speicherplatz verbraucht, und die Festplatte des Servers rechtzeitig zu vergrößern ist einfacher, als ein volles Volume unter Druck zu migrieren.

FAQ

Braucht Castopod einen SMTP-Anbieter, wie manche andere selbst gehostete Apps? Nicht, um einen Podcast zu veröffentlichen oder für die Kern-Moderation; SMTP wird nur gebraucht, wenn du optionale E-Mail-Benachrichtigungen aktivierst, was eine viel leichtere Anforderung ist als bei Apps, bei denen die Account-Bestätigung selbst davon abhängt.

Kann ich den RSS-Feed eines existierenden Podcasts zu Castopod migrieren? Ja, Castopod unterstützt das Importieren von Episoden aus einer existierenden Feed-URL während der Podcast-Erstellung, was die Episodenhistorie erhält, statt bei null zu starten.

Ist die Fediverse-Integration verpflichtend? Nein, Podcasts funktionieren auch ohne sie als normaler RSS-Feed und Web-Player; Föderation (Follows und Kommentare von Mastodon-artigen Apps) ist ein zusätzliches Feature darauf, keine Voraussetzung zum Veröffentlichen.

Wie funktionieren echte Analytics, ohne Hörer individuell zu tracken? Castopod implementiert die Podcasting-2.0-Analytics-Spezifikation und hasht identifizierende Daten wie IP-Adressen mit dem Salt aus Schritt 2, bevor ein Download gezählt wird, sodass du echte Download- und geografische Zahlen bekommst, ohne irgendetwas zu speichern, das einen einzelnen Hörer identifiziert.

Wie viel Speicherplatzwachstum ist für eine aktive Show realistisch? Eine wöchentliche einstündige Episode mit angemessener Bitrate sind einige Dutzend Megabyte pro Episode; das summiert sich bei den meisten Shows langsam, aber Video oder sehr hohe Audio-Bitraten ändern diese Rechnung schnell, prüfe die tatsächlichen Dateigrößen gegen den Server aus “Was du brauchst”, bevor du davon ausgehst, dass die Standard-40-GB für ein Jahr ausreichen.

Sobald MariaDB, Redis und HTTPS stehen, ist das Veröffentlichen einer Episode dieselben paar Klicks, die es auf einer gehosteten Plattform wäre, die eigentliche laufende Arbeit ist die Backup-Routine aus Schritt 6 und ein Auge auf den Speicherplatz, während die Show wächst.

Warum Leute sich dafür Railyard entscheiden

  • Dein eigenes Cloud-Konto. Deploye auf DigitalOcean, Hetzner, Vultr, AWS, OVHcloud oder jedem Linux-Server per SSH, direkt von deinem Anbieter abgerechnet, ohne Aufschlag.
  • Ein fester Preis pro Team. Free ist für immer kostenlos: ein Server plus ein Datenbankserver, drei Apps, keine Karte. Pro kostet 19 $ im Monat für bis zu fünf Server und unbegrenzte Apps. Team kostet 49 $ im Monat mit unbegrenzten Servern. Keine Kosten pro App, pro Deployment, pro Sitz oder pro Gigabyte.
  • Templates mit einem Klick. Deploye Open-Source-Apps, wie Datenbanken, Analytics und Dev-Tools, mit einem Klick auf deinem eigenen Server.
  • Verwaltete Datenbanken. Postgres, MySQL und Redis mit geplanten, wiederherstellungsgeprüften Backups und Point-in-Time-Recovery.
  • Push-to-Deploy. Deploye von GitHub, GitLab oder der CLI, mit automatischem HTTPS und Releases ohne Ausfallzeit.

Castopod mit einem Klick deployen

Wähle Castopod im Railyard-Vorlagenkatalog und bekomme MariaDB und Redis bereits für deine Show verdrahtet.

Kostenloser Plan, keine Kreditkarte, und 14 Tage Pro für jedes neue Team. Ein fester Preis pro Team.