Skip to content

How to Deploy Kanboard on a VPS

Updated Oct 2026

verified on Ubuntu 26.04 · Oct 2026
We earn commissions when you shop through the links below. Full disclosure →

Self-host Kanboard on a small VPS — the minimalist PHP kanban board, run with PostgreSQL in Docker Compose behind Caddy HTTPS, with a backup you can restore and a pinned-image upgrade path.

Before you start
  • A VPS with 512 MB+ RAM (Kanboard's own floor is 256 MB; the extra room is for PostgreSQL, Docker and the reverse proxy)
  • A fresh Ubuntu 24.04 or 26.04 server with root/sudo SSH access
  • A domain or subdomain you can point at the server
Need a box for this guide? Kamatera's free tier lets you spin one up now.Start free on Kamatera → (opens in new tab)

What Kanboard is

Kanboard is a minimalist, open-source kanban board: columns, swimlanes, subtasks, time tracking, automatic actions, a JSON-RPC API and a plugin system, all in a deliberately small PHP codebase. It is MIT-licensed and rated 1 / 5 to deploy. If you want a self-hosted alternative to Trello that does one job and stays out of your way, this is it.

Kanboard can run on SQLite, MySQL/MariaDB or PostgreSQL. Its Docker image supports all three, but upstream advises against SQLite inside Docker, so this guide uses the official PostgreSQL pairing: two containers, one Compose file, and named volumes for state. It picks up from "you have a server" and ends with the board on HTTPS, a tested backup and an upgrade routine. For help choosing a provider and tier, see Best VPS for self-hosting.

Server sizing

Kanboard is one of the lightest apps in the catalog. On our test box the app container idled at roughly 52 MB of RAM, and the whole install (images, volumes, database) used under 1 GB of disk. PostgreSQL adds some resident memory, and Docker and Caddy a little more again, so a 1 GB VPS is comfortable and 512 MB works for a personal or small-team board.

Disk grows with attachments and the database. Kanboard stores uploaded files in its data volume, so if your team attaches large files to cards, size the disk for that rather than for RAM.

Prepare the server

Update the system and install the few tools this guide uses:

sudo apt-get update && sudo apt-get -y upgrade
sudo apt-get install -y curl openssl ufw dnsutils

If you're logged in as root, create a non-root sudo user and continue as that user:

adduser deploy
usermod -aG sudo deploy

Then open only SSH and the two ports the reverse proxy needs:

sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw --force enable

Kanboard will be reachable only through the reverse proxy. That matters on a Docker host: a published container port goes around ufw entirely, so the Compose file below binds the app to 127.0.0.1, and Caddy becomes the only public door.

Where to host itaffiliate disclosure
Hetzner Cloudrun it on
2 vCPU · 4 GB RAM · 80 GB SSD · $23.59/mo
Get Hetzner Cloud (opens in new tab)
Kamaterafree trial
1 vCPU · 1 GB RAM · 20 GB SSD · $4.00/mo
Start free on Kamatera → (opens in new tab)
DigitalOceanalso works on
1 vCPU · 1 GB RAM · 25 GB SSD · $6.00/mo
Deploy on DigitalOcean → (opens in new tab)

Paid link — we earn a commission if you shop through it.

Install Docker

Kanboard is installed with Docker Compose. If Docker isn't on the server yet, the convenience script installs Docker Engine and the Compose plugin (the Docker and Compose on Ubuntu guide covers the details):

command -v docker >/dev/null || curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker "$USER"
sudo docker compose version

The group change applies on your next login; until then the commands below use sudo docker.

Install Kanboard

Create a project directory and generate a database password into a .env file that Compose reads automatically. The guard keeps the step safe to re-run: regenerating the password on an existing install would lock Kanboard out of its own database.

mkdir -p ~/kanboard && cd ~/kanboard
[ -f .env ] || echo "DB_PASSWORD=$(openssl rand -hex 16)" > .env
grep -c DB_PASSWORD .env

Now the Compose file. It is the official PostgreSQL variant, with the image tag pinned (so an upgrade is a deliberate edit, not a surprise) and the app port bound to loopback:

cd ~/kanboard
cat > docker-compose.yml <<'EOF'
services:
  app:
    image: kanboard/kanboard:v1.2.54
    restart: always
    ports: ["127.0.0.1:8080:80"]
    volumes: ["data:/var/www/app/data", "plugins:/var/www/app/plugins"]
    environment:
      DATABASE_URL: postgres://kanboard:${DB_PASSWORD}@db/kanboard
    depends_on:
      db:
        condition: service_healthy
  db:
    image: postgres:17
    restart: always
    environment:
      POSTGRES_USER: kanboard
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: kanboard
    volumes: ["db:/var/lib/postgresql/data"]
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "kanboard"]
      start_period: 15s
      interval: 10s
      timeout: 5s
volumes:
  data:
  plugins:
  db:
EOF

Start it and wait for the board to answer. The first boot creates the database schema, so give it a moment:

cd ~/kanboard
sudo docker compose up -d
for i in $(seq 1 30); do
  code=$(curl -s -o /dev/null -w '%{http_code}' -L http://127.0.0.1:8080/)
  [ "$code" = "200" ] && break
  sleep 3
done
echo "Kanboard answered HTTP $code"
sudo docker compose ps

HTTP 200 and both containers running (the database healthy) means the install worked. If it never answers, jump to Troubleshooting.

HTTPS + domain

Create an A record for your board's hostname (say kanban.example.com) pointing at the server's public IP, and confirm it resolves before requesting a certificate:

dig +short kanban.example.com

Then put Automatic HTTPS with Caddy in front of the app. The simplest route is Caddy as a third service in the same Compose file, so it reaches the app by name. In docker-compose.yml, add this service under services::

  caddy:
    image: caddy:2
    restart: always
    ports: ["80:80", "443:443"]
    volumes: ["./Caddyfile:/etc/caddy/Caddyfile", "caddy_data:/data"]
    depends_on: [app]

Add caddy_data: to the volumes: list at the bottom, and remove the ports: line from the app service so the board is no longer published on the host. The Caddyfile next to the Compose file is one block:

kanban.example.com {
    reverse_proxy app:80
}

Apply it with sudo docker compose up -d. Caddy requests the certificate on the first request and renews it on its own. Open https://kanban.example.com and confirm the padlock before you sign in.

First login and hardening

Kanboard ships with a default administrator, admin / admin. That is public knowledge, so before anything else:

  1. Sign in and open My profile from the user menu. Change the password to a long random one.
  2. Go to Settings → Application settings and set the application URL to your HTTPS address, so notification emails link to the right place.
  3. Create real user accounts for your team instead of sharing the admin login, and keep the administrator role for the few people who manage settings.
  4. If you won't use the JSON-RPC API, leave it unconfigured; if you do, use a dedicated API token rather than the admin password.

Backups

State lives in named volumes: the PostgreSQL data and Kanboard's data volume (file attachments and cached files). Back up both. Start with a logical database dump, which is portable across PostgreSQL versions:

cd ~/kanboard
sudo docker compose exec -T db pg_dump -U kanboard kanboard > kanboard-db-$(date +%F).sql
test -s kanboard-db-$(date +%F).sql && ls -lh kanboard-db-*.sql

Then archive the attachments volume and the Compose files:

cd ~/kanboard
sudo docker run --rm -v kanboard_data:/data -v "$PWD":/backup alpine \
  tar czf "/backup/kanboard-files-$(date +%F).tar.gz" -C /data .
sudo tar czf "kanboard-config-$(date +%F).tar.gz" docker-compose.yml .env
ls -lh kanboard-files-*.tar.gz kanboard-config-*.tar.gz

Copy these files off the server — object storage, another machine, anywhere that survives this VPS dying — and run the pair from cron. To restore, bring up only the database (sudo docker compose up -d db), pipe the dump back in with sudo docker compose exec -T db psql -U kanboard kanboard, unpack the files archive into the data volume, then start everything. Do that once on a scratch box so you know it works.

Upgrades

Because the image tag is pinned, an upgrade is an edit. Check Kanboard's release notes, take a backup (previous section), change the tag in docker-compose.yml, then pull and recreate:

cd ~/kanboard
sudo docker compose pull
sudo docker compose up -d
sudo docker compose logs --tail 20 app

Kanboard runs its database migrations automatically on the first start of a new version, and those are one-way, which is why the backup comes first. Keep the postgres major version pinned too; moving to a new PostgreSQL major is a dump-and-restore job, not a tag bump. Plugins in the plugins volume must support the version you upgrade to, so check them after the core update.

Troubleshooting

The board returns 502 through Caddy, or never answers. Check sudo docker compose ps: if app is restarting, read sudo docker compose logs app. The usual cause is a wrong DATABASE_URL, which happens when .env was regenerated after the database volume already existed with the old password. Restore the original .env, or remove the volumes if the install holds no data yet.

Caddy never gets a certificate. Confirm dig +short kanban.example.com returns the server's IP and that your provider's network-level firewall, not just ufw, allows inbound 80 and 443. A blocked port 80 silently breaks the ACME challenge.

You can't sign in after changing the admin password. Kanboard has no email-based reset until SMTP is configured, so store the new password in your password manager the moment you set it, and keep a second administrator account so one lost password never locks everyone out.

Attachments disappear after recreating the stack. The volumes were removed (docker compose down -v). Plain docker compose down keeps them; the -v flag deletes them.

Verification + next steps

Not exercised in our test run: the new-user step and the DNS check against your real domain (we ran on a throwaway box with a temporary hostname).

You're done when https://kanban.example.com loads with a valid certificate, you can sign in with a password that is not admin, docker compose ps shows every service up after a reboot (restart: always brings them back), and you have restored a backup onto a scratch box at least once.

From there, create your first project, set up columns and swimlanes, add automatic actions to move cards on events, and browse the plugin directory for integrations. For the ranked server picks and the app's catalog details, see Best VPS for self-hosting and the Kanboard entry.

Next steps

How to self-host Kanboard →More self-hosted project management tools →Automatic HTTPS with Caddy →Run Claude Code with Ollama on Your Own VPS →Deploy Coolify on a VPS →How to Deploy Actual Budget on a VPS →How to Deploy AFFiNE on a VPS →How to Deploy AnythingLLM on a VPS →How to Deploy Appwrite on a VPS →How to Deploy Audiobookshelf on a VPS →How to Deploy Authelia on a VPS →How to Deploy authentik on a VPS →How to Deploy Baserow on a VPS →How to Deploy Beszel on a VPS →How to Deploy Bitwarden on a VPS →How to Deploy BookStack on a VPS →How to Deploy CapRover on a VPS →How to Deploy Checkmate on a VPS →How to Deploy copyparty on a VPS →How to Deploy Directus on a VPS →How to Deploy Discourse on a VPS →How to Deploy docker-mailserver on a VPS →How to Deploy Docmost on a VPS →How to Deploy Dokku on a VPS →How to Deploy Dokploy on a VPS →How to Deploy Firefly III on a VPS →How to Deploy Flarum on a VPS →How to Deploy Forgejo on a VPS →How to Deploy Gatus on a VPS →How to Deploy Ghost on a VPS →How to Deploy Ghostfolio on a VPS →How to Deploy Gitea on a VPS →How to Deploy a GitHub Actions Self-Hosted Runner on a VPS →How to Deploy GitLab on a VPS →How to Deploy GlitchTip on a VPS →How to Deploy Grafana on a VPS →How to Deploy Graylog on a VPS →How to Deploy Headscale on a VPS →How to Deploy Healthchecks on a VPS →How to Deploy Home Assistant on a VPS →How to Deploy Immich on a VPS →How to Deploy Infisical on a VPS →How to Deploy Invoice Ninja on a VPS →How to Deploy Jan on a VPS →How to Deploy Jellyfin on a VPS →How to Deploy Karakeep on a VPS →How to Deploy Keycloak on a VPS →How to Deploy Leantime on a VPS →How to Deploy LibreChat on a VPS →How to Deploy Linkwarden on a VPS →How to Deploy LocalAI on a VPS →How to Deploy Mailcow on a VPS →How to Deploy Mailu on a VPS →How to Deploy Matomo on a VPS →How to Deploy Mattermost on a VPS →How to Deploy Meilisearch on a VPS →How to Deploy Memos on a VPS →How to Deploy a Minecraft Server on a VPS →How to Deploy n8n on a VPS →How to Deploy Navidrome on a VPS →How to Deploy NetBird on a VPS →How to Deploy Netdata on a VPS →How to Deploy Nextcloud on a VPS →How to Deploy Next.js to a VPS →How to Deploy Nginx Proxy Manager on a VPS →How to Deploy NocoDB on a VPS →How to Deploy ntfy on a VPS →How to Deploy Odoo on a VPS →How to Deploy Ollama on a VPS →How to Deploy ONLYOFFICE Docs on a VPS →How to Deploy Open WebUI on a VPS →How to Deploy OpenHands on a VPS →How to Deploy OpenObserve on a VPS →How to Deploy OpenProject on a VPS →How to Deploy Outline on a VPS →How to Deploy Pangolin on a VPS →How to Deploy Paperless-ngx on a VPS →How to Deploy Passbolt on a VPS →How to Deploy Plane on a VPS →How to Deploy Plausible Analytics on a VPS →How to Deploy Plex Media Server on a VPS →How to Deploy Pocket ID on a VPS →How to Deploy PocketBase on a VPS →How to Deploy Prometheus on a VPS →How to Deploy Psono on a VPS →How to Deploy Radarr on a VPS →How to Deploy Rocket.Chat on a VPS →How to Deploy SigNoz on a VPS →How to Deploy Sonarr on a VPS →How to Deploy Stalwart on a VPS →How to Deploy Stirling-PDF on a VPS →How to Deploy Supabase on a VPS →How to Deploy Synapse on a VPS →How to Deploy Taiga on a VPS →How to Deploy TeamPass on a VPS →How to Deploy Tinyauth on a VPS →How to Deploy Traefik on a VPS →How to Deploy Trilium on a VPS →How to Deploy Twenty CRM on a VPS →How to Deploy Umami on a VPS →How to Deploy Uptime Kuma on a VPS →How to Deploy Vaultwarden on a VPS →How to Deploy Vikunja on a VPS →How to Deploy wg-easy on a VPS →How to Deploy Wiki.js on a VPS →How to Deploy WordPress on a VPS →How to Deploy Zabbix on a VPS →How to Deploy Zitadel on a VPS →How to Deploy Zulip on a VPS →Docker & Compose on Ubuntu 26.04 →Building AI Workflows with n8n →Install Open WebUI with Ollama →Adding AI-Powered Insights to Plausible Analytics →Building AI-Powered Apps with Supabase and pgvector →

We use analytics cookies (Google Analytics, PostHog) to see which guides are useful. No ad networks, no cross-site tracking. See our privacy policy.