Plane: Open-Source Jira Alternative
Modern project planning and tracking. Issues, sprints, and roadmaps with beautiful UI.
Introduction
Plane is a modern, open-source project management platform designed to rival Jira and Linear. Built for agile teams, Plane offers a beautiful interface with powerful features including kanban boards, sprint planning, issue tracking, roadmaps, and analytics. With over 25,000 GitHub stars and backing from Y Combinator, Plane has become the leading self-hosted alternative to expensive SaaS project management tools.
Why Choose Plane?
Modern User Experience
Unlike Jira’s complex and cluttered interface, Plane provides a clean, intuitive design that teams can adopt immediately without extensive training. The interface is fast, responsive, and built with modern web technologies.
Complete Feature Parity
Plane includes all the features you’d expect from enterprise project management tools: multiple projects, customizable workflows, sprints, backlogs, roadmaps, time tracking, and detailed reporting.
Privacy and Data Control
Your project data, roadmaps, and strategic planning stay on your infrastructure. No third-party vendor has access to your intellectual property or business plans.
Cost Savings
Jira costs $7.75-15.25/user/month. For a team of 25, that’s $2,325-4,575 annually. Plane is completely free with unlimited users, projects, and features.
Developer-Friendly
Built by developers for developers, Plane integrates seamlessly with GitHub, GitLab, provides a powerful API, supports webhooks, and offers CLI tools for automation.
Key Features:
- Multiple workspaces and projects
- Kanban, list, and calendar views
- Sprint planning and backlog management
- Issue tracking with custom fields
- Roadmap planning and timeline views
- Cycle management for iterations
- Module-based organization
- Pages for documentation
- Detailed analytics and reports
- GitHub/GitLab integration
- API and webhooks
- Custom workflows and automation
- Time tracking and estimates
- Labels, priorities, and assignees
- Rich text and Markdown support
- File attachments and comments
Understanding the Architecture
Plane consists of multiple microservices working together:
Internet/Local Network
│
▼
┌───────────────┐
│ Reverse Proxy │ (Nginx, Traefik, Caddy)
│ HTTPS/SSL │
└───────┬───────┘
│
▼
┌───────────────┐
│ Plane Web │ (React Frontend - Port 3000)
└───────┬───────┘
│
┌───┴────┬──────────┬─────────┐
│ │ │ │
▼ ▼ ▼ ▼
┌──────┐ ┌──────┐ ┌────────┐ ┌──────┐
│ API │ │Space │ │ Admin │ │Live │
│:8000 │ │:4000 │ │ :8000 │ │:3000 │
└──┬───┘ └──────┘ └────────┘ └──────┘
│
├─────┬──────────┬─────────┐
│ │ │ │
▼ ▼ ▼ ▼
┌────┐ ┌────┐ ┌────────┐ ┌──────┐
│Post│ │Redis│ │ MinIO │ │Worker│
│gres│ │Cache│ │Storage │ │Queue │
└────┘ └────┘ └────────┘ └──────┘ Prerequisites
Hardware Requirements
Minimum Configuration:
- RAM: 4GB (handles small teams up to 10 users)
- CPU: 2 cores
- Storage: 20GB SSD
- Network: Standard homelab network
Recommended Configuration:
- RAM: 8GB (better for 25+ users)
- CPU: 4 cores
- Storage: 50GB+ SSD
- Network: Gigabit ethernet
Production Environment (50+ users):
- RAM: 16GB+
- CPU: 8+ cores
- Storage: 100GB+ SSD with fast I/O
- Dedicated database server
Software Requirements
- Docker Engine v24+ with docker-compose
- Linux (Ubuntu 22.04/24.04 LTS recommended)
- 2GB+ available RAM
- Domain name (optional, for HTTPS)
Pre-Deployment Checklist
# Verify Docker installation
docker --version
docker compose version
# Check system resources
free -h
df -h
# Verify network connectivity
ping -c 3 google.com Installation and Deployment
Step 1: Create Project Structure
# Create directory structure
mkdir -p ~/plane/{data,env}
cd ~/plane
# Set proper permissions
chmod 755 ~/plane Step 2: Generate Secure Secrets
# Generate required secrets
export SECRET_KEY=$(openssl rand -hex 32)
export POSTGRES_PASSWORD=$(openssl rand -base64 24)
export REDIS_PASSWORD=$(openssl rand -base64 24)
export MINIO_ACCESS_KEY=$(openssl rand -hex 16)
export MINIO_SECRET_KEY=$(openssl rand -hex 32)
echo "Save these credentials securely:"
echo "SECRET_KEY: $SECRET_KEY"
echo "POSTGRES_PASSWORD: $POSTGRES_PASSWORD"
echo "REDIS_PASSWORD: $REDIS_PASSWORD"
echo "MINIO_ACCESS_KEY: $MINIO_ACCESS_KEY"
echo "MINIO_SECRET_KEY: $MINIO_SECRET_KEY" Step 3: Create Environment Configuration
Create .env file:
cat > .env <<EOF
# Application Configuration
WEB_URL=http://YOUR-SERVER-IP:3000
CORS_ALLOWED_ORIGINS=http://YOUR-SERVER-IP:3000
# Database Configuration
POSTGRES_USER=plane
POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
POSTGRES_DB=plane
DATABASE_URL=postgresql://plane:${POSTGRES_PASSWORD}@plane-db:5432/plane
# Redis Configuration
REDIS_URL=redis://plane-redis:6379/
REDIS_PASSWORD=${REDIS_PASSWORD}
# MinIO Configuration (File Storage)
USE_MINIO=1
MINIO_ROOT_USER=${MINIO_ACCESS_KEY}
MINIO_ROOT_PASSWORD=${MINIO_SECRET_KEY}
MINIO_ENDPOINT=plane-minio:9000
AWS_ACCESS_KEY_ID=${MINIO_ACCESS_KEY}
AWS_SECRET_ACCESS_KEY=${MINIO_SECRET_KEY}
AWS_REGION=us-east-1
AWS_S3_BUCKET_NAME=plane-uploads
# Security
SECRET_KEY=${SECRET_KEY}
# Email Configuration (Optional - for notifications)
# EMAIL_HOST=smtp.gmail.com
# EMAIL_PORT=587
# EMAIL_USE_TLS=1
# [email protected]
# EMAIL_HOST_PASSWORD=your-app-password
# [email protected]
# GitHub Integration (Optional)
# GITHUB_CLIENT_ID=
# GITHUB_CLIENT_SECRET=
# Enable/Disable Features
ENABLE_SIGNUP=1
ENABLE_EMAIL_PASSWORD=1
ENABLE_MAGIC_LINK_LOGIN=0
EOF
# Secure the file
chmod 600 .env Important: Replace YOUR-SERVER-IP with your server’s actual IP address.
Step 4: Create Docker Compose Configuration
Create docker-compose.yml:
version: "3.8"
x-app-env: &app-env
environment:
- WEB_URL=${WEB_URL}
- DATABASE_URL=${DATABASE_URL}
- REDIS_URL=${REDIS_URL}
- SECRET_KEY=${SECRET_KEY}
- AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
- AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
- AWS_REGION=${AWS_REGION}
- AWS_S3_BUCKET_NAME=${AWS_S3_BUCKET_NAME}
- MINIO_ENDPOINT=${MINIO_ENDPOINT}
- USE_MINIO=${USE_MINIO}
- CORS_ALLOWED_ORIGINS=${CORS_ALLOWED_ORIGINS}
services:
# PostgreSQL Database
plane-db:
image: postgres:15-alpine
container_name: plane-db
restart: unless-stopped
command: postgres -c 'max_connections=1000'
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
PGDATA: /var/lib/postgresql/data
volumes:
- postgres-data:/var/lib/postgresql/data
networks:
- plane-network
healthcheck:
test: ["CMD-SHELL", "pg_isready -U plane"]
interval: 10s
timeout: 5s
retries: 5
# Redis Cache
plane-redis:
image: redis:7-alpine
container_name: plane-redis
restart: unless-stopped
volumes:
- redis-data:/data
networks:
- plane-network
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
# MinIO Object Storage
plane-minio:
image: minio/minio:latest
container_name: plane-minio
restart: unless-stopped
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: ${MINIO_ROOT_USER}
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}
volumes:
- minio-data:/data
networks:
- plane-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
# Plane API Backend
plane-api:
image: makeplane/plane-backend:latest
container_name: plane-api
restart: unless-stopped
<<: *app-env
depends_on:
plane-db:
condition: service_healthy
plane-redis:
condition: service_healthy
plane-minio:
condition: service_healthy
command: ./bin/docker-entrypoint-api.sh
volumes:
- logs-api:/code/plane/logs
networks:
- plane-network
# Plane Worker (Background Jobs)
plane-worker:
image: makeplane/plane-backend:latest
container_name: plane-worker
restart: unless-stopped
<<: *app-env
depends_on:
- plane-api
command: ./bin/docker-entrypoint-worker.sh
volumes:
- logs-worker:/code/plane/logs
networks:
- plane-network
# Plane Beat Scheduler
plane-beat-worker:
image: makeplane/plane-backend:latest
container_name: plane-beat-worker
restart: unless-stopped
<<: *app-env
depends_on:
- plane-api
command: ./bin/docker-entrypoint-beat.sh
volumes:
- logs-beat:/code/plane/logs
networks:
- plane-network
# Plane Web Frontend
plane-web:
image: makeplane/plane-frontend:latest
container_name: plane-web
restart: unless-stopped
environment:
- NEXT_PUBLIC_API_BASE_URL=http://plane-api:8000
depends_on:
- plane-api
ports:
- "3000:3000"
networks:
- plane-network
# Plane Space (Public pages)
plane-space:
image: makeplane/plane-space:latest
container_name: plane-space
restart: unless-stopped
environment:
- NEXT_PUBLIC_API_BASE_URL=http://plane-api:8000
depends_on:
- plane-api
ports:
- "4000:3000"
networks:
- plane-network
# Plane Admin
plane-admin:
image: makeplane/plane-admin:latest
container_name: plane-admin
restart: unless-stopped
environment:
- NEXT_PUBLIC_API_BASE_URL=http://plane-api:8000
depends_on:
- plane-api
ports:
- "8000:3000"
networks:
- plane-network
volumes:
postgres-data:
redis-data:
minio-data:
logs-api:
logs-worker:
logs-beat:
networks:
plane-network:
driver: bridge Step 5: Deploy Plane
# Pull all images
docker compose pull
# Start services
docker compose up -d
# Monitor startup logs
docker compose logs -f
# Wait for all services to be healthy (2-3 minutes)
# Press Ctrl+C when you see "Application startup complete"
# Verify all containers are running
docker compose ps All containers should show “Up” or “healthy” status.
Step 6: Initialize MinIO Bucket
# Create MinIO bucket for uploads
docker exec plane-minio mc alias set minio http://localhost:9000 ${MINIO_ROOT_USER} ${MINIO_ROOT_PASSWORD}
docker exec plane-minio mc mb minio/plane-uploads
docker exec plane-minio mc anonymous set download minio/plane-uploads Step 7: Access Plane
Navigate to http://YOUR-SERVER-IP:3000 in your browser.
Create your admin account:
- Click “Sign Up”
- Enter your email and password
- Set your full name
- Click “Create Account”
- You’ll be logged in automatically
Step 8: Create Your First Workspace
1. Click "Create Workspace"
2. Workspace Name: "My Company"
3. Workspace URL: "my-company" (unique identifier)
4. Click "Create"
5. You're now in your workspace! Initial Setup and Configuration
Create Your First Project
1. Click "Create Project" in sidebar
2. Project Details:
- Name: "Website Redesign"
- Identifier: "WEB" (appears on issues: WEB-1, WEB-2)
- Description: "Redesign company website"
- Network: Private (only team members)
3. Click "Create Project" Configure Project Settings
Navigate to Project Settings:
General Settings:
├─ Project Lead: Assign yourself
├─ Start Date: Set project start
├─ Target Date: Set deadline
└─ Cover Image: Upload project image
Features:
├─ Enable Cycles: Yes (for sprints)
├─ Enable Modules: Yes (for feature grouping)
├─ Enable Pages: Yes (for documentation)
└─ Enable Inbox: Yes (for issue triage)
States:
├─ Backlog (default)
├─ Todo
├─ In Progress
├─ Done
└─ Cancelled
(Customize as needed) Set Up Custom Labels
1. Project Settings → Labels
2. Create labels:
- bug (red)
- feature (blue)
- enhancement (green)
- documentation (yellow)
- high-priority (orange)
3. Save Configure Issue Priorities
Default priorities are:
- Urgent
- High
- Medium
- Low
- None
Customize in Project Settings → Priorities if needed.
User Management
Invite Team Members
1. Workspace Settings → Members
2. Click "Invite Members"
3. Enter email addresses (comma-separated)
4. Select role:
- Admin: Full workspace control
- Member: Can create projects
- Viewer: Read-only access
- Guest: Limited project access
5. Click "Send Invites" Project-Specific Roles
Add members to specific projects:
1. Open project
2. Project Settings → Members
3. Click "Add Members"
4. Select workspace members
5. Assign role:
- Admin: Full project control
- Member: Create and edit issues
- Viewer: Read-only
- Guest: Specific issue access
6. Save Create Teams
Organize members into teams:
1. Workspace Settings → Teams
2. Click "Create Team"
3. Team Name: "Backend Team"
4. Add members
5. Assign to projects
6. Save Working with Issues
Create Issues
1. Navigate to project
2. Click "New Issue" or press 'C'
3. Fill details:
- Title: "Add user authentication"
- Description: Use rich text or Markdown
- Assignee: Select team member
- Priority: High
- Labels: feature, backend
- Estimate: 5 (story points or hours)
- Start/Due dates
4. Click "Create Issue" Issue Views
Kanban View:
Drag and drop issues between columns (states)
Group by: Assignee, Priority, Labels, State
Perfect for visual workflow management List View:
Spreadsheet-like view
Bulk edit multiple issues
Filter and sort efficiently Calendar View:
See issues by due dates
Visualize deadlines
Plan sprint capacity Gantt View:
Timeline visualization
See dependencies
Track project progress Use Cycles (Sprints)
1. Click "Cycles" in sidebar
2. Click "Create Cycle"
3. Configure:
- Name: "Sprint 1"
- Start Date: 2025-01-20
- End Date: 2025-02-03
- Description: Sprint goals
4. Add issues to cycle:
- Drag from backlog
- Or assign in issue details
5. Monitor cycle progress:
- Burndown chart
- Velocity tracking
- Completion percentage Use Modules (Features/Epics)
1. Click "Modules" in sidebar
2. Create module:
- Name: "User Authentication"
- Description: "Complete auth system"
- Lead: Assign owner
- Start/Target dates
3. Add issues to module
4. Track progress
5. Link multiple cycles to one module Pages (Documentation)
1. Click "Pages" in sidebar
2. Create page:
- Title: "API Documentation"
- Content: Rich text or Markdown
- Add code blocks
- Embed images
- Link to issues
3. Organize in folders
4. Share with team Backup Procedures
What to Backup
| Component | Priority | Contains |
|---|---|---|
| PostgreSQL | Critical | All data: issues, projects, users |
| MinIO | Important | File attachments, images |
| .env file | Critical | Configuration and secrets |
| Redis | Optional | Cache only, can rebuild |
Automated Backup Script
Create ~/plane/backup.sh:
#!/bin/bash
# Configuration
BACKUP_DIR="/mnt/backups/plane"
DATE=$(date +%Y%m%d_%H%M%S)
RETENTION_DAYS=30
# Load environment
source ~/plane/.env
# Create backup directory
mkdir -p "$BACKUP_DIR"
echo "Starting Plane backup at $(date)"
# Backup PostgreSQL database
docker exec plane-db pg_dump -U plane plane | gzip > "$BACKUP_DIR/plane-db-${DATE}.sql.gz"
if [ $? -eq 0 ]; then
echo "Database backed up successfully"
else
echo "Database backup FAILED" >&2
exit 1
fi
# Backup MinIO data
docker run --rm -v plane_minio-data:/source:ro -v "$BACKUP_DIR":/backup alpine tar czf /backup/minio-data-${DATE}.tar.gz -C /source .
echo "MinIO data backed up"
# Backup environment file
cp ~/plane/.env "$BACKUP_DIR/env-${DATE}.txt"
# Create backup manifest
cat > "$BACKUP_DIR/manifest-${DATE}.txt" <<EOF
Plane Backup
Date: $(date)
Database: plane-db-${DATE}.sql.gz
MinIO: minio-data-${DATE}.tar.gz
Config: env-${DATE}.txt
EOF
# Clean old backups
find "$BACKUP_DIR" -name "*.gz" -mtime +$RETENTION_DAYS -delete
find "$BACKUP_DIR" -name "*.txt" -mtime +$RETENTION_DAYS -delete
echo "Backup completed at $(date)"
echo "Location: $BACKUP_DIR" Schedule daily backups:
chmod +x ~/plane/backup.sh
# Add to crontab
crontab -e
# Add: 0 2 * * * /home/user/plane/backup.sh >> /var/log/plane-backup.log 2>&1 Restore from Backup
# Stop Plane
cd ~/plane
docker compose down
# Restore database
gunzip < /mnt/backups/plane/plane-db-YYYYMMDD.sql.gz | docker exec -i plane-db psql -U plane plane
# Restore MinIO data
docker run --rm -v plane_minio-data:/dest -v /mnt/backups/plane:/backup alpine tar xzf /backup/minio-data-YYYYMMDD.tar.gz -C /dest
# Restore environment file
cp /mnt/backups/plane/env-YYYYMMDD.txt .env
# Start Plane
docker compose up -d
# Verify
docker compose logs -f Troubleshooting
Issue: Services Won’t Start
# Check logs for specific service
docker compose logs plane-api
docker compose logs plane-db
# Common fixes:
# 1. Database not ready
docker compose restart plane-db
sleep 30
docker compose restart plane-api
# 2. Port conflicts
sudo netstat -tlnp | grep :3000
# Change port in docker-compose.yml if needed
# 3. Permission issues
sudo chown -R $(id -u):$(id -g) ~/plane/data Issue: Can’t Upload Files
# Verify MinIO is running
docker compose ps plane-minio
# Check MinIO bucket
docker exec plane-minio mc ls minio/
# Recreate bucket if missing
docker exec plane-minio mc mb minio/plane-uploads
docker exec plane-minio mc anonymous set download minio/plane-uploads
# Restart API
docker compose restart plane-api Issue: Slow Performance
# Check resource usage
docker stats
# Increase PostgreSQL connections
# Edit docker-compose.yml:
# command: postgres -c 'max_connections=2000'
# Clear Redis cache
docker exec plane-redis redis-cli FLUSHDB
# Restart all services
docker compose restart Issue: Email Not Sending
# Test SMTP settings
docker exec plane-api python manage.py shell
# In Python shell:
from django.core.mail import send_mail
send_mail(
'Test Subject',
'Test message.',
'[email protected]',
['[email protected]'],
fail_silently=False,
)
# Check logs
docker compose logs plane-api | grep -i mail Issue: GitHub Integration Not Working
# Verify GitHub OAuth app settings:
# Homepage URL: http://YOUR-SERVER-IP:3000
# Callback URL: http://YOUR-SERVER-IP:3000/auth/github/callback
# Update .env with correct credentials
# Restart services
docker compose restart Advanced Configuration
Configure HTTPS with Reverse Proxy
Using Caddy:
Create Caddyfile:
plane.yourdomain.com {
reverse_proxy plane-web:3000
encode gzip
}
plane-api.yourdomain.com {
reverse_proxy plane-api:8000
encode gzip
} Update .env:
WEB_URL=https://plane.yourdomain.com
CORS_ALLOWED_ORIGINS=https://plane.yourdomain.com Enable GitHub Integration
# Create GitHub OAuth App:
# https://github.com/settings/developers
# Homepage: https://plane.yourdomain.com
# Callback: https://plane.yourdomain.com/auth/github/callback
# Add to .env:
GITHUB_CLIENT_ID=your_client_id
GITHUB_CLIENT_SECRET=your_client_secret
# Restart
docker compose restart Configure Webhooks
1. Project Settings → Webhooks
2. Click "Create Webhook"
3. URL: https://your-webhook-endpoint.com
4. Events to trigger:
- Issue created
- Issue updated
- Issue deleted
- Comment added
5. Save
6. Test webhook Conclusion
Plane provides enterprise-grade project management capabilities without the enterprise cost. With its modern interface, powerful features, and complete self-hosting, it’s the perfect solution for teams that want control over their project data.
What You’ve Accomplished:
- Deployed a full Plane instance with all microservices
- Configured PostgreSQL, Redis, and MinIO
- Set up workspaces and projects
- Implemented automated backups
- Configured user management
- Enabled advanced features
Next Steps:
- Import existing projects from Jira or Linear
- Set up GitHub/GitLab integration
- Configure custom workflows
- Create automation rules
- Set up analytics dashboards
- Train your team on Plane features
Start managing your projects with the power and flexibility that only self-hosting provides!