This guide shows you the steps to deploy a self-hosted instance of Plane using Kubernetes.

Install Plane

Plane One and Plane Pro are enabled on this edition, so the Free plan on this edition is easier to trial our paid plans from.

Prerequisites

  • A working Kubernetes cluster
  • kubectl and helm on the client system that you will use to install our Helm charts

Procedure

If you want to upgrade from Community to the Commercial edition, see Upgrade from Community.

  1. Open terminal or any other command-line app that has access to Kubernetes tools on your local system.

  2. Set the following environment variables:

    PLANE_VERSION=v1.3.2
    
    DOMAIN_NAME=<subdomain.domain.tld or domain.tld>
    
  3. Add the Plane helm chart repo.

    helm repo add plane https://helm.plane.so/
    
  4. Use one of the following ways to deploy Plane:

    • Quick setup:
      This is the fastest way to deploy Plane with the default settings. This will create stateful deployments for Postgres, Redis/Valkey, and Minio with a persistent volume claim using the longhorn storage class. This also sets up the Ingress routes for you using nginx ingress class. To customize these settings, see the Custom ingress routes.

    Run the following command to deploy Plane:

        helm install plane-app plane/plane-enterprise \
            --create-namespace \
            --namespace plane \
            --set license.licenseDomain=${DOMAIN_NAME} \
            --set license.licenseServer=https://prime.plane.so \
            --set planeVersion=${PLANE_VERSION} \
            --set ingress.enabled=true \
            --set ingress.ingressClass=nginx \
            --set env.storageClass=longhorn \
            --timeout 10m \
            --wait \
            --wait-for-jobs
    

    This is the minimum required to set up Plane Commercial edition. You can change the default namespace from plane, the default app name from plane-app, the default storage class from longhorn, and the default ingress class from nginx to whatever you would like to.

    You can also pass other settings referring to the Configuration Settings toggle section below.

    • Advanced setup:

      For more control over your setup, follow the steps below:

      1. Run the script below to download the values.yaml file and and edit using any editor like Vim or Nano.
      helm  show values plane/plane-enterprise > values.yaml
      vi values.yaml
      

      Make sure you set the required environment variables listed below:

      • planeVersion: v1.3.2
      • license.licenseDomain: <The domain you have specified to host Plane>
      • license.licenseServer: https://prime.plane.so
      • ingress.enabled: <true | false>
      • ingress.ingressClass: <nginx or any other ingress class configured in your cluster>
      • env.storageClass: <longhorn or any other storage class configured in your cluster>

      See the Configuration settings toggle section for more details.

      1. After saving the values.yaml file, run the following command to deploy Plane:
          helm install plane-app plane/plane-enterprise \
              --create-namespace \
              --namespace plane \
              -f values.yaml \
              --timeout 10m \
              --wait \
              --wait-for-jobs 
      

If you want to upgrade to a paid plan, see Plan upgrades.

Configuration settings

License

SettingDefaultRequiredDescription
planeVersionv1.3.2YesSpecifies the version of Plane to be deployed. Copy this from prime.plane.so.
license.licenseServerhttps://prime.plane.soYesSets the value of the licenseServer that gets you your license and validates it periodically. Don’t change this.
license.licenseDomain‘plane.example.com’YesThe fully-qualified domain name (FQDN) in the format sudomain.domain.tld or domain.tld that the license is bound to. It is also attached to your ingress host to access Plane.

Postgres

SettingDefaultRequiredDescription
services.postgres.local_setuptruePlane uses postgres as the primary database to store all the transactional data. This database can be hosted within kubernetes as part of helm chart deployment or can be used as hosted service remotely (e.g. aws rds or similar services). Set this to true when you choose to setup stateful deployment of postgres. Mark it as false when using a remotely hosted database
services.postgres.imageregistry.plane.tools/plane/postgres:15.5-alpineUsing this key, user must provide the docker image name to setup the stateful deployment of postgres. (must be set when services.postgres.local_setup=true)
services.postgres.servicePort5432This key sets the default port number to be used while setting up stateful deployment of postgres.
services.postgres.cliConnectPortIf you intend to access the hosted stateful deployment of postgres using any of the client tools (e.g Postico), this key helps you expose the port. The mentioned port must not be occupied by any other applicaiton
services.postgres.volumeSize2GiWhile setting up the stateful deployment, while creating the persistant volume, volume allocation size need to be provided. This key helps you set the volume allocation size. Unit of this value must be in Mi (megabyte) or Gi (gigabyte)
env.pgdb_usernameplaneDatabase credentials are requried to access the hosted stateful deployment of postgres. Use this key to set the username for the stateful deployment.
env.pgdb_passwordplaneDatabase credentials are requried to access the hosted stateful deployment of postgres. Use this key to set the password for the stateful deployment.
env.pgdb_nameplaneDatabase name to be used while setting up stateful deployment of Postgres
services.postgres.assign_cluster_ipfalseSet it to true if you want to assign ClusterIP to the service
env.pgdb_remote_urlUsers can also decide to use the remote hosted database and link to Plane deployment. Ignoring all the above keys, set services.postgres.local_setup to false and set this key with remote connection url.

Redis/Valkey Setup

SettingDefaultRequiredDescription
services.redis.local_setuptruePlane uses redis to cache the session authentication and other static data. This database can be hosted within kubernetes as part of helm chart deployment or can be used as hosted service remotely (e.g. aws rds or similar services). Set this to true when you choose to setup stateful deployment of redis. Mark it as false when using a remotely hosted database
services.redis.imageregistry.plane.tools/plane/valkey:7.2.5-alpineUsing this key, user must provide the docker image name to setup the stateful deployment of redis. (must be set when services.redis.local_setup=true)
services.redis.servicePort6379This key sets the default port number to be used while setting up stateful deployment of redis.
services.redis.volumeSize500MiWhile setting up the stateful deployment, while creating the persistant volume, volume allocation size need to be provided. This key helps you set the volume allocation size. Unit of this value must be in Mi (megabyte) or Gi (gigabyte)
services.redis.assign_cluster_ipfalseSet it to true if you want to assign ClusterIP to the service
env.remote_redis_urlUsers can also decide to use the remote hosted database and link to Plane deployment. Ignoring all the above keys, set services.redis.local_setup to false and set this key with remote connection url.

Doc Store (Minio/S3) Setup

SettingDefaultRequiredDescription
services.minio.local_setuptruePlane uses minio as the default file storage drive. This storage can be hosted within kubernetes as part of helm chart deployment or can be used as hosted service remotely (e.g. aws S3 or similar services). Set this to true when you choose to setup stateful deployment of minio. Mark it as false when using a remotely hosted database
services.minio.imageregistry.plane.tools/plane/minio:latestUsing this key, user must provide the docker image name to setup the stateful deployment of minio. (must be set when services.minio.local_setup=true)
services.minio.volumeSize3GiWhile setting up the stateful deployment, while creating the persistant volume, volume allocation size need to be provided. This key helps you set the volume allocation size. Unit of this value must be in Mi (megabyte) or Gi (gigabyte)
services.minio.root_useradminStorage credentials are requried to access the hosted stateful deployment of minio. Use this key to set the username for the stateful deployment.
services.minio.root_passwordpasswordStorage credentials are requried to access the hosted stateful deployment of minio. Use this key to set the password for the stateful deployment.
env.docstore_bucketuploadsYesStorage bucket name is required as part of configuration. This is where files will be uploaded irrespective of if you are using Minio or external S3 (or compatible) storage service
env.doc_upload_size_limit5242880YesDocument Upload Size Limit (default to 5Mb)
services.minio.assign_cluster_ipfalseSet it to true if you want to assign ClusterIP to the service
env.aws_access_keyExternal S3 (or compatible) storage service provides access key for the application to connect and do the necessary upload or download operations. To be provided when services.minio.local_setup=false
env.aws_secret_access_keyExternal S3 (or compatible) storage service provides secret access key for the application to connect and do the necessary upload or download operations. To be provided when services.minio.local_setup=false
env.aws_regionExternal S3 (or compatible) storage service providers creates any buckets in user selected region. This is also shared with the user as region for the application to connect and do the necessary upload or download operations. To be provided when services.minio.local_setup=false
env.aws_s3_endpoint_urlExternal S3 (or compatible) storage service providers shares a endpoint_url for the integration purpose for the application to connect and do the necessary upload or download operations. To be provided when services.minio.local_setup=false

Web Deployment

SettingDefaultRequiredDescription
services.web.replicas1YesKubernetes helps you with scaling up or down the deployments. You can run 1 or more pods for each deployment. This key helps you set up the number of replicas you want to run for this deployment. It must be >=1
services.web.memoryLimit1000MiEvery deployment in Kubernetes can be set to use the maximum memory they are allowed to use. This key sets the memory limit for this deployment to use.
services.web.cpuLimit500mEvery deployment in Kubernetes can be set to use the maximum cpu they are allowed to use. This key sets the cpu limit for this deployment to use.
services.web.imageregistry.plane.tools/plane/web-enterpriseThis deployment needs a preconfigured docker image to function. Docker image name is provided by the owner and must not be changed for this deployment
services.web.assign_cluster_ipfalseSet it to true if you want to assign ClusterIP to the service

Space Deployment

SettingDefaultRequiredDescription
services.space.replicas1YesKubernetes helps you with scaling up or down the deployments. You can run 1 or more pods for each deployment. This key helps you set up the number of replicas you want to run for this deployment. It must be >=1
services.space.memoryLimit1000MiEvery deployment in kubernetes can be set to use the maximum memory they are allowed to use. This key sets the memory limit for this deployment to use.
services.space.cpuLimit500mEvery deployment in kubernetes can be set to use the maximum cpu they are allowed to use. This key sets the cpu limit for this deployment to use.
services.space.imageregistry.plane.tools/plane/space-enterpriseThis deployment needs a preconfigured docker image to function. Docker image name is provided by the owner and must not be changed for this deployment
services.space.assign_cluster_ipfalseSet it to true if you want to assign ClusterIP to the service

Admin Deployment

SettingDefaultRequiredDescription
services.admin.replicas1YesKubernetes helps you with scaling up or down the deployments. You can run 1 or more pods for each deployment. This key helps you set up the number of replicas you want to run for this deployment. It must be >=1
services.admin.memoryLimit1000MiEvery deployment in kubernetes can be set to use the maximum memory they are allowed to use. This key sets the memory limit for this deployment to use.
services.admin.cpuLimit500mEvery deployment in kubernetes can be set to use the maximum cpu they are allowed to use. This key sets the cpu limit for this deployment to use.
services.admin.imageregistry.plane.tools/plane/admin-enterpriseThis deployment needs a preconfigured docker image to function. Docker image name is provided by the owner and must not be changed for this deployment
services.admin.assign_cluster_ipfalseSet it to true if you want to assign ClusterIP to the service

Live Service Deployment

SettingDefaultRequiredDescription
services.live.replicas1YesKubernetes helps you with scaling up/down the deployments. You can run 1 or more pods for each deployment. This key helps you setting up number of replicas you want to run for this deployment. It must be >=1
services.live.memoryLimit1000MiEvery deployment in kubernetes can be set to use maximum memory they are allowed to use. This key sets the memory limit for this deployment to use.
services.live.cpuLimit500mEvery deployment in kubernetes can be set to use maximum cpu they are allowed to use. This key sets the cpu limit for this deployment to use.
services.live.imageregistry.plane.tools/plane/live-enterpriseThis deployment needs a preconfigured docker image to function. Docker image name is provided by the owner and must not be changed for this deployment
env.live_sentry_dsn(optional) Live service deployment comes with some of the preconfigured integration. Sentry is one among those. Here user can set the Sentry provided DSN for this integration.
env.live_sentry_environment(optional) Live service deployment comes with some of the preconfigured integration. Sentry is one among those. Here user can set the Sentry environment name (as configured in Sentry) for this integration.
env.live_sentry_traces_sample_rate(optional) Live service deployment comes with some of the preconfigured integration. Sentry is one among those. Here user can set the Sentry trace sample rate (as configured in Sentry) for this integration.
services.live.assign_cluster_ipfalseSet it to true if you want to assign ClusterIP to the service

Monitor Deployment

SettingDefaultRequiredDescription
services.monitor.memoryLimit1000MiEvery deployment in kubernetes can be set to use the maximum memory they are allowed to use. This key sets the memory limit for this deployment to use.
services.monitor.cpuLimit500mEvery deployment in kubernetes can be set to use the maximum cpu they are allowed to use. This key sets the cpu limit for this deployment to use.
services.monitor.imageregistry.plane.tools/plane/monitor-enterpriseThis deployment needs a preconfigured docker image to function. Docker image name is provided by the owner and must not be changed for this deployment
services.monitor.volumeSize100MiWhile setting up the stateful deployment, while creating the persistant volume, volume allocation size need to be provided. This key helps you set the volume allocation size. Unit of this value must be in Mi (megabyte) or Gi (gigabyte)
services.monitor.assign_cluster_ipfalseSet it to true if you want to assign ClusterIP to the service

API Deployment

SettingDefaultRequiredDescription
services.api.replicas1YesKubernetes helps you with scaling up/down the deployments. You can run 1 or more pods for each deployment. This key helps you set up the number of replicas you want to run for this deployment. It must be >=1
services.api.memoryLimit1000MiEvery deployment in kubernetes can be set to use the maximum memory they are allowed to use. This key sets the memory limit for this deployment to use.
services.api.cpuLimit500mEvery deployment in kubernetes can be set to use the maximum cpu they are allowed to use. This key sets the cpu limit for this deployment to use.
services.api.imageregistry.plane.tools/plane/backend-enterpriseThis deployment needs a preconfigured docker image to function. Docker image name is provided by the owner and must not be changed for this deployment
env.sentry_dsn(optional) API service deployment comes with some of the preconfigured integration. Sentry is one among those. Here user can set the Sentry-provided DSN for this integration.
env.sentry_environment(optional) API service deployment comes with some of the preconfigured integration. Sentry is one among those. Here user can set the Sentry environment name (as configured in Sentry) for this integration.
services.api.assign_cluster_ipfalseSet it to true if you want to assign ClusterIP to the service

Worker Deployment

SettingDefaultRequiredDescription
services.worker.replicas1YesKubernetes helps you with scaling up or down the deployments. You can run 1 or more pods for each deployment. This key helps you set up the number of replicas you want to run for this deployment. It must be >=1
services.worker.memoryLimit1000MiEvery deployment in kubernetes can be set to use the maximum memory they are allowed to use. This key sets the memory limit for this deployment to use.
services.worker.cpuLimit500mEvery deployment in kubernetes can be set to use the maximum cpu they are allowed to use. This key sets the cpu limit for this deployment to use.

Beat-Worker deployment

SettingDefaultRequiredDescription
services.beatworker.replicas1YesKubernetes helps you with scaling up or down the deployments. You can run 1 or more pods for each deployment. This key helps you set up the number of replicas you want to run for this deployment. It must be >=1
services.beatworker.memoryLimit1000MiEvery deployment in kubernetes can be set to use the maximum memory they are allowed to use. This key sets the memory limit for this deployment to use.
services.beatworker.cpuLimit500mEvery deployment in kubernetes can be set to use the maximum cpu they are allowed to use. This key sets the cpu limit for this deployment to use.

Ingress and SSL Setup

SettingDefaultRequiredDescription
ingress.enabledtrueIngress setup in kubernetes is a common practice to expose the application to the intended audience. Set it to false if you are using an external ingress providers like Cloudflare
ingress.minioHost‘plane-services.minio.example.com’Based on the above configuration, if you want to expose the minio web console to a set of users, use this key to set the host mapping or leave it as EMPTY to not expose the interface.
ingress.ingressClass‘nginx’YesKubernetes cluster setup comes with various options of ingressClass. Based on your setup, set this value to the right one (eg. nginx, traefik, etc). Leave it to default in case you are using an external ingress provider.
ingress.ingress_annotations{ "nginx.ingress.kubernetes.io/proxy-body-size": "5m" }Ingress controllers come with various configuration options which can be passed as annotations. Setting this value lets you change the default value to user required.
ssl.createIssuerfalseKubernets cluster setup supports creating issuer type resource. After deployment, this is the step towards creating secure access to the ingress url. Issuer is required for you to generate SSL certificate. Kubernetes can be configured to use any certificate authority to generate SSL (depending on CertManager configuration). Set it to true to create the issuer. Applicable only when ingress.enabled=true
ssl.issuerhttpCertManager configuration allows user to create issuers using http or any of the other DNS Providers like cloudflare, digitalocean, etc. As of now, Plane supports http, cloudflare, digitalocean
ssl.tokenTo create issuers using DNS challenge, set the issuer api token of dns provider like cloudflareordigitalocean`(not required for http)
ssl.serverhttps://acme-v02.api.letsencrypt.org/directoryIssuer creation configuration needs the certificate generation authority server url. Default URL is the Let's Encrypt server
ssl.emailplane@example.comCertificate generation authority needs a valid email id before generating certificate. Required when ssl.createIssuer=true
ssl.generateCertsfalseAfter creating the issuers, the user can still not create the certificate until sure of the configuration. Setting this to true will try to generate SSL certificate and associate with ingress. Applicable only when ingress.enabled=true and ssl.createIssuer=true

Common Environment Settings

SettingDefaultRequiredDescription
env.storageClasslonghornCreating the persitant volumes for the stateful deployments needs the storageClass name. Set the correct value as per your kubernetes cluster configuration.
env.secret_key60gp0byfz2dvffa45cxl20p1scy9xbpf6d8c5y0geejgkyp1b5YesThis must be a random string which is used for hashing/encrypting the sensitive data within the application. Once set, changing this might impact the already hashed/encrypted data

Custom Ingress Routes

If you are planning to use 3rd party ingress providers, here is the available route configuration

HostPathService
plane.example.com/<http://plane-app-web.plane:3000>
plane.example.com/spaces/*<http://plane-app-space.plane:3000>
plane.example.com/god-mode/*<http://plane-app-admin.plane:3000>
plane.example.com/live/*<http://plane-app-live.plane:3000>
plane.example.com/api/*<http://plane-app-api.plane:8000>
plane.example.com/auth/*<http://plane-app-api.plane:8000>
plane.example.com/uploads/*<http://plane-app-minio.plane:9000>
plane-minio.example.com/<http://plane-app-minio.plane:9090>