DockerSelf-Hosting

Plane with Docker: self-hosted project management, a Jira alternative (Linux, Windows, Mac)

Before you start

  • 20 min read

Boxes marked Run in terminal are what you type; plain text explains why. Check what you need first

What you get in one minute#

Plane is an open-source project management tool for tracking work items, running cycles (sprints) and planning roadmaps, and its Community Edition is free to run on your own server with Docker.

Plane official logo

Logo: the official Plane project (github.com/makeplane/plane)

The README calls it an open-source tool to "track issues, run cycles, and manage product roadmaps". People use it where they might use Jira, but with the data on their own machine. This guide installs the free Community Edition. A closed-source Commercial Edition also exists, explained below.

WhatValue (official docs and release files, read November 2026)
Current versionPlane v1.4.3, released October 2026 (marked "Latest" on GitHub)
Imagesmakeplane/plane-frontend, plane-backend, plane-proxy, plane-admin, plane-space, plane-live, all tag v1.4.3 (amd64 and arm64, checked on Docker Hub)
Time neededAbout 20 minutes by the docs' own estimate; plan 40 minutes with HTTPS
Size and RAMDocs ask for 2 CPU cores and 4 GB RAM (8 GB recommended for production). No idle RAM figure is published
Ports80 and 443 (the bundled proxy); the database, queue and storage publish no host port
LicenceCommunity Edition: AGPL-3.0 (LICENSE.txt at the release tag). Commercial Edition: closed source
Official docsdevelopers.plane.so/self-hosting and the repository

Screenshot of Plane showing a work-item board with Blocked, Planning and Permits awaited columns above a timeline with linked tasks

Image: the official Plane project (README at v1.4.3)

At a glance:

  • What it is: a multi-container web app (web, API, workers, Postgres, queue, cache, file storage). The official script starts all of it.
  • What you get: work items, cycles, modules, saved views, pages and analytics (the README's feature list).
  • Community vs Commercial: Community is AGPL-3.0 and free. Commercial is closed-source and adds paid plans. The docs' main Docker page installs Commercial by default, so read the next section first.
  • Two secrets to change: SECRET_KEY and LIVE_SERVER_SECRET_KEY ship with placeholder values. A fresh install can crash-loop until you change them (open issue #9525).
  • Alive and maintained: not archived, not renamed. The docs moved to developers.plane.so. v1.4.3 fixes access-control bugs, and the release says self-hosted instances should upgrade.
  • Platforms: the server runs on Linux, Mac (Docker Desktop) or Windows with WSL2, per the docs' OS list. We tested none of these on this page.

How it fits together#

Your browser reaches one proxy, which sends each path to the right Plane app. Everything saves to Postgres, a queue and an object store in Docker volumes.

Two-lane diagram: you open https://plane.your-domain in a browser, an optional Caddy or Traefik front door forwards over HTTPS to the Plane proxy, which routes by path to the web, admin, space, live and api apps; the apps read and write Postgres, queue jobs in RabbitMQ and Valkey that the worker picks up, and upload files to MinIO storage

Drawn for this guide from the official compose file and architecture docs. The dashed Caddy or Traefik box is the optional HTTPS route.

Before you start#

Community or Commercial?#

Plane's docs separate the edition (the code you run) from the plan (the features a licence key unlocks).

CommunityCommercialAirgapped
Source codeOpen, AGPL-3.0ClosedClosed
CostFree, no keyFree plan: 12 seats per workspace; paid plans need a licence keyEnterprise Grid only, through sales
FeaturesSame as the Cloud Free tierSame as CloudSame as Commercial, works offline
Installsetup.sh from GitHub (this guide)curl -fsSL https://prime.plane.so/install/ | sh - (Prime CLI)Special package
Release cycleIts own codebase, features arrive lastShips with Cloud's features soonerSame as Commercial

Pick Community if you want open code you can audit and no licence server. Pick Commercial if you need paid-plan features. Moving from Community to Commercial later is a documented path, and the docs say there are no forced migrations.

Tip: AGPL-3.0 means: if you change Plane and let other people use your changed copy over a network, you must offer them your changes. Running it unchanged for your own team asks nothing extra.

What you need#

Linux server: 2 CPU cores, 4 GB RAM (8 GB for production), Docker Engine and Docker Compose v2, curl and openssl. The Community docs name an AWS t3.medium (2 vCPU, 4 GB) as the minimum. Check:

Run in terminalbash
docker --version
docker compose version
curl --version | head -1

Windows: the docs list "Windows with WSL2" (the Community steps also mention Git Bash). This guide uses Ubuntu in WSL2 with Docker Desktop's WSL integration. Check:

Run in terminalpowershell
docker --version
wsl -l -v

Mac: Docker Desktop. Check in Terminal:

Run in terminalbash
docker --version
docker compose version

Checklist:

  • [ ] 2 cores and 4 GB RAM free for Plane (8 GB if several people will use it)
  • [ ] Docker Compose v2: docker compose version works (the docs say old docker-compose causes errors)
  • [ ] Ports 80 and 443 free, or ready to change them in plane.env
  • [ ] A backup place that is not this machine
  • [ ] For the HTTPS section only: a domain name with a DNS record pointing at the server

Tested by DIY Lab Hub: not yet. Every command comes from the official setup.sh, docker-compose.yml, variables.env and docs at release v1.4.3, read in November 2026. We did not run them.

Step 1: Create the folder#

Plane's script creates a plane-app folder next to itself, and everything it manages lives there. Data stays in Docker volumes that the script backs up. We put the install under ~/docker_volumes/plane, like all DIY Lab Hub guides.

Linux#

Run in terminalbash
mkdir -p ~/docker_volumes/plane
cd ~/docker_volumes/plane

Windows (PowerShell)#

Open Ubuntu in WSL2 (install it once with wsl --install -d Ubuntu), then run the Linux commands inside it. Keep the folder in the Ubuntu home directory.

Run in terminalpowershell
wsl -d Ubuntu

Mac (Terminal)#

Same commands as Linux:

Run in terminalbash
mkdir -p ~/docker_volumes/plane
cd ~/docker_volumes/plane

Check it worked. pwd prints a path ending in docker_volumes/plane.

Tip: Always run setup.sh from this folder. The script builds its paths from the folder you are in, so running it elsewhere creates a second, empty plane-app and looks like a lost database.

Step 2: Download the official script and install#

The official Community route is the setup.sh file attached to each GitHub release. The script asks GitHub for the latest release, downloads that release's docker-compose.yml and variables.env, and pulls the images.

Linux#

Run in terminalbash
cd ~/docker_volumes/plane
curl -fsSL -o setup.sh https://github.com/makeplane/plane/releases/latest/download/setup.sh
chmod +x setup.sh
./setup.sh install

The docs show the same actions as a menu (run ./setup.sh, choose 1 for Install). The script also accepts the word install, start, stop, restart, upgrade, logs or backup.

Windows (PowerShell)#

Run the Linux commands inside the Ubuntu window from Step 1. From PowerShell you can also call them without opening a shell:

Run in terminalpowershell
wsl -d Ubuntu -- bash -lc "cd ~/docker_volumes/plane && curl -fsSL -o setup.sh https://github.com/makeplane/plane/releases/latest/download/setup.sh && chmod +x setup.sh && ./setup.sh install"

Mac (Terminal)#

Same commands as Linux. The script has a branch for macOS.

Run in terminalbash
cd ~/docker_volumes/plane
curl -fsSL -o setup.sh https://github.com/makeplane/plane/releases/latest/download/setup.sh
chmod +x setup.sh
./setup.sh install

Check it worked. The script ends with "Most recent version of Plane is now available for you to use" (from the script source). Then check the version it chose:

Run in terminalbash
ls plane-app
grep '^APP_RELEASE=' plane-app/plane.env

You should see docker-compose.yaml, plane.env and archive, and APP_RELEASE=v1.4.3. If a newer release is out when you read this, read its notes before you carry on. This guide was checked against v1.4.3.

Tip: The script finds the latest release through the GitHub API without a login. If that lookup fails it stops with "Failed to check for the latest release". Wait a few minutes (rate limit) and run it again.

Step 3: Set the secret keys and the address#

plane.env is the one file you edit. Two values are placeholders in the official file, which says "change this before deploying to production".

Linux#

Run in terminalbash
cd ~/docker_volumes/plane/plane-app
sed -i "s|^SECRET_KEY=.*|SECRET_KEY=$(openssl rand -hex 32)|" plane.env
sed -i "s|^LIVE_SERVER_SECRET_KEY=.*|LIVE_SERVER_SECRET_KEY=$(openssl rand -hex 32)|" plane.env
chmod 600 plane.env
grep -c 'change-this-key' plane.env

The last command should print 0. We use openssl rand -hex 32 because the official file suggests it, and because the script reads values by splitting on =, so a key with an = inside breaks.

Then set the address people will type. For a first test on the same machine keep the defaults (http://localhost). For other computers on your network, edit these two lines to the same value, for example http://<server-ip>:

File contenttext
WEB_URL=http://<server-ip>
CORS_ALLOWED_ORIGINS=http://<server-ip>

Windows (PowerShell)#

Run the Linux block inside Ubuntu (WSL2). The file is ~/docker_volumes/plane/plane-app/plane.env in the Ubuntu home. To open it from PowerShell:

Run in terminalpowershell
wsl -d Ubuntu -- nano ~/docker_volumes/plane/plane-app/plane.env

Mac (Terminal)#

macOS sed needs an empty backup suffix after -i:

Run in terminalbash
cd ~/docker_volumes/plane/plane-app
sed -i '' "s|^SECRET_KEY=.*|SECRET_KEY=$(openssl rand -hex 32)|" plane.env
sed -i '' "s|^LIVE_SERVER_SECRET_KEY=.*|LIVE_SERVER_SECRET_KEY=$(openssl rand -hex 32)|" plane.env
chmod 600 plane.env
grep -c 'change-this-key' plane.env

Check it worked. grep -c 'change-this-key' plane.env prints 0.

Tip: Never paste plane.env into a chat or an issue: it now holds your secret keys. Share only the variable names.

The internal database, queue and storage passwords stay at the defaults in the official file. No host port is published for them (checked in the compose file), so only containers on Plane's own network can reach them. To change them, follow the docs for external services; editing one password alone can break the connection strings.

Step 4: Start Plane#

Linux#

Run in terminalbash
cd ~/docker_volumes/plane
./setup.sh start

The script pulls images, waits for the migrator to finish, then waits for the API. The first start takes several minutes. It ends with "You can access the application at" followed by your WEB_URL.

Windows (PowerShell)#

Run in terminalpowershell
wsl -d Ubuntu -- bash -lc "cd ~/docker_volumes/plane && ./setup.sh start"

Mac (Terminal)#

Same commands as Linux:

Run in terminalbash
cd ~/docker_volumes/plane
./setup.sh start

Check it worked. All containers are up and the proxy answers:

Run in terminalbash
docker ps --format 'table {{.Names}}\t{{.Status}}'
curl -I http://localhost

Expect containers named plane-app-... for web, space, admin, live, api, worker, beat-worker, plane-db, plane-redis, plane-mq, plane-minio and proxy (the service list in the v1.4.3 compose file; the docs' sample output is older). The migrator container runs once and then exits. curl prints an HTTP status line instead of "connection refused".

Tip: If the script says "API Service did not respond to health-check", do not wait for hours. Read ./setup.sh logs and see Troubleshooting. The most common cause on a new install is a placeholder secret key.

Step 5: Create the admin account and your first project#

Linux#

Open http://localhost (or your WEB_URL) in a browser. Plane shows "Let's secure your instance": enter an email and password for the instance admin. Then create a workspace and a project.

Run in terminalbash
xdg-open http://localhost

Windows (PowerShell)#

Codepowershell
Start-Process "http://localhost"

Mac (Terminal)#

Run in terminalbash
open http://localhost

Next, visit /god-mode (append it to your address). This is the instance admin area. The docs recommend setting up SMTP there so invitations work. Under Authentication you can switch off "Allow anyone to sign up without an invite", and under General switch off "Let Plane collect anonymous usage data".

Check it worked. You can sign in, create a workspace and a project, add a work item, and see it on a board.

Tip: Store the admin password in a password manager now. The docs' reset page needs shell access to the server.

Put it behind HTTPS (with or without Traefik)#

The bundled proxy serves plain HTTP on port 80 by default (SITE_ADDRESS=:80). For a server people reach from outside, put HTTPS in front. Home-only users can stay on HTTP on a trusted network. Both routes below need a domain with a DNS record pointing at the server and ports 80 and 443 reachable.

The official Community docs say: disable the bundled proxy service, put your proxy on the same Docker network (usually plane-app_default), and route paths to the containers. Plane's own table:

PathContainerPort
/* (everything else)web3000
/spaces/*space3000
/god-mode/*admin3000
/live/*live3000
/api/*, /auth/*, /static/*api8000
/uploads/* (your bucket name)plane-minio9000

Edit the compose file first. In ~/docker_volumes/plane/plane-app/docker-compose.yaml, delete the whole proxy: service (the block under the comment "Comment this if you already have a reverse proxy running"). Then set the real address in plane.env:

File contenttext
WEB_URL=https://plane.example.com
CORS_ALLOWED_ORIGINS=https://plane.example.com

Tip: ./setup.sh upgrade replaces docker-compose.yaml with the new release's file and moves your edited one to plane-app/archive/<timestamp>.docker-compose.yaml. After every upgrade, repeat your proxy edits. Keep a copy of your edited file somewhere safe.

With Traefik#

On a server that already runs Traefik v3 with the Docker provider, add the official labels and join the shared network.

This assumes an external Docker network proxy and an entrypoint named https (use your own names). Create the network once:

Run in terminalbash
docker network create proxy

Add this to each of web, api, admin, space, live and plane-minio in docker-compose.yaml. Plane's official labels (shown for web and api) set the router and port; we add the entrypoint, TLS and network lines. Keep default in the list so the service still reaches Plane's other containers:

File contentyaml
  web:
    networks:
      - default
      - proxy
    labels:
      - "traefik.enable=true"
      - "traefik.docker.network=proxy"
      - "traefik.http.routers.plane-web.rule=Host(`plane.example.com`)"
      - "traefik.http.routers.plane-web.entrypoints=https"
      - "traefik.http.routers.plane-web.tls=true"
      - "traefik.http.services.plane-web.loadbalancer.server.port=3000"
  api:
    networks:
      - default
      - proxy
    labels:
      - "traefik.enable=true"
      - "traefik.docker.network=proxy"
      - "traefik.http.routers.plane-api.rule=Host(`plane.example.com`) && (Path(`/api`) || PathPrefix(`/api/`) || Path(`/auth`) || PathPrefix(`/auth/`) || Path(`/static`) || PathPrefix(`/static/`))"
      - "traefik.http.routers.plane-api.entrypoints=https"
      - "traefik.http.routers.plane-api.tls=true"
      - "traefik.http.services.plane-api.loadbalancer.server.port=8000"

Do the same for the other four services with these rules and ports (from the official page):

RouterRule after Host(...)Port
plane-adminPath(/god-mode) or PathPrefix(/god-mode/)3000
plane-spacePath(/spaces) or PathPrefix(/spaces/)3000
plane-livePath(/live) or PathPrefix(/live/)3000
plane-minioPath(/uploads) or PathPrefix(/uploads/)9000

At the bottom of the file add the network:

File contentyaml
networks:
  proxy:
    external: true

Apply it with ./setup.sh restart.

Check it worked. curl -I https://plane.example.com/ returns an HTTP status line over HTTPS, and the browser shows a valid certificate.

Without Traefik: Caddy#

Choose this if you have no Traefik. Caddy gets and renews its own certificates.

Caddy's docs describe automatic Let's Encrypt certificates for a public domain and tls internal for a local certificate at home. See also our Caddy guide. Start Plane first, so its network plane-app_default exists (check with docker network ls). Create the Caddy folders, mounting the conf folder, not a single file:

Run in terminalbash
mkdir -p ~/docker_volumes/caddy/{conf,data,config}
cd ~/docker_volumes/caddy

Save as ~/docker_volumes/caddy/docker-compose.yml. The image is caddy:2.11.8, the newest tag we found on Docker Hub in November 2026:

File contentyaml
services:
  caddy:
    image: caddy:2.11.8
    container_name: caddy
    restart: unless-stopped
    ports:
      - "80:80/tcp"
      - "443:443/tcp"
      - "443:443/udp"
    volumes:
      - ./conf:/etc/caddy
      - ./data:/data
      - ./config:/config
    networks:
      - plane

networks:
  plane:
    external: true
    name: plane-app_default

Save as ~/docker_volumes/caddy/conf/Caddyfile, Plane's official Caddy template with your domain:

File contenttext
plane.example.com {
    request_body {
        max_size 50MB
    }

    redir /spaces /spaces/ permanent
    reverse_proxy /spaces/* space:3000

    redir /god-mode /god-mode/ permanent
    reverse_proxy /god-mode/* admin:3000

    reverse_proxy /live/* live:3000
    reverse_proxy /api/* api:8000
    reverse_proxy /auth/* api:8000
    reverse_proxy /static/* api:8000

    reverse_proxy /uploads/* plane-minio:9000
    reverse_proxy /uploads plane-minio:9000

    reverse_proxy /* web:3000
}

For a home-only name, add tls internal as the first line inside the block (for example plane.home.arpa). Caddy then uses its own local certificate, and each device must trust Caddy's root certificate once (the steps are in our Caddy guide). Then start it:

Run in terminalbash
docker compose up -d

Windows and Mac are clients here: you only open the https address in a browser.

Check it worked. curl -I https://plane.example.com/ returns an HTTP status line over HTTPS. For tls internal the browser shows a padlock only after the root is trusted.

Tip: Plane's bundled proxy is also Caddy, and its Caddyfile.ce reads SITE_ADDRESS and CERT_EMAIL from plane.env. Setting those can give a Let's Encrypt certificate without a second Caddy. We read this in the file only; the official SSL page covers the Commercial Edition, and we did not run it.

Security and testing#

ControlHow
Secret keysChange SECRET_KEY and LIVE_SERVER_SECRET_KEY (Step 3); chmod 600 plane.env
Sign-upIn /god-mode, switch off "Allow anyone to sign up without an invite" for a private team
Sign-in limitsv1.4.3 rate-limits email and password sign-in; the release notes list it as a security fix
PortsOnly the proxy publishes 80 and 443. Postgres, RabbitMQ, Valkey and storage publish none
FirewallAllow 80 and 443 only, for example sudo ufw allow 80,443/tcp (ufw is one example)
Updatesv1.4.3 fixed several access-control bugs; the notes say self-hosted instances should upgrade
TelemetryThe docs say Plane collects the instance admin's name and email, an instance ID and anonymised usage data; switch it off in God mode
BackupsThe backup folder holds your whole database: keep it private (chmod 700)

Quick tests after each change:

Run in terminalbash
cd ~/docker_volumes/plane
docker ps --format 'table {{.Names}}\t{{.Status}}'
./setup.sh logs
curl -I https://plane.example.com/

On Windows run the first two inside Ubuntu; curl.exe -I https://plane.example.com/ works in PowerShell.

Common mistakes#

These come from the official issue tracker, the docs' own warnings and the setup script.

MistakeWhy it happensDo this instead
Leaving SECRET_KEY as change-this-key-on-deploymentThe placeholder is in the official variables.env. Issue #9525 (open, October 2026) reports the API container in a reboot loop until it was changed, and the docs page does not say soSet both keys with openssl rand -hex 32 before the first start (Step 3)
Keeping WEB_URL=http://localhost on a real serverIt is the default. Links, redirects and CORS use itSet WEB_URL and CORS_ALLOWED_ORIGINS to the exact address people type
A proxy that does not send X-Forwarded-ProtoUpload links then come back as http://. Issue #5827 (closed) was fixed by adding the forwarded headersUse the official Caddy or Traefik setup; with other proxies pass the forwarded headers
Upgrading without a backupFailures happen: issue #8176 (open) reports a migrator loop after 0.15.1 to 1.3.0, and #6455 (closed) reports lost contentRun ./setup.sh backup and copy plane.env first
Editing docker-compose.yaml and then running upgradeThe script moves your file to archive/ and downloads a fresh oneRe-apply your proxy edits after each upgrade
Using a database on localhostInside the container, localhost is the container itself. The docs list plane-migrator-1 container exited with status 1 for thisUse an address the container can reach
Running an old docker-composeThe docs list "Error during docker compose execution" for permission problems and old ComposeUse Docker Compose v2 and sudo or the docker group
Running setup.sh from another folderThe script creates plane-app beside itselfcd ~/docker_volumes/plane first
Installing Commercial when you wanted CommunityThe main Docker Compose docs page installs Commercial with the Prime CLIUse setup.sh from the GitHub release (Step 2)
AI assistants: telling you to run sudo prime-cli upgrade or prime-cli backupThese are Commercial tools; the docs say they only work on instances installed with prime-cliOn Community use ./setup.sh upgrade and ./setup.sh backup
AI assistants: copying an old compose file from the deploy/selfhost path or a v0.x guideOlder paths and images appear in old answers (issue #7178 links one)Use the compose file and variables.env attached to the release

Tip: Read the compose file you actually run before you ask a chatbot about it. Check the image names (makeplane/plane-frontend, plane-backend, plane-proxy) and the tag against the release page.

Tip: After any change run ./setup.sh logs and pick the service. Most errors print there with their exact text.

Tip: Test your backup on a spare machine before you need it. An untested backup is a guess.

Troubleshooting#

ProblemSolution
API container restarts in a loop on a fresh installCheck the log for the "SECRET_KEY is set to a known insecure or placeholder value" warning; set a real SECRET_KEY in plane.env, then ./setup.sh restart (issue #9525)
Failed to check for the latest release. Exiting...The script could not read GitHub's release API (a rate limit, for example). Wait and rerun; v1.4.3 made the lookup stop with an error
"Waiting for API Service to Start" for 300 sRun ./setup.sh logs for api and migrator. Reports exist after restore (issue #7178) and after big upgrades (#8176)
plane-migrator-1 container exited with status 1An external database set to localhost; use a reachable address (official docs)
Page says Plane cannot start because a service did not startRead the api and migrator logs; check WEB_URL and that all containers are up
Uploads fail or go to http:// behind HTTPSPass X-Forwarded-Proto, set WEB_URL to https and try MINIO_ENDPOINT_SSL=1 (docs: "Force HTTPS for MinIO when dealing with SSL termination")
setup.sh fails on SynologyIssue #8714 (open): one user removed --policy always from the pull line, which is a workaround we did not test
Podmansetup.sh is not compatible with podman-compose (issue #6679, closed); the docs have a separate Podman page

Known bugs (open, November 2026)#

  • Issue #9525: the docs do not mention the placeholder secret key. The same report describes missing proxy and live variables in v1.3.1; the v1.4.3 compose file we read passes them.
  • Issue #8176: migrator loops after an upgrade from 0.15.1. One commenter renamed a mis-cased Postgres table; that is a community workaround, not official advice.
  • Issue #8390: CORS_ALLOWED_ORIGINS reported as ignored, with the app host used instead.

Diagnostics:

Run in terminalbash
cd ~/docker_volumes/plane
docker ps --format 'table {{.Names}}\t{{.Status}}'
docker compose -f plane-app/docker-compose.yaml --env-file plane-app/plane.env ps
./setup.sh logs

Updates and backups#

Back up first. The official script copies the Postgres, file-storage, RabbitMQ and Valkey data into plane-app/backup/<date>:

Run in terminalbash
cd ~/docker_volumes/plane
./setup.sh backup
cp plane-app/plane.env plane-app/backup/plane.env.$(date +%F)
chmod -R go-rwx plane-app/backup

The script copies files out of the running database container. For a second, safer copy of the database, add a standard Postgres dump (our addition, not in Plane's docs; user and database are both plane in the official file):

Run in terminalbash
docker compose -f plane-app/docker-compose.yaml --env-file plane-app/plane.env exec -T plane-db pg_dump -U plane plane | gzip > plane-app/backup/plane-db-$(date +%F).sql.gz

Update. Read the release notes, then:

Run in terminalbash
cd ~/docker_volumes/plane
curl -fsSL -o setup.sh https://github.com/makeplane/plane/releases/latest/download/setup.sh
./setup.sh upgrade

It stops the services and downloads the new files; your plane.env is not overwritten. Compare plane-app/variables-upgrade.env with plane.env, copy any new variables across, re-apply your proxy edits, then ./setup.sh start.

Schedule (Linux and Mac). A nightly 03:00 backup in crontab -e. TERM is set because the script clears the screen:

File contentbash
0 3 * * * cd $HOME/docker_volumes/plane && TERM=xterm ./setup.sh backup >> backup.log 2>&1

Windows (PowerShell). Use Task Scheduler to run this once a day:

Run in terminalpowershell
wsl -d Ubuntu -- bash -lc "cd ~/docker_volumes/plane && TERM=xterm ./setup.sh backup"

Restore test. The official restore script needs jq. Stop Plane, download it next to setup.sh, point it at a backup folder with the *.tar.gz files, then start:

Run in terminalbash
cd ~/docker_volumes/plane
./setup.sh stop
curl -fsSL -o restore.sh https://github.com/makeplane/plane/releases/download/v1.4.3/restore.sh
chmod +x restore.sh
./restore.sh plane-app/backup/<date>
./setup.sh start

Practise this on a spare machine, not the live one: it replaces the current volumes. Issue #7178 reports a restore followed by a stuck start.

Performance and resources#

The docs give no measured idle RAM, and we ran nothing, so we publish none. What they do say:

  • Minimum: 2 CPU cores and 4 GB RAM; 8 GB recommended for production.
  • Measure yours: docker stats --no-stream lists every container.
  • Replicas: plane.env has WEB_REPLICAS, API_REPLICAS, WORKER_REPLICAS and others, all 1. The compose file sets GUNICORN_WORKERS to 1 directly.
  • Uploads: FILE_SIZE_LIMIT defaults to 5 MB (5242880 bytes).
  • Production advice from the docs: use an external database and storage, so a machine failure does not take your data with it.

FAQ#

Is Plane free to self-host? The Community Edition is: it is AGPL-3.0, with no licence key. The Commercial Edition has a free plan of 12 seats per workspace, and paid plans need a licence key.

Is Plane dead, archived or renamed? No. The repository is active, v1.4.3 came out in October 2026, and the self-hosting docs moved to developers.plane.so.

Can I switch between editions? Community to Commercial is documented ("Upgrade Community to Commercial"). The docs say there are no forced migrations.

Does it send my data to the project? The docs describe anonymised usage data, the admin's name and email, and an instance ID. You can turn it off in /god-mode. The Commercial Edition also talks to a licence server.

Can Windows or Mac be the server? The docs list macOS and Windows with WSL2 among supported systems, but we tested neither. For a team, use a Linux server.

Sources#

Checked against the official docs on 2026-11-05.