# Docker and Kubernetes Deployment Architecture for Self-Hosting Plane

> Explore the Docker and Kubernetes deployment architecture for self-hosting Plane. Discover its microservices, background workers, and infrastructure components for seamless deployment.

- Repository: [Plane/plane](https://github.com/makeplane/plane)
- Tags: architecture
- Published: 2026-06-23

---

**Plane's self-hosted deployment uses a microservices architecture with five containerized application services (web, admin, space, api, live), three background workers (Celery, beat, migrator), and four infrastructure components (PostgreSQL, Valkey/Redis, RabbitMQ, MinIO), deployable via Docker Compose or the community Helm chart.**

The `makeplane/plane` repository provides complete infrastructure definitions for running the project management platform on your own servers. Whether you choose Docker Compose for single-node deployments or Kubernetes for orchestrated scaling, the **Docker and Kubernetes deployment architecture for self-hosting Plane** maintains identical service boundaries and environment variable contracts.

## Core Application Services

Plane splits its functionality across five distinct application services defined in the root [`docker-compose.yml`](https://github.com/makeplane/plane/blob/main/docker-compose.yml). Each service builds from a dedicated Dockerfile in the `apps/` directory.

**Frontend Services**

- **web** (`apps/web/Dockerfile.web`): The main React-based end-user interface serving the project management dashboard on port 80.
- **admin** (`apps/admin/Dockerfile.admin`): A separate React administration UI for system-level configuration.
- **space** (`apps/space/Dockerfile.space`): The React "Space" UI providing distinct workspace functionality.

**Backend Services**

- **api** (`apps/api/Dockerfile.api`): The Django REST API handling authentication, business logic, and CRUD operations. All frontend services depend on this component.
- **live** (`apps/live/Dockerfile.live`): A WebSocket server that pushes real-time updates to connected clients.

In Docker Compose, these services express startup dependencies using `depends_on` constraints. The Kubernetes Helm chart translates these into `PodAffinity` rules ensuring UI pods start only after the API pod reports readiness.

## Background Processing Layer

Asynchronous tasks run through Celery workers managed by three distinct deployment patterns:

- **worker** ([`./bin/docker-entrypoint-worker.sh`](https://github.com/makeplane/plane/blob/main/./bin/docker-entrypoint-worker.sh)): Standard Celery workers processing async jobs like file uploads and email notifications. In Kubernetes, this maps to a `Deployment` with configurable `replicas` for horizontal scaling.
- **beat-worker** ([`./bin/docker-entrypoint-beat.sh`](https://github.com/makeplane/plane/blob/main/./bin/docker-entrypoint-beat.sh)): The Celery beat scheduler for periodic tasks (cleanup, analytics). Deployed as a single-replica `Deployment`.
- **migrator** ([`./bin/docker-entrypoint-migrator.sh`](https://github.com/makeplane/plane/blob/main/./bin/docker-entrypoint-migrator.sh)): A one-shot database migration job that runs before application startup. In Kubernetes, this implements a `Job` resource that completes before the main services scale up.

All workers consume environment variables from the same `.env` file mounted at `env_file: - ./apps/api/.env` in the Compose configuration.

## Data and Infrastructure Stack

Plane requires four stateful infrastructure services for persistence, caching, and messaging:

| Service | Docker Image | Kubernetes Implementation | Purpose |
|---------|--------------|---------------------------|---------|
| **plane-db** | `postgres:15.7-alpine` | `StatefulSet` + `PersistentVolumeClaim` (`pgdata`) | Primary relational database for Django models |
| **plane-redis** | `valkey/valkey:7.2.11-alpine` | `StatefulSet` + PVC (`redisdata`) | Caching layer and Celery result backend |
| **plane-mq** | `rabbitmq:3.13.6-management-alpine` | `StatefulSet` + PVC (`rabbitmq_data`) | Message broker for Celery task queues |
| **plane-minio** | `minio/minio` | `Deployment` + PVC (`uploads`) | S3-compatible object storage for file uploads |
| **proxy** | Custom Nginx (`apps/proxy/Dockerfile.ce`) | `Deployment` + `Service` | Reverse proxy and TLS termination |

The infrastructure services reference a top-level `.env` file (lines 16-22 in [`docker-compose.yml`](https://github.com/makeplane/plane/blob/main/docker-compose.yml)) for credentials and connection strings. In Kubernetes, these values migrate to `ConfigMap` or `Secret` resources mounted as environment variables.

## Kubernetes Implementation with Helm

The community Helm chart located in `deployments/kubernetes/community` packages Plane for production Kubernetes clusters and publishes to Artifact Hub.

**Key Kubernetes Mappings**

Docker Compose services translate to specific workload controllers:

- **Stateless Applications** (`web`, `admin`, `space`, `api`, `live`): `Deployment` + `Service` (ClusterIP)
- **Background Workers**: `Deployment` with configurable `replicaCount`
- **Database Migrations**: `Job` (run-once)
- **Stateful Services** (PostgreSQL, Valkey, RabbitMQ): `StatefulSet` + `PersistentVolumeClaim`

The [`values.yaml`](https://github.com/makeplane/plane/blob/main/values.yaml) file in the Helm chart mirrors the Docker Compose environment variables, allowing operators to configure `POSTGRES_USER`, `POSTGRES_PASSWORD`, `AWS_ACCESS_KEY_ID`, and other secrets while tuning resource limits and replica counts.

**Networking and Ingress**

In Docker environments, all containers share a single Docker network with the `proxy` container exclusively exposing ports 80 and 443. The Kubernetes chart creates a `Service` of type `LoadBalancer` (or `NodePort` for on-premises clusters) for the proxy deployment. An optional `Ingress` resource enables hostname-based routing to distinct UI services.

**Persistence Configuration**

Each stateful component mounts specific PVCs that survive pod restarts:

- PostgreSQL mounts `pgdata` at `/var/lib/postgresql/data`
- Valkey mounts `redisdata` at `/data`
- RabbitMQ mounts `rabbitmq_data` at `/var/lib/rabbitmq`
- MinIO mounts `uploads` at `/export`

All PVCs specify `storageClassName` matching the cluster's default storage class.

## Architecture Flow and Request Path

Understanding the request flow clarifies how components interact in the **Docker and Kubernetes deployment architecture for self-hosting Plane**:

1. **Ingress/Load Balancer** receives external HTTPS traffic and routes to the `proxy` service.
2. **Proxy** terminates TLS and path-routes requests to `web`, `admin`, or `space` services based on URL patterns.
3. **UI Services** call the `api` service for authentication, data access, and business logic operations.
4. **API** persists data to **PostgreSQL**, caches in **Valkey/Redis**, queues tasks to **RabbitMQ**, and stores files in **MinIO**.
5. **Live** service subscribes to RabbitMQ topics and pushes real-time updates via WebSockets to connected clients.
6. **Celery Workers** consume background jobs from RabbitMQ (e.g., processing file uploads, sending notifications).
7. **Beat Worker** schedules periodic maintenance tasks like cleanup and analytics aggregation.

## Summary

- Plane's architecture consists of **five application containers** (web, admin, space, api, live), **three worker types** (Celery, beat, migrator), and **four infrastructure services** (PostgreSQL 15.7, Valkey 7.2, RabbitMQ 3.13, MinIO).
- The reference implementation uses [`docker-compose.yml`](https://github.com/makeplane/plane/blob/main/docker-compose.yml) at the repository root, while production Kubernetes deployments use the community Helm chart in `deployments/kubernetes/community`.
- Stateful services require `PersistentVolumeClaims` with `pgdata`, `redisdata`, `rabbitmq_data`, and `uploads` volumes to ensure data persistence.
- The `proxy` container (Nginx) handles external traffic, TLS termination, and internal routing to UI and API services.
- Environment configuration is unified through `.env` files in Docker and `ConfigMap`/`Secret` resources in Kubernetes.

## Frequently Asked Questions

### What hardware requirements are needed to self-host Plane?

A minimal production deployment requires 4 vCPU cores and 8GB RAM to run the core services, PostgreSQL, and Redis comfortably. The Kubernetes Helm chart allows resource limits to be tuned per-component in [`values.yaml`](https://github.com/makeplane/plane/blob/main/values.yaml), while Docker Compose deployments should ensure the host has sufficient resources for all defined services.

### How do I scale background workers in the Kubernetes deployment?

Modify the `replicaCount` value for the `plane-worker` deployment in the Helm chart's [`values.yaml`](https://github.com/makeplane/plane/blob/main/values.yaml) file. The worker deployment uses the same `apps/api/Dockerfile.api` image but executes [`./bin/docker-entrypoint-worker.sh`](https://github.com/makeplane/plane/blob/main/./bin/docker-entrypoint-worker.sh) to process Celery tasks. Horizontal scaling adds parallel job processing capacity without affecting the beat-worker or migrator jobs.

### Can I use external PostgreSQL or Redis instead of the containerized versions?

Yes. Both the Docker Compose file and Helm chart support external data sources. Remove the `plane-db` and `plane-redis` service definitions from Docker Compose, or set `enabled: false` for these components in the Helm [`values.yaml`](https://github.com/makeplane/plane/blob/main/values.yaml). Configure the `DATABASE_URL` and `REDIS_URL` environment variables to point to your external managed services.

### What is the difference between the Docker Compose and Kubernetes networking models?

Docker Compose creates an isolated bridge network where all containers communicate via internal DNS names, with only the `proxy` service exposing ports 80/443 to the host. Kubernetes uses ClusterIP services for internal communication, optionally exposing the proxy via LoadBalancer or NodePort services, and supports Ingress resources for HTTP/HTTPS routing based on hostnames and path prefixes.