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
- Open
http://YOUR_SERVER_IP:8040in your browser - Create the first admin account through the web interface
- Start searching for podcasts using the built-in search (powered by iTunes and Podcast Index)
- 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
| Variable | Default | Description |
|---|---|---|
HOSTNAME | http://localhost:8040 | Public URL for RSS sharing and API callbacks. Set to your domain if using remote access. |
SEARCH_API_URL | Pinepods hosted search | Podcast search API endpoint. Uses the Pinepods project’s hosted instance by default. |
DB_TYPE | — | postgresql or mariadb. PostgreSQL recommended. |
VALKEY_HOST | — | Hostname of the Valkey/Redis cache service. |
DEFAULT_LANGUAGE | en | Interface language code. |
DEBUG_MODE | false | Enable 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
| Volume | Contents | Priority |
|---|---|---|
pinepods-db | PostgreSQL database (subscriptions, listen history, users) | Critical |
pinepods-downloads | Downloaded podcast episodes | Replaceable (can re-download) |
pinepods-backups | Built-in backup files | Important |
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
| Resource | Value |
|---|---|
| RAM | ~300 MB (Pinepods) + ~200 MB (PostgreSQL) + ~50 MB (Valkey) |
| CPU | Low — mostly idle except during podcast search and downloads |
| Disk | 500 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.
Related
Get self-hosting tips in your inbox
Get the Docker Compose configs, hardware picks, and setup shortcuts we don't put in articles. Weekly. No spam.
Comments