Funkwhale Music Platform
Social music platform for sharing and discovering music.
Overview
Funkwhale is a self-hosted, federated music server that enables users to build their own Spotify-like platform with social features and ActivityPub federation. Born from the need for a decentralized alternative to proprietary music streaming services, Funkwhale allows individuals and communities to share, discover, and stream music while maintaining full control over their data and privacy. The platform supports multiple audio formats, provides Subsonic API compatibility for mobile apps, and integrates with the broader fediverse through ActivityPub protocol.
This deployment stack combines Funkwhale's Django-based API backend with a Vue.js frontend, while leveraging PostgreSQL for robust metadata storage and complex music library relationships, and Redis for high-performance caching and Celery task queue management. The architecture separates concerns effectively: the API handles music metadata, user management, and federation logic, while Celery workers process audio transcoding, library imports, and federation tasks in the background. Redis serves dual purposes as both a cache layer for frequently accessed music metadata and as a message broker for asynchronous task processing.
This configuration is ideal for music enthusiasts, podcast creators, radio stations, and organizations wanting to create their own streaming platform without vendor lock-in. The federated nature allows multiple Funkwhale instances to share content and users, creating a decentralized network similar to Mastodon but for audio content. Musicians can distribute their work directly, while communities can build curated collections with fine-grained privacy controls and user permissions.
Key Features
- ActivityPub federation enabling content sharing across multiple Funkwhale instances and fediverse integration
- Subsonic API compatibility allowing use of existing mobile music apps like DSub and Ultrasonic
- Multi-format audio support with automatic transcoding via Celery workers for bandwidth optimization
- Advanced music library management with artist pages, album collections, and tag-based organization
- Social features including follow/unfollow, playlist sharing, and content discovery across federated instances
- Granular privacy controls with public, followers-only, and private content visibility levels
- Bulk music import from filesystem with automatic metadata extraction and duplicate detection
- Built-in audio player with queue management, repeat modes, and scrobbling support
Common Use Cases
- 1Independent musicians distributing music directly to fans with federated reach across multiple instances
- 2Community radio stations creating curated playlists with listener interaction and content discovery
- 3Music collectives and labels building private streaming platforms with controlled access and member features
- 4Podcast networks hosting audio content with RSS feed generation and cross-instance syndication
- 5Educational institutions providing music streaming for students with copyright-compliant content management
- 6Personal music servers replacing Spotify with family sharing and mobile app compatibility
- 7Music archivists preserving rare recordings with metadata preservation and federated backup systems
Prerequisites
- Minimum 2GB RAM (1GB+ for PostgreSQL, 512MB+ for Redis, plus Funkwhale components and Celery workers)
- Port 80 available for HTTP access to the Funkwhale web interface
- Music library accessible at filesystem path with read permissions for Docker containers
- Domain name or hostname configured for FUNKWHALE_HOST environment variable
- Understanding of music metadata management and audio format compatibility
- Basic knowledge of Django admin interface for user and content moderation
For development & testing. Review security settings, change default credentials, and test thoroughly before production use. See Terms
docker-compose.yml
docker-compose.yml
1services: 2 api: 3 image: funkwhale/api:latest4 container_name: funkwhale-api5 environment: 6 - FUNKWHALE_HOSTNAME=${FUNKWHALE_HOST}7 - FUNKWHALE_PROTOCOL=http8 - DATABASE_URL=postgresql://funkwhale:${DB_PASSWORD}@db:5432/funkwhale9 - CACHE_URL=redis://redis:6379/010 - DJANGO_SECRET_KEY=${SECRET_KEY}11 - DJANGO_ALLOWED_HOSTS=*12 volumes: 13 - funkwhale-data:/srv/funkwhale/data14 - /path/to/music:/music:ro15 depends_on: 16 - db17 - redis18 networks: 19 - funkwhale-network20 restart: unless-stopped2122 front: 23 image: funkwhale/front:latest24 container_name: funkwhale-front25 environment: 26 - FUNKWHALE_API_HOST=api27 - FUNKWHALE_API_PORT=500028 ports: 29 - "80:80"30 depends_on: 31 - api32 networks: 33 - funkwhale-network34 restart: unless-stopped3536 celery-worker: 37 image: funkwhale/api:latest38 container_name: funkwhale-celery-worker39 command: celery -A funkwhale_api.taskapp worker -l INFO40 environment: 41 - FUNKWHALE_HOSTNAME=${FUNKWHALE_HOST}42 - DATABASE_URL=postgresql://funkwhale:${DB_PASSWORD}@db:5432/funkwhale43 - CACHE_URL=redis://redis:6379/044 - DJANGO_SECRET_KEY=${SECRET_KEY}45 volumes: 46 - funkwhale-data:/srv/funkwhale/data47 - /path/to/music:/music:ro48 depends_on: 49 - api50 networks: 51 - funkwhale-network52 restart: unless-stopped5354 celery-beat: 55 image: funkwhale/api:latest56 container_name: funkwhale-celery-beat57 command: celery -A funkwhale_api.taskapp beat -l INFO58 environment: 59 - FUNKWHALE_HOSTNAME=${FUNKWHALE_HOST}60 - DATABASE_URL=postgresql://funkwhale:${DB_PASSWORD}@db:5432/funkwhale61 - CACHE_URL=redis://redis:6379/062 - DJANGO_SECRET_KEY=${SECRET_KEY}63 depends_on: 64 - api65 networks: 66 - funkwhale-network67 restart: unless-stopped6869 db: 70 image: postgres:15-alpine71 container_name: funkwhale-db72 environment: 73 - POSTGRES_USER=funkwhale74 - POSTGRES_PASSWORD=${DB_PASSWORD}75 - POSTGRES_DB=funkwhale76 volumes: 77 - postgres-data:/var/lib/postgresql/data78 networks: 79 - funkwhale-network80 restart: unless-stopped8182 redis: 83 image: redis:7-alpine84 container_name: funkwhale-redis85 volumes: 86 - redis-data:/data87 networks: 88 - funkwhale-network89 restart: unless-stopped9091volumes: 92 funkwhale-data: 93 postgres-data: 94 redis-data: 9596networks: 97 funkwhale-network: 98 driver: bridge.env Template
.env
1# Funkwhale2FUNKWHALE_HOST=funkwhale.localhost3DB_PASSWORD=secure_funkwhale_password45# Generate with: openssl rand -hex 326SECRET_KEY=your_secret_keyUsage Notes
- 1Web UI at http://localhost
- 2Create admin: manage.py createsuperuser
- 3Federation with ActivityPub
- 4Import from filesystem
- 5Subsonic API compatible
Individual Services(6 services)
Copy individual services to mix and match with your existing compose files.
api
api:
image: funkwhale/api:latest
container_name: funkwhale-api
environment:
- FUNKWHALE_HOSTNAME=${FUNKWHALE_HOST}
- FUNKWHALE_PROTOCOL=http
- DATABASE_URL=postgresql://funkwhale:${DB_PASSWORD}@db:5432/funkwhale
- CACHE_URL=redis://redis:6379/0
- DJANGO_SECRET_KEY=${SECRET_KEY}
- DJANGO_ALLOWED_HOSTS=*
volumes:
- funkwhale-data:/srv/funkwhale/data
- /path/to/music:/music:ro
depends_on:
- db
- redis
networks:
- funkwhale-network
restart: unless-stopped
front
front:
image: funkwhale/front:latest
container_name: funkwhale-front
environment:
- FUNKWHALE_API_HOST=api
- FUNKWHALE_API_PORT=5000
ports:
- "80:80"
depends_on:
- api
networks:
- funkwhale-network
restart: unless-stopped
celery-worker
celery-worker:
image: funkwhale/api:latest
container_name: funkwhale-celery-worker
command: celery -A funkwhale_api.taskapp worker -l INFO
environment:
- FUNKWHALE_HOSTNAME=${FUNKWHALE_HOST}
- DATABASE_URL=postgresql://funkwhale:${DB_PASSWORD}@db:5432/funkwhale
- CACHE_URL=redis://redis:6379/0
- DJANGO_SECRET_KEY=${SECRET_KEY}
volumes:
- funkwhale-data:/srv/funkwhale/data
- /path/to/music:/music:ro
depends_on:
- api
networks:
- funkwhale-network
restart: unless-stopped
celery-beat
celery-beat:
image: funkwhale/api:latest
container_name: funkwhale-celery-beat
command: celery -A funkwhale_api.taskapp beat -l INFO
environment:
- FUNKWHALE_HOSTNAME=${FUNKWHALE_HOST}
- DATABASE_URL=postgresql://funkwhale:${DB_PASSWORD}@db:5432/funkwhale
- CACHE_URL=redis://redis:6379/0
- DJANGO_SECRET_KEY=${SECRET_KEY}
depends_on:
- api
networks:
- funkwhale-network
restart: unless-stopped
db
db:
image: postgres:15-alpine
container_name: funkwhale-db
environment:
- POSTGRES_USER=funkwhale
- POSTGRES_PASSWORD=${DB_PASSWORD}
- POSTGRES_DB=funkwhale
volumes:
- postgres-data:/var/lib/postgresql/data
networks:
- funkwhale-network
restart: unless-stopped
redis
redis:
image: redis:7-alpine
container_name: funkwhale-redis
volumes:
- redis-data:/data
networks:
- funkwhale-network
restart: unless-stopped
Quick Start
terminal
1# 1. Create the compose file2cat > docker-compose.yml << 'EOF'3services:4 api:5 image: funkwhale/api:latest6 container_name: funkwhale-api7 environment:8 - FUNKWHALE_HOSTNAME=${FUNKWHALE_HOST}9 - FUNKWHALE_PROTOCOL=http10 - DATABASE_URL=postgresql://funkwhale:${DB_PASSWORD}@db:5432/funkwhale11 - CACHE_URL=redis://redis:6379/012 - DJANGO_SECRET_KEY=${SECRET_KEY}13 - DJANGO_ALLOWED_HOSTS=*14 volumes:15 - funkwhale-data:/srv/funkwhale/data16 - /path/to/music:/music:ro17 depends_on:18 - db19 - redis20 networks:21 - funkwhale-network22 restart: unless-stopped2324 front:25 image: funkwhale/front:latest26 container_name: funkwhale-front27 environment:28 - FUNKWHALE_API_HOST=api29 - FUNKWHALE_API_PORT=500030 ports:31 - "80:80"32 depends_on:33 - api34 networks:35 - funkwhale-network36 restart: unless-stopped3738 celery-worker:39 image: funkwhale/api:latest40 container_name: funkwhale-celery-worker41 command: celery -A funkwhale_api.taskapp worker -l INFO42 environment:43 - FUNKWHALE_HOSTNAME=${FUNKWHALE_HOST}44 - DATABASE_URL=postgresql://funkwhale:${DB_PASSWORD}@db:5432/funkwhale45 - CACHE_URL=redis://redis:6379/046 - DJANGO_SECRET_KEY=${SECRET_KEY}47 volumes:48 - funkwhale-data:/srv/funkwhale/data49 - /path/to/music:/music:ro50 depends_on:51 - api52 networks:53 - funkwhale-network54 restart: unless-stopped5556 celery-beat:57 image: funkwhale/api:latest58 container_name: funkwhale-celery-beat59 command: celery -A funkwhale_api.taskapp beat -l INFO60 environment:61 - FUNKWHALE_HOSTNAME=${FUNKWHALE_HOST}62 - DATABASE_URL=postgresql://funkwhale:${DB_PASSWORD}@db:5432/funkwhale63 - CACHE_URL=redis://redis:6379/064 - DJANGO_SECRET_KEY=${SECRET_KEY}65 depends_on:66 - api67 networks:68 - funkwhale-network69 restart: unless-stopped7071 db:72 image: postgres:15-alpine73 container_name: funkwhale-db74 environment:75 - POSTGRES_USER=funkwhale76 - POSTGRES_PASSWORD=${DB_PASSWORD}77 - POSTGRES_DB=funkwhale78 volumes:79 - postgres-data:/var/lib/postgresql/data80 networks:81 - funkwhale-network82 restart: unless-stopped8384 redis:85 image: redis:7-alpine86 container_name: funkwhale-redis87 volumes:88 - redis-data:/data89 networks:90 - funkwhale-network91 restart: unless-stopped9293volumes:94 funkwhale-data:95 postgres-data:96 redis-data:9798networks:99 funkwhale-network:100 driver: bridge101EOF102103# 2. Create the .env file104cat > .env << 'EOF'105# Funkwhale106FUNKWHALE_HOST=funkwhale.localhost107DB_PASSWORD=secure_funkwhale_password108109# Generate with: openssl rand -hex 32110SECRET_KEY=your_secret_key111EOF112113# 3. Start the services114docker compose up -d115116# 4. View logs117docker compose logs -fOne-Liner
Run this command to download and set up the recipe in one step:
terminal
1curl -fsSL https://docker.recipes/api/recipes/funkwhale-music/run | bashTroubleshooting
- Import tasks failing or stuck: Check Celery worker logs and ensure music directory has proper read permissions and supported audio formats
- Federation not working with other instances: Verify FUNKWHALE_HOSTNAME matches your actual domain and is accessible externally with proper DNS configuration
- High memory usage during imports: Limit concurrent Celery workers and increase Redis memory allocation for large music libraries
- Subsonic API authentication failing: Ensure user accounts are created through Django admin and have proper API permissions enabled
- Frontend showing API connection errors: Verify FUNKWHALE_API_HOST environment variable matches the actual API service name and port 5000 connectivity
- Database migration errors on startup: Check PostgreSQL logs for disk space and ensure DATABASE_URL format matches PostgreSQL connection requirements
Community Notes
Loading...
Loading notes...
Download Recipe Kit
Get all files in a ready-to-deploy package
Includes docker-compose.yml, .env template, README, and license
Components
funkwhale-apifunkwhale-frontfunkwhale-celerypostgresqlredis
Tags
#music#funkwhale#social#federated#activitypub
Category
Media & EntertainmentAd Space
Shortcuts: C CopyF FavoriteD Download