How to Self-Host Piped with Docker Compose
What Is Piped?
Piped is a privacy-focused alternative frontend for YouTube. It proxies all requests through your server so Google never sees your IP address, strips tracking, removes ads, and integrates SponsorBlock to skip sponsor segments automatically. Piped supports user accounts, subscriptions, playlists, and watch history — all stored locally on your instance.
Unlike Invidious (which uses scraping), Piped uses YouTube’s internal API with a proxy layer for IP rotation. The result is faster video loading and better compatibility with YouTube’s frequent changes.
Prerequisites
- A Linux server (Ubuntu 22.04+ recommended)
- Docker and Docker Compose installed (guide)
- 2 GB of RAM minimum (4 GB recommended)
- A domain name with 3 subdomains configured (required for HTTPS)
- Ports 80 and 443 open
Docker Compose Configuration
Piped requires 6 services: frontend, backend, proxy, background helper, PostgreSQL, and a reverse proxy. The official deployment uses an internal Nginx router with Caddy for TLS termination.
The recommended approach uses the official Piped-Docker repository:
git clone https://github.com/TeamPiped/Piped-Docker
cd Piped-Docker
./configure-instance.sh
The script prompts for your three subdomains and generates all configuration files. If you prefer manual setup, here’s the full stack:
Create a docker-compose.yml file:
services:
piped-frontend:
image: 1337kavin/piped-frontend:latest # Piped does not publish semver tags — :latest is the only option
restart: unless-stopped
environment:
BACKEND_HOSTNAME: pipedapi.example.com
PROXY_HOSTNAME: pipedproxy.example.com
depends_on:
- piped
networks:
- piped
piped:
image: 1337kavin/piped:latest # Piped does not publish semver tags — :latest is the only option
restart: unless-stopped
volumes:
- ./config/config.properties:/app/config.properties:ro
depends_on:
- postgres
networks:
- piped
piped-proxy:
image: 1337kavin/piped-proxy:latest # Piped does not publish semver tags — :latest is the only option
restart: unless-stopped
volumes:
- piped-proxy:/app/socket
networks:
- piped
bg-helper:
image: 1337kavin/bg-helper:latest # Piped does not publish semver tags — :latest is the only option
restart: unless-stopped
networks:
- piped
postgres:
image: postgres:16-alpine
restart: unless-stopped
volumes:
- piped-db:/var/lib/postgresql/data
environment:
POSTGRES_DB: piped
POSTGRES_USER: piped
POSTGRES_PASSWORD: changeme_use_a_strong_password
healthcheck:
test: ["CMD-SHELL", "pg_isready -U piped"]
interval: 10s
timeout: 5s
retries: 5
networks:
- piped
caddy:
image: caddy:2-alpine
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./config/Caddyfile:/etc/caddy/Caddyfile:ro
- caddy-data:/data
- piped-proxy:/var/run/ytproxy
depends_on:
- piped
- piped-frontend
- piped-proxy
networks:
- piped
volumes:
piped-db:
piped-proxy:
caddy-data:
networks:
piped:
driver: bridge
Create config/config.properties for the backend:
# Public URLs — change these to your actual domains
API_URL=https://pipedapi.example.com
FRONTEND_URL=https://piped.example.com
PROXY_PART=https://pipedproxy.example.com
# Server
PORT=8080
HTTP_WORKERS=2
# Database (Hibernate)
hibernate.connection.url=jdbc:postgresql://postgres:5432/piped
hibernate.connection.username=piped
hibernate.connection.password=changeme_use_a_strong_password
# Features
DISABLE_REGISTRATION=false
FEED_RETENTION=30
DISABLE_LBRY=false
# SponsorBlock
SPONSORBLOCK_SERVERS=https://sponsor.ajay.app
Create config/Caddyfile for Caddy:
piped.example.com {
reverse_proxy piped-frontend:80
}
pipedapi.example.com {
reverse_proxy piped:8080
}
pipedproxy.example.com {
@ytproxy path /videoplayback* /api/v4/* /api/manifest/*
reverse_proxy @ytproxy unix//var/run/ytproxy/http-proxy.sock
header / {
Access-Control-Allow-Origin *
Access-Control-Allow-Methods "GET, POST, OPTIONS"
}
reverse_proxy piped-proxy:8080
}
Replace all instances of example.com with your actual domain. Create DNS A records for all three subdomains pointing to your server.
Start the stack:
docker compose up -d
Initial Setup
- Wait for Caddy to obtain SSL certificates. This takes 1-2 minutes after DNS propagates. Check with
docker compose logs caddy. - Access the frontend at
https://piped.example.com. - Create an account by clicking Register. Your account data stays on your instance — Google never sees it.
- Import YouTube subscriptions: Export your subscriptions from Google Takeout as a JSON file, then import via Piped’s settings.
Configuration
Disable Public Registration
After creating your account, disable registration to keep your instance private:
# In config/config.properties
DISABLE_REGISTRATION=true
Restart the backend: docker compose restart piped
Feed Retention
Control how long subscription feed data is kept:
# Days to retain feed items (default: 30)
FEED_RETENTION=30
Return YouTube Dislike Integration
Enable dislike counts using the Return YouTube Dislike API:
DISABLE_RYD=false
RYD_PROXY_URL=https://returnyoutubedislikeapi.com
Advanced Configuration (Optional)
IPv6 Proxy Rotation
YouTube bans IPs that make too many requests. The piped-proxy service handles basic proxying, but for high-traffic instances you’ll want IPv6 rotation. Configure your VPS with a /48 or /64 IPv6 block and set up the proxy to rotate source addresses.
Federation
Piped supports instance federation. To list your instance publicly and share subscriptions across the Piped network, see the Piped Federation documentation.
Reverse Proxy
The Docker Compose above includes Caddy for automatic HTTPS. If you’re already running a reverse proxy like Nginx Proxy Manager or Traefik, remove the Caddy service and configure your existing proxy to forward traffic to the appropriate internal services.
For Nginx Proxy Manager, create three proxy hosts pointing to the Docker network:
piped.example.com→piped-frontend:80pipedapi.example.com→piped:8080pipedproxy.example.com→piped-proxy:8080
See Reverse Proxy Setup for detailed instructions.
Backup
Back up the PostgreSQL database volume. This contains all user accounts, subscriptions, and playlists:
docker compose exec postgres pg_dump -U piped piped > piped-backup.sql
Restore:
cat piped-backup.sql | docker compose exec -T postgres psql -U piped piped
See Backup Strategy for automated backup approaches.
Troubleshooting
Videos Won’t Load (PoToken Errors)
Symptom: “Could not get stream” or signatureTimestamp errors.
Fix: Ensure the bg-helper service is running. This service generates proof-of-origin tokens that YouTube requires. Check: docker compose logs bg-helper
SSL Certificate Errors
Symptom: Caddy logs show “ACME challenge failed” or similar.
Fix: Ensure all three DNS A records are pointing to your server’s IP and have propagated (use dig piped.example.com). Caddy cannot obtain certificates until DNS is configured correctly.
YouTube IP Ban (Slow or Failing Playback)
Symptom: Videos buffer endlessly or fail intermittently. Fix: Your server’s IP is being rate-limited by YouTube. Consider IPv6 rotation or using a residential proxy. Single-IP instances will eventually get throttled under heavy use.
Database Connection Refused
Symptom: Backend logs show “Connection refused” to PostgreSQL.
Fix: Wait for the PostgreSQL health check to pass before the backend starts. If persistent, check that POSTGRES_PASSWORD matches in both the Compose file and config.properties.
Frontend Shows “API Unreachable”
Symptom: Frontend loads but shows no content.
Fix: Verify BACKEND_HOSTNAME in the frontend environment matches your actual API subdomain. Check that the API service is accessible: curl -s https://pipedapi.example.com/healthcheck
Resource Requirements
- RAM: 700 MB idle (backend is Java-based), 1.5 GB under active use
- CPU: 2 cores recommended for smooth video proxying
- Disk: 500 MB for application data, plus PostgreSQL storage (grows slowly with user data)
Verdict
Piped is the best privacy-focused YouTube frontend for self-hosting. It’s faster than Invidious, handles YouTube’s API changes better thanks to the PoToken system, and includes SponsorBlock integration. The three-subdomain requirement adds setup complexity, but the official configure-instance.sh script makes deployment straightforward.
Use Piped if you want ad-free, tracking-free YouTube on your own infrastructure. For a simpler but less full-featured alternative, consider Invidious. If you want to archive YouTube content rather than stream it, look at Tube Archivist.
Frequently Asked Questions
How does Piped compare to Invidious?
Both are privacy-focused YouTube frontends, but they use different technical approaches. Piped uses YouTube’s internal API with a proxy layer and PoToken system for authentication. Invidious uses scraping. Piped generally handles YouTube’s frequent changes better and loads videos faster. Invidious has a simpler single-container setup. Choose Piped for better performance and compatibility. Choose Invidious for simpler deployment.
Why does Piped need three subdomains?
Piped separates the frontend, API, and video proxy into three services, each needing its own subdomain for CORS and SSL to work correctly. Typically: piped.example.com (frontend), pipedapi.example.com (API), and pipedproxy.example.com (video proxy). The official configure-instance.sh script generates all the configuration files for your three subdomains automatically.
Will YouTube block my Piped instance?
Eventually, yes — single-IP instances get rate-limited under heavy use. YouTube throttles IPs that make many requests. Mitigation options include IPv6 rotation, residential proxies, or limiting the number of concurrent users. Light personal use on a single instance typically works fine. For shared instances with many users, IP rotation is essential.
Can I import my YouTube subscriptions into Piped?
Yes. Piped supports importing subscriptions from YouTube (via Google Takeout), Invidious, and NewPipe. Export your subscription list as an OPML or JSON file and import it through the Piped settings page. Subscriptions, playlists, and watch history are stored locally on your instance.
How much RAM does Piped use?
The backend is Java-based, so expect 700 MB idle and 1.5 GB under active use. PostgreSQL adds another 200–300 MB. The proxy service uses minimal RAM. Total: plan for 2 GB minimum, 4 GB recommended for smooth operation with multiple concurrent users streaming video.
Does Piped support SponsorBlock?
Yes — SponsorBlock integration is built in. Piped automatically skips sponsor segments, intros, outros, and other community-flagged sections in videos. You can configure which segment types to skip in the settings. This works out of the box with no additional setup.
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