لماذا تستضيف Kimai بنفسك؟
تجمع أداة تتبُّع الوقت بيانات حساسة: من يعمل لصالح أي عميل، وكم ساعة، وبأي سعر. في خدمة SaaS تبقى هذه المعلومات لدى المزوّد، وترتفع الكلفة مع كل مستخدم جديد. أما عندما تستضيف Kimai على VPS خاص بك، فتبقى قاعدة البيانات تحت يدك، وتضيف المستخدمين دون رسوم ترخيص، وتختار أنت توقيت التحديثات.
- رخصة MIT — بلا رسوم ترخيص وبلا حدّ لعدد المستخدمين يفرضه المزوّد.
- فوترة مدمجة — تُنشأ الفواتير مباشرة من كشوف الساعات، دون أي وحدة خارجية.
- REST API موثّقة — اربط أدواتك الداخلية (التذاكر، الموارد البشرية، لوحات المتابعة) ببياناتك أنت.
- سيادة البيانات — الساعات والأسعار وملفات العملاء تبقى في قاعدة MySQL الخاصة بك.
- منظومة خفيفة — حاوية تطبيق واحدة وقاعدة MySQL، تعمل براحة على خطة VPS للمبتدئين.
البنية: ما الذي يعمل على الـ VPS
Kimai تطبيق PHP مبني على إطار العمل Symfony. يعتمد الإصدار 2 على MySQL أو MariaDB، ولم يعد يدعم SQLite. تتوفر الصورة الرسمية kimai/kimai2 بنسختين: apache (خادم ويب مدمج يستمع على المنفذ 8001) وfpm (مخصّصة للعمل خلف خادم Nginx خاص بك). يستخدم قالب ServOrbit الصورة kimai/kimai2:apache-latest مع MySQL 8.0، فتقتصر المنظومة على حاويتين فقط.
مكوّنات المنظومة
- الحاوية
kimai— Apache وPHP وتطبيق Symfony في المسار/opt/kimai، والمنفذ 8001 منشور على127.0.0.1فقط. - الحاوية
db— MySQL 8.0 مع فحص صحةmysqladmin ping، فلا يبدأ Kimai إلا بعد جاهزية قاعدة البيانات. - الحجم
kimai_db— ملفات بيانات MySQL، أي جميع كشوف الساعات التي تسجّلها. - الحجم
kimai_data— المسار/opt/kimai/var/data، أي الملفات المرفوعة عبر التطبيق (قوالب الفواتير والمستندات). - الحجم
kimai_public— المسار/opt/kimai/public/avatars، أي صور المستخدمين الرمزية. - الوكيل العكسي — Nginx أو Caddy أو Traefik ينهي اتصال HTTPS ويمرّر الطلبات إلى المنفذ المحلي 8001.
نشر Kimai على ServOrbit
يجهّز Marketplace الخاص بـ ServOrbit المنظومة كاملة على Ubuntu 24.04: Docker وMySQL 8.0 وحاوية Kimai والأحجام الثلاثة وكلمة مرور مولَّدة لحساب المسؤول. لا تحتاج إلى اسم نطاق للبدء.
إطلاق النشر
في منطقة العميل: Marketplace ← ERP والأعمال ← Kimai ← نشر. ينشئ ServOrbit الـ VPS ويثبّت Docker ويشغّل المنظومة (MySQL 8 + Apache/PHP) تلقائيًا.
استلام بيانات الدخول
انتظر 60 ثانية تقريبًا. تعرض بطاقة التطبيق بيانات الدخول: المعرّف
[email protected]وكلمة مرور مولَّدة.الاتصال دون نطاق
افتح نفق SSH بالأمر
ssh -L 8080:127.0.0.1:8001 root@<IP>ثم افتحhttp://localhost:8080. أضف نطاقًا من لوحة التحكم متى أصبحت جاهزًا.إنشاء العميل والمشروع
أنشئ أول عميل، ثم مشروعًا مرتبطًا به، ونشاطًا واحدًا على الأقل. حدّد سعرًا بالساعة أو ميزانية.
تسجيل الساعات الأولى
انقر ▶ لتشغيل المؤقّت واختر المشروع والنشاط، وسيسجّل Kimai وقتك أثناء العمل.
عند أول تسجيل دخول، افتح ملفك الشخصي واستبدل العنوان [email protected] بعنوان بريد حقيقي، وغيّر كلمة المرور المولَّدة. احتفظ بعد ذلك بحساب المسؤول الأعلى لأعمال الإدارة فقط، وأنشئ حسابات بأسماء أصحابها للعمل اليومي.
التثبيت اليدوي باستخدام Docker Compose
إن كنت تفضّل تثبيت Kimai بنفسك على VPS قائم، فهذا ملف docker-compose.yml مكافئ للقالب، مع حجم إضافي للإضافات. ضعه في مجلد مخصّص مثل /opt/kimai.
services:
db:
image: mysql:8.0
restart: unless-stopped
environment:
MYSQL_DATABASE: kimai
MYSQL_USER: kimai
MYSQL_PASSWORD: ${DB_PASSWORD}
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
volumes:
- kimai_db:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "--silent"]
interval: 10s
retries: 12
kimai:
image: kimai/kimai2:apache-latest
restart: unless-stopped
depends_on:
db:
condition: service_healthy
ports:
- "127.0.0.1:8001:8001"
environment:
DATABASE_URL: "mysql://kimai:${DB_PASSWORD}@db/kimai?charset=utf8mb4&serverVersion=8.0.34"
APP_SECRET: ${APP_SECRET}
ADMINMAIL: [email protected]
ADMINPASS: ${ADMIN_PASSWORD}
TRUSTED_HOSTS: "localhost,127.0.0.1,kimai.your-domain.com"
volumes:
- kimai_data:/opt/kimai/var/data
- kimai_plugins:/opt/kimai/var/plugins
- kimai_public:/opt/kimai/public/avatars
volumes:
kimai_db:
kimai_data:
kimai_plugins:
kimai_public:بعد ذلك ولّد الأسرار في ملف .env الذي يقرؤه Compose تلقائيًا، ثم شغّل المنظومة. عند التشغيل الأول تنشئ الحاوية مخطّط قاعدة البيانات وحساب المسؤول المحدَّد في ADMINMAIL وADMINPASS.
cat > .env <<EOF
DB_PASSWORD=$(openssl rand -hex 16)
DB_ROOT_PASSWORD=$(openssl rand -hex 16)
APP_SECRET=$(openssl rand -hex 32)
ADMIN_PASSWORD=$(openssl rand -hex 12)
EOF
chmod 600 .env
docker compose up -d
docker compose logs -f kimaiمتغيّرات البيئة التي ينبغي معرفتها
DATABASE_URL— سلسلة اتصال Doctrine: المستخدم وكلمة المرور والمضيفdbواسم القاعدة وcharset=utf8mb4وserverVersion. ولأن كلمة المرور جزء من عنوان URL، تجنّب فيها الرموز@و/و:؛ والسرّ الست عشري يحلّ المسألة.APP_SECRET— مفتاح Symfony الذي تُوقَّع به الجلسات والرموز. استخدم قيمة عشوائية طويلة تولّدها مرة واحدة ولا تغيّرها دون سبب، لأن تغييرها يُخرج جميع المستخدمين من جلساتهم.ADMINMAILوADMINPASS— حساب المسؤول الأعلى الذي يُنشأ عند التشغيل الأول. بعد أن تعمل النسخة، أدِر الحسابات من الواجهة أو من سطر الأوامر.TRUSTED_HOSTS— قائمة أسماء المضيفين المقبولة مفصولة بفواصل. يجب أن تتضمّن نطاقك العام، وإلا رفض Symfony الطلبات.MAILER_URL— وسيلة إرسال البريد. يضبطها قالب ServOrbit علىnull://localhost، فلا تُرسَل أي رسالة. حدّد خادم SMTP لتفعيل استعادة كلمة المرور والإشعارات.
وضع Kimai خلف نطاق مع HTTPS
توجيه DNS
أنشئ سجل A للنطاق الفرعي
kimai.your-domain.comيشير إلى عنوان IP العام للـ VPS، وتحقّق من الانتشار بالأمرdig +short kimai.your-domain.com.إعداد الوكيل العكسي
المنفذ 8001 يستمع على
127.0.0.1فقط، فلا يصل إليه إلا الوكيل المحلي. مثال على كتلة إعداد Nginx:server { listen 80; server_name kimai.your-domain.com; location / { proxy_pass http://127.0.0.1:8001; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }الحصول على الشهادة
باستخدام certbot وإضافته الخاصة بـ Nginx تُصدَر شهادة Let's Encrypt وتُستكمل كتلة
serverللمنفذ 443:apt install -y certbot python3-certbot-nginx certbot --nginx -d kimai.your-domain.comتعريف Kimai بالنطاق
أضف
kimai.your-domain.comإلىTRUSTED_HOSTS، ثم نفّذdocker compose up -dلإعادة إنشاء الحاوية. إذا بقيت الروابط المولَّدة تبدأ بـhttp://، فراجع توثيق Kimai الخاص بالوكلاء العكسيين: لا تُعتمد ترويساتX-Forwarded-*إلا إذا جاءت من وكيل موثوق.إغلاق ما لا حاجة إليه
في الجدار الناري افتح المنافذ 22 و80 و443 فقط. لا تنشر MySQL أي منفذ، ولا ينبغي أن تفعل.
إنشاء المستخدمين من سطر الأوامر
تكفي الواجهة لإدارة الحسابات يوميًا، لكن وحدة تحكّم Symfony في Kimai مفيدة جدًا لأتمتة انضمام الموظفين الجدد أو لاستعادة الوصول. يأخذ الأمر kimai:user:create اسم المستخدم وعنوان البريد والدور، ثم يطلب كلمة المرور:
docker compose exec kimai /opt/kimai/bin/console kimai:user:create alice [email protected] ROLE_TEAMLEADوتوفّر وحدة التحكّم نفسها الأمر kimai:reload لإعادة بناء ذاكرة التخزين المؤقت بعد تعديل الإعدادات، والأمر kimai:update لتطبيق ترحيلات قاعدة البيانات في التثبيتات خارج Docker. نفّذ bin/console list kimai داخل الحاوية لعرض الأوامر المتاحة في إصدارك.
نموذج البيانات: العملاء والمشاريع والأنشطة
ينظّم Kimai الوقت على ثلاثة مستويات. العميل يحمل العملة والمنطقة الزمنية وبيانات الفوترة. المشروع يتبع عميلًا واحدًا، ويمكن أن تكون له تواريخ بداية ونهاية ورقم طلب وميزانية. النشاط يصف طبيعة العمل (تطوير، اجتماع، دعم)، ويمكن ربطه بمشروع محدّد أو جعله عامًا متاحًا في كل المشاريع. وكل إدخال في كشف الساعات يربط مستخدمًا ومشروعًا ونشاطًا وفترة زمنية، مع وصف ووسوم عند الحاجة. إن تصميم هذا التسلسل جيدًا منذ البداية يوفّر عليك تصحيحات مرهقة لاحقًا: عميل لكل جهة تُصدر لها فواتير، ومشروع لكل مهمة أو عقد، وأنشطة عامة للأعمال المشتركة بين المشاريع.
الأسعار والميزانيات
- السعر بالساعة — يُحدَّد على مستوى العميل أو المشروع أو النشاط أو المستخدم، ويُطبَّق المستوى الأدق على كل إدخال.
- السعر الثابت — مبلغ مقطوع لكل إدخال، مفيد لخدمة تُفوتَر بسعر محدّد أيًّا كانت مدتها.
- السعر الداخلي — الكلفة الحقيقية للساعة بالنسبة إليك، منفصلة عن السعر المفوتَر، لقياس ربحية كل مشروع.
- ميزانية بالوقت أو بالمال — على مستوى العميل أو المشروع أو النشاط، مع مؤشّر مرئي لنسبة الاستهلاك.
- ميزانية شهرية أو إجمالية — تُتابَع باقة صيانة شهرية بطريقة مختلفة عن مشروع بسعر ثابت طوال مدّته.
- التجاوز — تُظهر لوحات المتابعة نسبة استهلاك الميزانية، ويتيح أحد الإعدادات السماح بالإدخالات التي تتجاوزها أو منعها.
الأدوار والفرق والصلاحيات
يعتمد Kimai أدوارًا متدرّجة، وتتيح شاشة الأدوار والصلاحيات ضبط ما يراه كل دور وما يعدّله بدقة. وتكمّل الفرق هذا النظام: العميل أو المشروع أو النشاط المقصور على فريق لا يظهر إلا لأعضائه، وقائد الفريق يراجع ساعات فريقه ويصحّحها دون الاطلاع على بقية الشركة. وللمتعاون الخارجي، أنشئ حساب مستخدم مقصورًا على فريق مخصّص له.
ROLE_USER— يسجّل ساعاته ويراجعها في المشاريع المتاحة له.ROLE_TEAMLEAD— يرى ساعات أعضاء فرقه ويعدّلها ويطّلع على تقاريرهم.ROLE_ADMIN— يدير العملاء والمشاريع والأنشطة والفواتير والمستخدمين.ROLE_SUPER_ADMIN— صلاحيات كاملة، بما فيها إعدادات النظام والصلاحيات.
الفوترة انطلاقًا من كشوف الساعات
تحوّل وحدة الفوترة مجموعة مختارة من الساعات إلى مستند. من قائمة الفواتير تختار عميلًا وفترة، ومشروعًا إن شئت، ثم قالبًا. يحسب Kimai المبالغ انطلاقًا من الأسعار، ويعرض معاينة، ثم يحفظ الفاتورة مع حالتها (قيد الانتظار، مدفوعة، ملغاة). ويمكن وسم الإدخالات المفوترة بأنها مُصدَّرة، مما يمنع فوترتها مرتين ويحميها من التعديل لاحقًا.
إعداد أول قالب فاتورة
إنشاء القالب
من الفواتير ← القوالب، أدخل اسم الجهة المُصدِرة والعنوان والبيانات البنكية ومهلة الدفع ونص التذييل.
اختيار صيغة الإخراج
اختر صيغة PDF أو HTML لمستند جاهز للإرسال، أو صيغة مكتبية إن كنت تستكمل الفاتورة في أداة أخرى.
تحديد الترقيم
اضبط صيغة رقم الفاتورة (بادئة، سنة، عدّاد) للحصول على تسلسل متّصل يوافق ممارساتك المحاسبية.
ضبط الضريبة
أدخل نسبة الضريبة المطبّقة في القالب، وأنشئ قالبًا لكل نظام ضريبي إن كنت تفوتر عملاء بنسب مختلفة.
الضريبة على القيمة المضافة والبيانات الإلزامية
يحسب Kimai الضريبة انطلاقًا من النسبة المُدخلة في القالب، لكنه لا يعرف وضعك الضريبي. فالبيانات القانونية والنسبة المطبّقة ومدة حفظ الفواتير تتوقف على بلدك وصفتك القانونية، لذا اطلب من محاسبك مراجعة القالب. وإن كنت تمسك حساباتك كاملة في نظام ERP مثل Dolibarr، فيمكن أن يبقى Kimai أداة تسجيل الوقت، وأن يكون التصدير منه أساسًا للفاتورة النهائية.
واجهة REST API والتكاملات
يوفّر Kimai واجهة REST API تغطي العملاء والمشاريع والأنشطة وكشوف الساعات والمستخدمين. وتقدّم نسختك نفسها التوثيق التفاعلي على المسار /api/doc، متوافقًا دائمًا مع الإصدار المثبَّت. لمصادقة سكربت، أنشئ رمز API من ملفك الشخصي، ثم أرسله في ترويسة الطلب:
curl -s -H "Authorization: Bearer YOUR_TOKEN" \
https://kimai.your-domain.com/api/timesheetsيرث الرمز صلاحيات صاحبه، لذا أنشئ حساب خدمة بأدنى دور لازم بدل استخدام حساب المسؤول الأعلى. تتيح الواجهة مثلًا تشغيل مؤقّت من اختصار، أو إرسال الساعات إلى لوحة متابعة، أو مزامنة المشاريع مع أداة التذاكر لديك.
توسيع Kimai بالإضافات
يملك Kimai متجر إضافات على موقعه الرسمي، فيه إضافات مجانية وأخرى مدفوعة: المصاريف، والحقول المخصّصة، ومسارات اعتماد كشوف الساعات، والاستيراد من أدوات أخرى. الإضافة مجلد يوضع في var/plugins/. ومع Docker، اربط هذا المجلد بحجم دائم، وإلا اختفى عند إعادة إنشاء الحاوية؛ وهذا دور الحجم kimai_plugins في ملف compose أعلاه. تثبيت نموذجي:
docker compose cp PluginNameBundle kimai:/opt/kimai/var/plugins/
docker compose exec kimai /opt/kimai/bin/console kimai:reload --env=prodتضيف بعض الإضافات جداول إلى القاعدة وتأتي بأمر تثبيت خاص بها؛ اتبع صفحة الإضافة، وتحقّق من توافقها مع إصدار Kimai لديك قبل كل تحديث.
النسخ الاحتياطي والاستعادة
يكاد كل شيء يكون في قاعدة MySQL، ويكمّل الحجمان kimai_data وkimai_public النسخة الاحتياطية. والتفريغ المنطقي أسهل نقلًا من نسخ ملفات MySQL أثناء التشغيل:
docker compose exec -T db sh -c 'exec mysqldump --single-transaction -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DATABASE"' > kimai-$(date +%F).sql
docker run --rm -v kimai_kimai_data:/data -v "$PWD":/backup alpine tar czf /backup/kimai_data-$(date +%F).tgz -C /data .يبدأ الاسم الفعلي للحجم باسم مشروع Compose، فتحقّق منه بالأمر docker volume ls. للاستعادة، شغّل منظومة فارغة بنفس ملف .env، ثم أعد تحميل التفريغ:
docker compose exec -T db sh -c 'exec mysql -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DATABASE"' < kimai-YYYY-MM-DD.sqlجدوِل التفريغ كل ليلة عبر cron، وانسخه خارج الـ VPS (باستخدام Restic أو BorgBackup أو تخزين كائنات)، وجرّب الاستعادة مرة واحدة على الأقل: فالنسخة التي لم تُستعَد قطّ ليست سوى فرضية.
تحديثات بلا مفاجآت
- النسخ الاحتياطي أولًا — تفريغ قبل التحديث مباشرة يتيح لك التراجع إذا فشل أحد الترحيلات.
- تحديث الصورة —
docker compose pull kimai && docker compose up -d kimai، ثم تابع السجلات بالأمرdocker compose logs -f kimai. عند الإقلاع تطبّق الحاوية ترحيلات قاعدة البيانات تلقائيًا. - تثبيت إصدار محدّد — في الإنتاج، استبدل
apache-latestبوسم صورة يحمل رقم إصدار، لتقرّر أنت موعد الترقية. - قراءة ملاحظات الإصدار — بعض الإصدارات الرئيسية تغيّر المتطلبات أو سلوك الإضافات.
- التصدير بانتظام — تصدير كشوف الساعات بصيغة CSV أو XLSX نسخة مقروءة تفيد في التدقيق أو الانتقال إلى أداة أخرى.
حلّ المشكلات الشائعة
ترجع معظم أعطال Kimai على Docker إلى عدد محدود من الأسباب المعروفة. ابدأ دائمًا بالأمرين docker compose logs kimai وdocker compose ps.
- رسالة «Untrusted Host» أو خطأ 400 بعد إضافة نطاق — اسم المضيف غير موجود في
TRUSTED_HOSTS. أضفه ثم أعد إنشاء الحاوية. - خطأ 500 مع «Permission denied» على المجلد
var/— يحدث غالبًا بعد تنفيذ أمر من وحدة التحكّم بمستخدم غير مستخدم خادم الويب. أعد الملكية بالأمرdocker compose exec kimai chown -R www-data:www-data /opt/kimai/varثم نفّذkimai:reload. - تعديل في الإعدادات بلا أثر — ذاكرة Symfony المؤقتة تقدّم النسخة القديمة:
docker compose exec kimai /opt/kimai/bin/console kimai:reload --env=prod. - إعادة تشغيل Kimai في حلقة عند الإقلاع الأول — القاعدة غير جاهزة أو
DATABASE_URLغير صحيح. راجع فحص صحةdbوبيانات الدخول في ملف .env. - روابط تبدأ بـ
http://خلف وكيل HTTPS — ترويساتX-Forwarded-Protoلا تُرسَل أو لا تُعتبر موثوقة؛ راجع إعدادات الوكيل. - نسيان كلمة المرور دون بريد مُعَدّ —
MAILER_URLيشير إلىnull://: أعد تعيين كلمة المرور من حساب مسؤول، أو أنشئ مسؤولًا جديدًا من سطر الأوامر.
Kimai مقارنةً بـ Toggl Track وClockify وHarvest
مرّر الجدول أفقيًا
| المعيار | Kimai (استضافة ذاتية) | Toggl Track | Clockify | Harvest |
|---|---|---|---|---|
| الترخيص | مفتوح المصدر (MIT) | مملوك | مملوك | مملوك |
| الاستضافة | الـ VPS الخاص بك | خدمة SaaS لدى المزوّد | خدمة SaaS لدى المزوّد | خدمة SaaS لدى المزوّد |
| مكان البيانات | قاعدة MySQL الخاصة بك | بنية المزوّد التحتية | بنية المزوّد التحتية | بنية المزوّد التحتية |
| نموذج الكلفة | كلفة الخادم فقط، بلا رسوم لكل مستخدم | مستوى مجاني محدود ثم اشتراك | مستوى مجاني ثم اشتراك | مستوى مجاني محدود ثم اشتراك |
| الفوترة | وحدة مدمجة (قوالب، ترقيم، ضريبة) | بحسب الخطة | بحسب الخطة | مدمجة في المنتج |
| الواجهة البرمجية | REST مع رموز وتوثيق مدمج | REST | REST | REST |
| التخصيص | الشيفرة المصدرية والإضافات والإعدادات | الإعدادات والتكاملات | الإعدادات والتكاملات | الإعدادات والتكاملات |
اختيار حجم الـ VPS المناسب
Kimai قليل الاستهلاك، ويأتي معظم الحمل من MySQL ومن التقارير التي تغطي فترات طويلة. للمستقل أو الفريق الصغير يكفي 1 vCPU ومن 1 إلى 2 غيغابايت من الذاكرة. وإذا تجاوز عدد المستخدمين النشطين نحو عشرين مستخدمًا، أو كنت تُعدّ بانتظام تقارير سنوية وعمليات تصدير كبيرة، فخطّط لـ 2 vCPU و4 غيغابايت، ما يترك هامشًا لذاكرة InnoDB المؤقتة في MySQL. أما مساحة القرص فمتواضعة: بضعة غيغابايتات تكفي لسنوات من كشوف الساعات، لكن احتفظ بمساحة للتفريغات المحلية قبل نقلها خارج الخادم.
قبل دعوة فريقك، حدّد قواعد العمل من الإعدادات: تقريب المدد، والسماح بالإدخالات المستقبلية أو منعها، وقفل الفترات التي سبقت فوترتها. فاتخاذ هذه القرارات على نسخة فارغة أسهل بكثير من اتخاذها بعد أشهر من السجلات.