Self-Host Planka (Trello Alternative)
Deploy Planka, a self-hosted Trello alternative, using Docker Compose with PostgreSQL, HTTPS via Caddy, and full support for boards, cards, comments, and attachments.
Before you start
- ▸A Linux server with at least 1 GB RAM and internet access
- ▸A domain or subdomain with its DNS A record pointing to the server's IP
- ▸Root or sudo access on the server
- ▸Ports 80 and 443 open in both the host firewall and any upstream cloud security group
Planka is a fast, open-source Kanban board application that gives you everything Trello offers — cards, lists, labels, attachments, and comments — without the subscription or the data leaving your server. Deploying it with Docker Compose takes under fifteen minutes, and adding a reverse proxy gives you a proper HTTPS URL.
Prerequisites
- A server (VPS or bare metal) with at least 1 GB RAM and Docker Engine installed
- Docker Compose v2 (the
docker composeplugin, not the legacydocker-composebinary) - A domain name or subdomain pointed at your server's IP — needed for the reverse proxy and for Planka's
BASE_URL - Ports 80 and 443 reachable, or whichever port you choose for HTTP-only setups
Step 1 — Install Docker (if not already present)
Debian / Ubuntu
sudo apt update
sudo apt install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
| sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo $VERSION_CODENAME) stable" \
| sudo tee /etc/apt/sources.list.d/docker.list
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
Fedora / RHEL / Rocky
sudo dnf -y install dnf-plugins-core
sudo dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo
sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
sudo systemctl enable --now docker
Arch
sudo pacman -S docker docker-compose
sudo systemctl enable --now docker
Add your user to the docker group so you can run commands without sudo:
sudo usermod -aG docker $USER
newgrp docker
Step 2 — Create the Compose Project
Create a dedicated directory and a docker-compose.yml file:
mkdir -p ~/planka && cd ~/planka
cat > docker-compose.yml <<'EOF'
services:
planka:
image: ghcr.io/plankanban/planka:latest
restart: unless-stopped
depends_on:
db:
condition: service_healthy
ports:
- "3000:1337"
environment:
BASE_URL: https://planka.example.com
DATABASE_URL: postgresql://planka:planka_password@db/planka
SECRET_KEY: "change_me_to_a_64_char_random_string"
DEFAULT_ADMIN_EMAIL: [email protected]
DEFAULT_ADMIN_PASSWORD: StrongAdminPass1
DEFAULT_ADMIN_NAME: Admin
DEFAULT_ADMIN_USERNAME: admin
volumes:
- planka_data:/app/public/user-avatars
- planka_data:/app/public/project-background-images
- planka_attachments:/app/private/attachments
db:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_DB: planka
POSTGRES_USER: planka
POSTGRES_PASSWORD: planka_password
volumes:
- db_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U planka"]
interval: 10s
timeout: 5s
retries: 5
volumes:
planka_data:
planka_attachments:
db_data:
EOF
Before starting, replace every placeholder value:
BASE_URL— your real domain, including scheme (https://)SECRET_KEY— generate a 64-character random string (see below)DEFAULT_ADMIN_PASSWORDandPOSTGRES_PASSWORD— strong unique passwords
openssl rand -hex 32
Paste the output as SECRET_KEY. Keep Postgres credentials consistent between the planka and db service blocks.
Step 3 — Start Planka
docker compose up -d
Watch the logs until the app is ready (look for a line indicating the server is listening):
docker compose logs -f planka
Planka is now reachable on port 3000. Before exposing it to the internet, add the reverse proxy in the next step.
Step 4 — Reverse Proxy with Caddy (HTTPS)
Caddy is the simplest choice for automatic TLS. Install it, then write a minimal Caddyfile.
Debian / Ubuntu
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf https://dl.cloudsmith.io/public/caddy/stable/gpg.key \
| sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt \
| sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update && sudo apt install -y caddy
Fedora / RHEL / Rocky
sudo dnf install -y 'dnf-command(copr)'
sudo dnf copr enable @caddy/caddy
sudo dnf install -y caddy
Arch
sudo pacman -S caddy
Edit /etc/caddy/Caddyfile:
sudo tee /etc/caddy/Caddyfile <<'EOF'
planka.example.com {
reverse_proxy localhost:3000
}
EOF
sudo systemctl enable --now caddy
sudo systemctl reload caddy
Caddy fetches a Let's Encrypt certificate automatically. Your Planka instance is now available at https://planka.example.com.
If you prefer Nginx or Apache, the key settings are: proxy to http://localhost:3000, enable WebSocket upgrade headers (Upgrade and Connection), and set proxy_set_header Host $host. Planka uses WebSockets for real-time board updates.
Step 5 — Open the Firewall
ufw (Debian / Ubuntu)
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw reload
firewalld (Fedora / RHEL / Rocky)
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
Step 6 — Log In and Configure Boards
Open your domain in a browser and sign in with the DEFAULT_ADMIN_EMAIL and password you set. The first screen prompts you to create a Project (the top-level container, equivalent to a Trello workspace).
- Boards — inside a project, create boards for each workflow. Click the + icon next to the project name.
- Lists — within a board, add lists (columns) like To Do, In Progress, Done.
- Cards — add cards to lists. Click a card to open the detail view.
- Comments — in the card detail view, type a comment in the text field at the bottom and press Save.
- Attachments — in the card detail view, click Attachment in the sidebar, then choose a file. Attachments are stored in the
planka_attachmentsDocker volume at/app/private/attachments. - Labels and Due Dates — also accessible from the card detail sidebar.
Invite other users from Admin panel → Users → Add user, or enable open registration in the environment variables (set ALLOW_ALL_TO_CREATE_PROJECTS=true and restart the container).
Step 7 — Verify the Deployment
docker compose ps
Both planka and db should show Up (or running). Check that HTTPS works and the certificate is valid:
curl -I https://planka.example.com
You should see HTTP/2 200 (or a redirect to the login page). If WebSockets are working correctly, board changes made in one browser tab will appear instantly in another without a page refresh.
Keeping Planka Updated
cd ~/planka
docker compose pull
docker compose up -d
This pulls the latest image and recreates the container while leaving your named volumes (data, attachments, database) untouched.
Backup
Back up both the Postgres database and the attachments volume:
# Dump the database
docker compose exec db pg_dump -U planka planka > planka_backup_$(date +%F).sql
# Archive the attachments volume
docker run --rm -v planka_planka_attachments:/data -v $(pwd):/backup \
alpine tar czf /backup/attachments_$(date +%F).tar.gz -C /data .
Troubleshooting
- Planka container exits immediately — usually a bad
DATABASE_URLor the db healthcheck hasn't passed yet. Rundocker compose logs plankaanddocker compose logs dbto confirm Postgres started cleanly. - Real-time updates not working — WebSocket proxying is likely misconfigured. With Nginx, ensure you have
proxy_http_version 1.1,proxy_set_header Upgrade $http_upgrade, andproxy_set_header Connection "upgrade"in your location block. - Attachment uploads fail — verify the
planka_attachmentsvolume is mounted correctly and the container has write permission. Check withdocker compose exec planka ls -la /app/private/. - Certificate errors — ensure ports 80 and 443 are open and DNS has propagated. Caddy logs are at
journalctl -u caddy -n 50. - Forgot admin password — reset it via the Admin panel when logged in as another admin, or use
docker compose exec planka node ./node_modules/.bin/sails run reset-password --email [email protected].
Frequently asked questions
- Can I run Planka without a domain name, on a local network only?
- Yes. Set BASE_URL to http://your-server-ip:3000, remove the reverse proxy, and access Planka directly on port 3000. You won't get HTTPS unless you configure a self-signed certificate or use a local CA.
- How do I enable email notifications in Planka?
- Add SMTP environment variables to the planka service in docker-compose.yml: SMTP_HOST, SMTP_PORT, SMTP_SECURE, SMTP_USER, SMTP_PASSWORD, and SMTP_FROM. Restart the container after saving.
- Is it safe to expose Planka directly to the internet without a reverse proxy?
- Not recommended. Running directly on port 3000 means no TLS and no HTTP/2. Always place a reverse proxy in front so traffic is encrypted and you can add rate-limiting or auth middleware.
- How large can attachments be, and can I change the limit?
- The default maximum attachment size is set by Planka's internal limits (currently around 100 MB). If you use Caddy or Nginx, also set client_max_body_size (Nginx) or request_body_max in your Caddyfile to match or exceed Planka's limit.
- Can multiple people use the same Planka instance with separate accounts?
- Yes. Create additional user accounts from the Admin panel under Users. Each user has their own profile and you can add them to specific projects and boards with member-level or admin-level permissions.
Related guides
Configure Prometheus Alertmanager
Configure Prometheus Alertmanager with routing trees, receivers, inhibition rules, grouping, Go templates, and PagerDuty/Slack on-call integrations.
Build an Intranet Server on Linux
Set up a complete small-office intranet on one Linux box: Nginx web server, dnsmasq local DNS, Samba file sharing, and a Wiki.js team wiki.
Build an nftables Firewall Script
Build a complete nftables firewall from scratch: tables, chains, sets, default-deny input policy, service allowlisting, and persistent systemd configuration.
Caddy as a Reverse Proxy
Set up Caddy as a reverse proxy with automatic HTTPS, load balancing, WebSocket passthrough, reusable snippets, and header control — no certbot required.