Self-host Kimai
updated Sep 2026deployed by usprices checked · Jul 2026Install verified on Ubuntu 26.04 · Sep 2026 · how we test
We earn commissions when you shop through the links below. Full disclosure →
Time tracking for freelancers and teams: timesheets against customers, projects and activities, per-user and per-project rates, time and money budgets, reports, exports and invoices, with a JSON API, SAML/LDAP login and TOTP two-factor authentication.
Key facts
CategoryTime tracking
LicenseAGPL-3.0
StackPHP, Symfony, MySQL
Min RAM1024 MB
Official imageyes
Measured idle RAM512 MB
Difficulty
Websitekimai.org (opens in new tab)
What you need
- Any VPS with at least 1024 MB of RAM
- A domain you control — most self-hosted setups need HTTPS in front of them
- Under an hour if you've used Docker before
Where to host itaffiliate disclosure
Hetzner Cloudrun it on
From $23.59/mo · 2 vCPU / 4 GB / 80 GB · EU + USKamaterafree trial
From $4/mo · 1 vCPU / 1 GB / 20 GB · US + EU + AsiaDigitalOceanalso works on
From $6/mo · 1 vCPU / 1 GB / 25 GB · US + EU + AsiaPaid link — we earn a commission if you shop through it.
Install
Run these commands on your server:
# Kimai + MySQL — the compose file from kimai.org's Docker Compose docs, with generated passwords in .env
mkdir -p kimai && cd kimai
printf 'DB_PASS=%s\nDB_ROOT_PASS=%s\nADMINPASS=%s\n' "$(openssl rand -hex 16)" "$(openssl rand -hex 16)" "$(openssl rand -hex 12)" > .env
# Behind a domain, also set TRUSTED_HOSTS=your.domain in the kimai environment
cat > docker-compose.yml <<'EOF'
services:
sqldb:
image: mysql:8.4
volumes: [mysql:/var/lib/mysql]
environment: [MYSQL_DATABASE=kimai, MYSQL_USER=kimaiuser, "MYSQL_PASSWORD=${DB_PASS}", "MYSQL_ROOT_PASSWORD=${DB_ROOT_PASS}"]
command: --default-storage-engine innodb
restart: unless-stopped
healthcheck: { test: mysqladmin -uroot -p$$MYSQL_ROOT_PASSWORD ping -h 127.0.0.1 --silent, interval: 10s, timeout: 5s, retries: 12, start_period: 30s }
kimai:
image: kimai/kimai2:apache
depends_on: { sqldb: { condition: service_healthy, restart: true } }
volumes: [data:/opt/kimai/var/data, plugins:/opt/kimai/var/plugins]
ports: ["8001:8001"]
environment: [ADMINMAIL=admin@example.com, "ADMINPASS=${ADMINPASS}", "DATABASE_URL=mysql://kimaiuser:${DB_PASS}@sqldb/kimai?charset=utf8mb4&serverVersion=8.4.0"]
restart: unless-stopped
volumes: { data: {}, mysql: {}, plugins: {} }
EOF
docker compose up -d
# → http://SERVER_IP:8001 — log in as admin@example.com with ADMINPASS from .envMore self-hosted tools
File sync & storage
Syncthing
Go
easyRead guide →
SSO & Identity
Tinyauth
Go
easyRead guide →
Search engine
Typesense
C++
easyRead guide →
Project Management
WeKan
JavaScriptMeteorFerretDBSQLite
easyRead guide →