Plane Issue Tracker
Open-source project tracking tool, JIRA alternative.
Overview
Plane is an open-source project management and issue tracking platform designed as a modern alternative to JIRA. Built with a focus on simplicity and speed, Plane offers comprehensive project tracking capabilities including issue management, sprint planning, roadmap visualization, and team collaboration features. The platform emphasizes user experience with a clean, intuitive interface while providing powerful features like custom workflows, multiple project views, and advanced filtering options.
This Docker deployment creates a complete Plane installation using a multi-service architecture. The stack includes a Next.js frontend (web), Django REST API backend (api), Celery worker processes for background tasks (worker), Celery beat scheduler for periodic tasks (beat), PostgreSQL for primary data storage (db), Redis for caching and task queues (redis), and MinIO for S3-compatible file storage (minio). The backend services share the same Docker image but run different processes to handle web requests, background processing, and scheduled tasks separately.
This configuration is ideal for teams seeking a self-hosted project management solution with enterprise-grade features but without vendor lock-in. Organizations transitioning from JIRA, development teams requiring integrated issue tracking with Git workflows, and companies needing customizable project management tools will benefit from this deployment. The separation of concerns across multiple services provides scalability while maintaining data sovereignty and customization flexibility.
Key Features
- Comprehensive issue tracking with custom fields, labels, and workflow states
- Sprint planning and cycle management with burndown charts and velocity tracking
- Multiple project views including Kanban boards, lists, and calendar views
- Advanced filtering and search capabilities across issues and projects
- File attachment support with S3-compatible storage via MinIO integration
- Real-time collaboration features powered by Redis pub/sub messaging
- Background task processing for notifications, imports, and data synchronization
- GitHub and GitLab integration for automatic issue creation and status updates
Common Use Cases
- 1Software development teams migrating from JIRA to an open-source alternative
- 2Startups and scale-ups needing project management without per-user licensing costs
- 3Organizations requiring self-hosted solutions for data privacy and compliance
- 4Development teams integrating issue tracking with existing Git workflows
- 5Companies needing customizable project management workflows and reporting
- 6Remote teams requiring real-time collaboration on project planning and execution
- 7Agencies managing multiple client projects with separate workspaces and permissions
Prerequisites
- Docker and Docker Compose installed with minimum 4GB total RAM available
- Port 3000 available for web interface and port 9000 for MinIO console access
- Environment variables configured including SECRET_KEY, database password, and MinIO credentials
- SMTP server details for email notifications (optional but recommended)
- Basic understanding of Django/Python applications for configuration and troubleshooting
- Familiarity with PostgreSQL for database maintenance and backup procedures
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 web: 3 image: makeplane/plane-frontend:latest4 container_name: plane-web5 environment: 6 - NEXT_PUBLIC_API_BASE_URL=${API_URL}7 ports: 8 - "3000:3000"9 depends_on: 10 - api11 networks: 12 - plane-network13 restart: unless-stopped1415 api: 16 image: makeplane/plane-backend:latest17 container_name: plane-api18 environment: 19 - DEBUG=020 - DJANGO_SETTINGS_MODULE=plane.settings.production21 - SECRET_KEY=${SECRET_KEY}22 - DATABASE_URL=postgres://plane:${DB_PASSWORD}@db:5432/plane23 - REDIS_URL=redis://redis:6379/24 - EMAIL_HOST=${EMAIL_HOST}25 - EMAIL_HOST_USER=${EMAIL_HOST_USER}26 - EMAIL_HOST_PASSWORD=${EMAIL_HOST_PASSWORD}27 - AWS_ACCESS_KEY_ID=${MINIO_ACCESS_KEY}28 - AWS_SECRET_ACCESS_KEY=${MINIO_SECRET_KEY}29 - AWS_S3_ENDPOINT_URL=${MINIO_URL}30 - AWS_S3_BUCKET_NAME=plane31 - FILE_SIZE_LIMIT=524288032 - WEB_URL=${WEB_URL}33 depends_on: 34 - db35 - redis36 networks: 37 - plane-network38 restart: unless-stopped3940 worker: 41 image: makeplane/plane-backend:latest42 container_name: plane-worker43 command: ./bin/worker44 environment: 45 - DEBUG=046 - DJANGO_SETTINGS_MODULE=plane.settings.production47 - SECRET_KEY=${SECRET_KEY}48 - DATABASE_URL=postgres://plane:${DB_PASSWORD}@db:5432/plane49 - REDIS_URL=redis://redis:6379/50 depends_on: 51 - api52 - redis53 networks: 54 - plane-network55 restart: unless-stopped5657 beat: 58 image: makeplane/plane-backend:latest59 container_name: plane-beat60 command: ./bin/beat61 environment: 62 - DEBUG=063 - DJANGO_SETTINGS_MODULE=plane.settings.production64 - SECRET_KEY=${SECRET_KEY}65 - DATABASE_URL=postgres://plane:${DB_PASSWORD}@db:5432/plane66 - REDIS_URL=redis://redis:6379/67 depends_on: 68 - api69 - redis70 networks: 71 - plane-network72 restart: unless-stopped7374 db: 75 image: postgres:15-alpine76 container_name: plane-db77 environment: 78 - POSTGRES_USER=plane79 - POSTGRES_PASSWORD=${DB_PASSWORD}80 - POSTGRES_DB=plane81 volumes: 82 - postgres-data:/var/lib/postgresql/data83 networks: 84 - plane-network85 restart: unless-stopped8687 redis: 88 image: redis:7-alpine89 container_name: plane-redis90 volumes: 91 - redis-data:/data92 networks: 93 - plane-network94 restart: unless-stopped9596 minio: 97 image: minio/minio:latest98 container_name: plane-minio99 environment: 100 - MINIO_ROOT_USER=${MINIO_ACCESS_KEY}101 - MINIO_ROOT_PASSWORD=${MINIO_SECRET_KEY}102 command: server /data --console-address ":9001"103 volumes: 104 - minio-data:/data105 ports: 106 - "9000:9000"107 networks: 108 - plane-network109 restart: unless-stopped110111volumes: 112 postgres-data: 113 redis-data: 114 minio-data: 115116networks: 117 plane-network: 118 driver: bridge.env Template
.env
1# Plane2WEB_URL=http://localhost:30003API_URL=http://localhost:800045# Generate with: openssl rand -hex 326SECRET_KEY=your_secret_key_here7DB_PASSWORD=secure_plane_password89# MinIO10MINIO_ACCESS_KEY=plane_minio11MINIO_SECRET_KEY=secure_minio_password12MINIO_URL=http://minio:90001314# Email (optional)15EMAIL_HOST=smtp.example.com16EMAIL_HOST_USER=plane@example.com17EMAIL_HOST_PASSWORD=email_passwordUsage Notes
- 1Web UI at http://localhost:3000
- 2Create plane bucket in MinIO first
- 3JIRA-like issue tracking
- 4Supports cycles, modules, views
- 5GitHub and GitLab integrations
Individual Services(7 services)
Copy individual services to mix and match with your existing compose files.
web
web:
image: makeplane/plane-frontend:latest
container_name: plane-web
environment:
- NEXT_PUBLIC_API_BASE_URL=${API_URL}
ports:
- "3000:3000"
depends_on:
- api
networks:
- plane-network
restart: unless-stopped
api
api:
image: makeplane/plane-backend:latest
container_name: plane-api
environment:
- DEBUG=0
- DJANGO_SETTINGS_MODULE=plane.settings.production
- SECRET_KEY=${SECRET_KEY}
- DATABASE_URL=postgres://plane:${DB_PASSWORD}@db:5432/plane
- REDIS_URL=redis://redis:6379/
- EMAIL_HOST=${EMAIL_HOST}
- EMAIL_HOST_USER=${EMAIL_HOST_USER}
- EMAIL_HOST_PASSWORD=${EMAIL_HOST_PASSWORD}
- AWS_ACCESS_KEY_ID=${MINIO_ACCESS_KEY}
- AWS_SECRET_ACCESS_KEY=${MINIO_SECRET_KEY}
- AWS_S3_ENDPOINT_URL=${MINIO_URL}
- AWS_S3_BUCKET_NAME=plane
- FILE_SIZE_LIMIT=5242880
- WEB_URL=${WEB_URL}
depends_on:
- db
- redis
networks:
- plane-network
restart: unless-stopped
worker
worker:
image: makeplane/plane-backend:latest
container_name: plane-worker
command: ./bin/worker
environment:
- DEBUG=0
- DJANGO_SETTINGS_MODULE=plane.settings.production
- SECRET_KEY=${SECRET_KEY}
- DATABASE_URL=postgres://plane:${DB_PASSWORD}@db:5432/plane
- REDIS_URL=redis://redis:6379/
depends_on:
- api
- redis
networks:
- plane-network
restart: unless-stopped
beat
beat:
image: makeplane/plane-backend:latest
container_name: plane-beat
command: ./bin/beat
environment:
- DEBUG=0
- DJANGO_SETTINGS_MODULE=plane.settings.production
- SECRET_KEY=${SECRET_KEY}
- DATABASE_URL=postgres://plane:${DB_PASSWORD}@db:5432/plane
- REDIS_URL=redis://redis:6379/
depends_on:
- api
- redis
networks:
- plane-network
restart: unless-stopped
db
db:
image: postgres:15-alpine
container_name: plane-db
environment:
- POSTGRES_USER=plane
- POSTGRES_PASSWORD=${DB_PASSWORD}
- POSTGRES_DB=plane
volumes:
- postgres-data:/var/lib/postgresql/data
networks:
- plane-network
restart: unless-stopped
redis
redis:
image: redis:7-alpine
container_name: plane-redis
volumes:
- redis-data:/data
networks:
- plane-network
restart: unless-stopped
minio
minio:
image: minio/minio:latest
container_name: plane-minio
environment:
- MINIO_ROOT_USER=${MINIO_ACCESS_KEY}
- MINIO_ROOT_PASSWORD=${MINIO_SECRET_KEY}
command: server /data --console-address ":9001"
volumes:
- minio-data:/data
ports:
- "9000:9000"
networks:
- plane-network
restart: unless-stopped
Quick Start
terminal
1# 1. Create the compose file2cat > docker-compose.yml << 'EOF'3services:4 web:5 image: makeplane/plane-frontend:latest6 container_name: plane-web7 environment:8 - NEXT_PUBLIC_API_BASE_URL=${API_URL}9 ports:10 - "3000:3000"11 depends_on:12 - api13 networks:14 - plane-network15 restart: unless-stopped1617 api:18 image: makeplane/plane-backend:latest19 container_name: plane-api20 environment:21 - DEBUG=022 - DJANGO_SETTINGS_MODULE=plane.settings.production23 - SECRET_KEY=${SECRET_KEY}24 - DATABASE_URL=postgres://plane:${DB_PASSWORD}@db:5432/plane25 - REDIS_URL=redis://redis:6379/26 - EMAIL_HOST=${EMAIL_HOST}27 - EMAIL_HOST_USER=${EMAIL_HOST_USER}28 - EMAIL_HOST_PASSWORD=${EMAIL_HOST_PASSWORD}29 - AWS_ACCESS_KEY_ID=${MINIO_ACCESS_KEY}30 - AWS_SECRET_ACCESS_KEY=${MINIO_SECRET_KEY}31 - AWS_S3_ENDPOINT_URL=${MINIO_URL}32 - AWS_S3_BUCKET_NAME=plane33 - FILE_SIZE_LIMIT=524288034 - WEB_URL=${WEB_URL}35 depends_on:36 - db37 - redis38 networks:39 - plane-network40 restart: unless-stopped4142 worker:43 image: makeplane/plane-backend:latest44 container_name: plane-worker45 command: ./bin/worker46 environment:47 - DEBUG=048 - DJANGO_SETTINGS_MODULE=plane.settings.production49 - SECRET_KEY=${SECRET_KEY}50 - DATABASE_URL=postgres://plane:${DB_PASSWORD}@db:5432/plane51 - REDIS_URL=redis://redis:6379/52 depends_on:53 - api54 - redis55 networks:56 - plane-network57 restart: unless-stopped5859 beat:60 image: makeplane/plane-backend:latest61 container_name: plane-beat62 command: ./bin/beat63 environment:64 - DEBUG=065 - DJANGO_SETTINGS_MODULE=plane.settings.production66 - SECRET_KEY=${SECRET_KEY}67 - DATABASE_URL=postgres://plane:${DB_PASSWORD}@db:5432/plane68 - REDIS_URL=redis://redis:6379/69 depends_on:70 - api71 - redis72 networks:73 - plane-network74 restart: unless-stopped7576 db:77 image: postgres:15-alpine78 container_name: plane-db79 environment:80 - POSTGRES_USER=plane81 - POSTGRES_PASSWORD=${DB_PASSWORD}82 - POSTGRES_DB=plane83 volumes:84 - postgres-data:/var/lib/postgresql/data85 networks:86 - plane-network87 restart: unless-stopped8889 redis:90 image: redis:7-alpine91 container_name: plane-redis92 volumes:93 - redis-data:/data94 networks:95 - plane-network96 restart: unless-stopped9798 minio:99 image: minio/minio:latest100 container_name: plane-minio101 environment:102 - MINIO_ROOT_USER=${MINIO_ACCESS_KEY}103 - MINIO_ROOT_PASSWORD=${MINIO_SECRET_KEY}104 command: server /data --console-address ":9001"105 volumes:106 - minio-data:/data107 ports:108 - "9000:9000"109 networks:110 - plane-network111 restart: unless-stopped112113volumes:114 postgres-data:115 redis-data:116 minio-data:117118networks:119 plane-network:120 driver: bridge121EOF122123# 2. Create the .env file124cat > .env << 'EOF'125# Plane126WEB_URL=http://localhost:3000127API_URL=http://localhost:8000128129# Generate with: openssl rand -hex 32130SECRET_KEY=your_secret_key_here131DB_PASSWORD=secure_plane_password132133# MinIO134MINIO_ACCESS_KEY=plane_minio135MINIO_SECRET_KEY=secure_minio_password136MINIO_URL=http://minio:9000137138# Email (optional)139EMAIL_HOST=smtp.example.com140EMAIL_HOST_USER=plane@example.com141EMAIL_HOST_PASSWORD=email_password142EOF143144# 3. Start the services145docker compose up -d146147# 4. View logs148docker 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/plane-pm/run | bashTroubleshooting
- plane-api container fails to start: Verify DATABASE_URL format and ensure plane-db is fully initialized before API startup
- File uploads not working: Check MinIO credentials match between plane-api AWS_* variables and plane-minio MINIO_ROOT_* settings
- Background tasks not processing: Ensure plane-worker container is running and Redis connection is established via REDIS_URL
- Email notifications not sending: Verify EMAIL_HOST, EMAIL_HOST_USER, and EMAIL_HOST_PASSWORD variables are correctly set in plane-api
- plane-web shows API connection errors: Confirm NEXT_PUBLIC_API_BASE_URL points to accessible plane-api service and matches your domain setup
- Scheduled tasks not executing: Check plane-beat container logs and ensure Celery beat scheduler is connecting to Redis successfully
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
plane-webplane-apiplane-workerplane-beatpostgresqlredisminio
Tags
#issue-tracker#jira-alternative#project-management#plane
Category
Productivity & CollaborationAd Space
Shortcuts: C CopyF FavoriteD Download