How to Self-Host Pinepods with Docker Compose

What Is Pinepods?

Pinepods is a self-hosted podcast management server with multi-user support, podcast discovery, episode downloads, and native mobile apps. It replaces cloud podcast apps like Pocket Casts, Apple Podcasts, and Overcast by giving you full control over your listening history, subscriptions, and downloaded episodes. Pinepods also includes a gpodder-compatible API, so you can sync subscriptions with external podcast clients.

Official site: pinepods.online

Prerequisites

  • A Linux server (Ubuntu 22.04+ recommended)
  • Docker and Docker Compose installed (guide)
  • 2 GB of free RAM (PostgreSQL + Valkey + Pinepods)
  • 10 GB of disk space minimum (more if downloading episodes)
  • A domain name (optional, for remote access)

Docker Compose Configuration

Create a directory for Pinepods and a docker-compose.yml file:

mkdir -p /opt/pinepods && cd /opt/pinepods
services:
  db:
    image: postgres:17-alpine
    container_name: pinepods-db
    environment:
      POSTGRES_DB: pinepods_database
      POSTGRES_USER: pinepods
      # CHANGE THIS — use a strong random password
      POSTGRES_PASSWORD: changeme_strong_password_here
      PGDATA: /var/lib/postgresql/data/pgdata
    volumes:
      - pinepods-db:/var/lib/postgresql/data
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U pinepods -d pinepods_database"]
      interval: 10s
      timeout: 5s
      retries: 5

  valkey:
    image: valkey/valkey:8-alpine
    container_name: pinepods-valkey
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "valkey-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5

  pinepods:
    image: madeofpendletonwool/pinepods:0.8.2
    container_name: pinepods
    ports:
      - "8040:8040"
    environment:
      # Server URL — set to your public URL for RSS sharing and remote access
      HOSTNAME: "http://localhost:8040"
      # Podcast search APIs (hosted by Pinepods project)
      SEARCH_API_URL: "https://search.pinepods.online/api/search"
      PEOPLE_API_URL: "https://people.pinepods.online"
      # Database connection
      DB_TYPE: postgresql
      DB_HOST: db
      DB_PORT: "5432"
      DB_USER: pinepods
      # Must match POSTGRES_PASSWORD above
      DB_PASSWORD: changeme_strong_password_here
      DB_NAME: pinepods_database
      # Valkey (Redis-compatible cache)
      VALKEY_HOST: valkey
      VALKEY_PORT: "6379"
      # User and timezone
      PUID: "1000"
      PGID: "1000"
      TZ: "America/New_York"
      # Language
      DEFAULT_LANGUAGE: "en"
      # Set to true for verbose logging
      DEBUG_MODE: "false"
    volumes:
      - pinepods-downloads:/opt/pinepods/downloads
      - pinepods-backups:/opt/pinepods/backups
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
      valkey:
        condition: service_healthy

volumes:
  pinepods-db:
  pinepods-downloads:
  pinepods-backups:

Start the stack:

docker compose up -d

Initial Setup

  1. Open http://YOUR_SERVER_IP:8040 in your browser
  2. Create the first admin account through the web interface
  3. Start searching for podcasts using the built-in search (powered by iTunes and Podcast Index)
  4. Subscribe to your first podcast and episodes will begin syncing

The first admin account has full management privileges. Additional users can be created from the admin panel.

Configuration

Key Environment Variables

VariableDefaultDescription
HOSTNAMEhttp://localhost:8040Public URL for RSS sharing and API callbacks. Set to your domain if using remote access.
SEARCH_API_URLPinepods hosted searchPodcast search API endpoint. Uses the Pinepods project’s hosted instance by default.
DB_TYPEpostgresql or mariadb. PostgreSQL recommended.
VALKEY_HOSTHostname of the Valkey/Redis cache service.
DEFAULT_LANGUAGEenInterface language code.
DEBUG_MODEfalseEnable verbose logging for troubleshooting.

Setting Your Public URL

If you are accessing Pinepods from outside your local network, update HOSTNAME to your public URL:

environment:
  HOSTNAME: "https://pinepods.example.com"

This is required for:

  • RSS feed sharing links
  • OAuth callbacks (if using OIDC authentication)
  • Mobile app connectivity

Using MariaDB Instead of PostgreSQL

Replace the db service:

services:
  db:
    image: mariadb:11-jammy
    container_name: pinepods-db
    environment:
      MYSQL_ROOT_PASSWORD: changeme_root_password
      MYSQL_DATABASE: pinepods_database
      MYSQL_USER: pinepods
      MYSQL_PASSWORD: changeme_strong_password_here
    volumes:
      - pinepods-db:/var/lib/mysql
    restart: unless-stopped

And update the Pinepods environment:

environment:
  DB_TYPE: mariadb
  DB_PORT: "3306"

Advanced Configuration (Optional)

OIDC Authentication

Pinepods supports OpenID Connect for single sign-on with providers like Authentik, Keycloak, or Authelia. Configure via environment variables:

environment:
  OIDC_ENABLED: "true"
  OIDC_PROVIDER_URL: "https://auth.example.com"
  OIDC_CLIENT_ID: "pinepods"
  OIDC_CLIENT_SECRET: "your-client-secret"

Self-Hosted Search API

If you prefer not to use the Pinepods project’s hosted search API, you can deploy your own instance. The search API source is available in the Pinepods GitHub repository.

Reverse Proxy

Caddy

pinepods.example.com {
    reverse_proxy localhost:8040
}

Nginx

server {
    listen 443 ssl http2;
    server_name pinepods.example.com;

    ssl_certificate /etc/letsencrypt/live/pinepods.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/pinepods.example.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8040;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

For full reverse proxy setup, see Reverse Proxy Explained.

Backup

Critical Data

VolumeContentsPriority
pinepods-dbPostgreSQL database (subscriptions, listen history, users)Critical
pinepods-downloadsDownloaded podcast episodesReplaceable (can re-download)
pinepods-backupsBuilt-in backup filesImportant

Database Backup

docker exec pinepods-db pg_dump -U pinepods pinepods_database > pinepods_backup_$(date +%Y%m%d).sql

Restore

docker exec -i pinepods-db psql -U pinepods pinepods_database < pinepods_backup_20260304.sql

For a full backup strategy, see Backup Strategy.

Troubleshooting

Pinepods fails to start with database connection error

Symptom: Container exits with “connection refused” or “database does not exist”

Fix: Ensure the PostgreSQL container is fully started before Pinepods. The health check in the Docker Compose above handles this. If you removed depends_on, add it back:

depends_on:
  db:
    condition: service_healthy

Podcast search returns no results

Symptom: Searching for podcasts shows nothing.

Fix: Verify SEARCH_API_URL is reachable from the container:

docker exec pinepods curl -s https://search.pinepods.online/api/search | head -20

If it fails, your server may not have outbound HTTPS access or DNS resolution may be broken inside Docker.

Episodes not downloading

Symptom: Download button does nothing or episodes show as queued indefinitely.

Fix: Check that the downloads volume has write permissions:

docker exec pinepods ls -la /opt/pinepods/downloads/

Ensure PUID/PGID match the volume owner.

Mobile app cannot connect

Symptom: iOS or Android app says “Unable to connect to server.”

Fix: Set HOSTNAME to your externally reachable URL (not localhost). The mobile app uses this URL to connect.

Resource Requirements

ResourceValue
RAM~300 MB (Pinepods) + ~200 MB (PostgreSQL) + ~50 MB (Valkey)
CPULow — mostly idle except during podcast search and downloads
Disk500 MB for application + episode downloads (variable)

Verdict

Pinepods is the most full-featured self-hosted podcast server available. Multi-user support, gpodder compatibility, native mobile apps, and built-in podcast search make it a genuine replacement for cloud podcast services. The three-container setup (app + database + cache) is heavier than single-binary alternatives like Podgrab, but the feature set justifies it. If you want a shared podcast server for your household or a privacy-respecting alternative to Pocket Casts, Pinepods is the right tool.

Frequently Asked Questions

Does Pinepods support podcast subscriptions from OPML files?

Yes. You can import OPML files from any podcast client through the Pinepods web interface. This makes migrating from Apple Podcasts, Pocket Casts, or other services straightforward.

Can I use Pinepods with AntennaPod or other gpodder-compatible apps?

Yes. Pinepods includes a built-in gpodder API server, so any podcast client that supports gpodder sync (AntennaPod, gPodder, Kasts) can sync subscriptions and listen history with your Pinepods instance.

How much disk space do downloaded episodes use?

A typical podcast episode is 30-80 MB. If you subscribe to 20 podcasts and download the last 10 episodes of each, expect roughly 6-16 GB. Configure download retention policies in the Pinepods settings to manage disk usage.

How does Pinepods compare to Podgrab?

Podgrab is a simpler, single-binary podcast downloader focused on automated episode downloading. Pinepods is a full podcast management server with multi-user support, a web player, native mobile apps, podcast search, and gpodder sync. Choose Podgrab if you just want automatic downloads. Choose Pinepods if you want a complete podcast platform that replaces cloud apps like Pocket Casts.

Does Pinepods have mobile apps?

Yes. Pinepods offers native iOS and Android apps that connect to your self-hosted instance. The apps support streaming, offline downloads, and playback synchronization. Set the HOSTNAME environment variable to your externally reachable URL so the apps can connect.

Can multiple users share a Pinepods instance?

Yes. Pinepods supports multi-user accounts with individual subscription lists, listen history, and downloaded episodes. Each user gets their own isolated experience while sharing the same server infrastructure. This makes it ideal for households or small groups.

Comments