Guía de despliegue

Alojar Kimai en VPS: seguimiento de tiempo open source

Desplegar en un VPS Cloud →

Tutorial

Alojar Kimai en VPS: seguimiento de tiempo open source

Autoalojamiento14 min de lectura14 pasos

Kimai es un software de seguimiento de tiempo open source, con licencia MIT, capaz de sustituir a Toggl Track, Clockify o Harvest a largo plazo: temporizador, partes de horas, clientes, proyectos, actividades, tarifas horarias, presupuestos, informes y facturación. Esta guía va más allá de la instalación. Explica la arquitectura del stack Docker, un `docker-compose.yml` comentado para quien despliega a mano, la publicación en HTTPS detrás de un proxy inverso, la creación de cuentas desde la línea de comandos, el modelo de datos y los roles, la facturación, la API REST, los plugins, las copias de seguridad, las actualizaciones y los errores más habituales. Al terminar sabrás operar Kimai en producción para un equipo, no solo arrancarlo.

Contenido· ¿Por qué alojar Kimai tú mismo?1/21
  1. 01¿Por qué alojar Kimai tú mismo?
  2. 02Arquitectura: qué se ejecuta en el VPS
  3. 03Las piezas del stack
  4. 04Desplegar Kimai en ServOrbit
  5. 05Instalación manual con Docker Compose
  6. 06Variables de entorno que conviene conocer
  7. 07Publicar Kimai en un dominio con HTTPS
  8. 08Crear usuarios desde la línea de comandos
  9. 09El modelo de datos: clientes, proyectos, actividades
  10. 10Tarifas y presupuestos
  11. 11Roles, equipos y permisos
  12. 12Facturar a partir de los partes de horas
  13. 13Preparar tu primera plantilla de factura
  14. 14IVA y menciones obligatorias
  15. 15API REST e integraciones
  16. 16Ampliar Kimai con plugins
  17. 17Copia de seguridad y restauración
  18. 18Actualizaciones sin sorpresas
  19. 19Resolución de problemas habituales
  20. 20Kimai frente a Toggl Track, Clockify y Harvest
  21. 21Dimensionar el VPS

¿Por qué alojar Kimai tú mismo?

Una herramienta de control horario concentra datos sensibles: quién trabaja para qué cliente, cuántas horas y a qué tarifa. En un servicio SaaS esa información reside en los servidores del proveedor y el coste crece con cada usuario. Si alojas Kimai en tu propio VPS, la base de datos queda bajo tu control, añades usuarios sin pagar licencias y decides tú cuándo actualizar.

  • Licencia MIT — sin tarifas de licencia ni límite de usuarios impuesto por el proveedor.
  • Facturación integrada — las facturas se generan directamente desde los partes de horas, sin módulos externos.
  • API REST documentada — conecta tus herramientas internas (tickets, RR. HH., paneles) a tus propios datos.
  • Soberanía de datos — horas, tarifas y fichas de clientes se quedan en tu base MySQL.
  • Stack ligero — un contenedor de aplicación y una base MySQL, holgado en un VPS de entrada.

Arquitectura: qué se ejecuta en el VPS

Kimai es una aplicación PHP construida sobre el framework Symfony. La versión 2 funciona con MySQL o MariaDB; SQLite ya no está soportado. La imagen oficial kimai/kimai2 tiene dos variantes: apache (servidor web incluido, escucha en el puerto 8001) y fpm (pensada para ir detrás de tu propio Nginx). La plantilla de ServOrbit usa kimai/kimai2:apache-latest con MySQL 8.0, de modo que el stack se reduce a dos contenedores.

Las piezas del stack

  • Contenedor kimai — Apache y PHP, la aplicación Symfony en /opt/kimai, puerto 8001 publicado solo en 127.0.0.1.
  • Contenedor db — MySQL 8.0 con un healthcheck mysqladmin ping: Kimai solo arranca cuando la base está lista.
  • Volumen kimai_db — los ficheros de datos de MySQL, es decir, todos tus partes de horas.
  • Volumen kimai_data — /opt/kimai/var/data, los ficheros subidos a la aplicación (plantillas de factura, documentos).
  • Volumen kimai_public — /opt/kimai/public/avatars, los avatares de los usuarios.
  • Proxy inverso — Nginx, Caddy o Traefik termina el HTTPS y reenvía las peticiones al puerto local 8001.

Desplegar Kimai en ServOrbit

El Marketplace de ServOrbit aprovisiona el stack completo sobre Ubuntu 24.04: Docker, MySQL 8.0, el contenedor de Kimai, los tres volúmenes y una contraseña de administrador generada. No necesitas un dominio para empezar.

  1. Lanzar el despliegue

    En tu área de cliente: Marketplace → ERP y Gestión → Kimai → Desplegar. ServOrbit crea el VPS, instala Docker y arranca el stack (MySQL 8 + Apache/PHP) automáticamente.

  2. Recuperar las credenciales

    Espera unos 60 segundos. La tarjeta de la app muestra tus credenciales: usuario [email protected] y contraseña generada.

  3. Conectarse sin dominio

    Abre un túnel SSH: ssh -L 8080:127.0.0.1:8001 root@<ip> y luego http://localhost:8080. Añade un dominio desde el panel cuando lo tengas listo.

  4. Crear cliente y proyecto

    Crea tu primer cliente, luego un proyecto vinculado y al menos una actividad. Fija una tarifa horaria o un presupuesto.

  5. Registrar las primeras horas

    Haz clic en ▶ para iniciar el temporizador y elige proyecto y actividad: Kimai registra tus horas en tiempo real.

En el primer inicio de sesión, abre tu perfil para sustituir [email protected] por una dirección real y cambiar la contraseña generada. Después reserva esa cuenta de superadministrador para la administración y crea cuentas nominativas para el trabajo diario.

Instalación manual con Docker Compose

Si prefieres instalar Kimai por tu cuenta en un VPS existente, aquí tienes un docker-compose.yml equivalente a la plantilla, con un volumen adicional para los plugins. Colócalo en un directorio dedicado, por ejemplo /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:

A continuación genera los secretos en un fichero .env, que Compose lee automáticamente, y arranca el stack. En el primer arranque el contenedor crea el esquema de la base y la cuenta de administrador definida por ADMINMAIL y 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

Variables de entorno que conviene conocer

  • DATABASE_URL — cadena de conexión de Doctrine: usuario, contraseña, host db, nombre de la base, charset=utf8mb4 y serverVersion. Como la contraseña va dentro de una URL, evita @, / o :; un secreto hexadecimal resuelve el problema.
  • APP_SECRET — clave de Symfony con la que se firman sesiones y tokens. Un valor aleatorio largo, generado una vez y sin tocarlo después: cambiarlo cierra la sesión de todos.
  • ADMINMAIL y ADMINPASS — la cuenta de superadministrador creada en el primer arranque. Con la instancia en marcha, gestiona las cuentas desde la interfaz o la consola.
  • TRUSTED_HOSTS — lista de nombres de host aceptados, separados por comas. Debe incluir tu dominio público; si no, Symfony rechaza las peticiones.
  • MAILER_URL — transporte de correo. La plantilla de ServOrbit lo fija en null://localhost, así que no se envía ningún correo. Indica un servidor SMTP para activar la recuperación de contraseña y las notificaciones.

Publicar Kimai en un dominio con HTTPS

  1. Apuntar el DNS

    Crea un registro A para kimai.your-domain.com hacia la IP pública del VPS y comprueba la propagación con dig +short kimai.your-domain.com.

  2. Configurar el proxy inverso

    El puerto 8001 solo escucha en 127.0.0.1, así que únicamente el proxy local puede alcanzarlo. Ejemplo de bloque 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;
        }
    }
  3. Obtener el certificado

    Con certbot y su plugin de Nginx, se emite el certificado de Let's Encrypt y el bloque server se completa para el puerto 443:

    apt install -y certbot python3-certbot-nginx
    certbot --nginx -d kimai.your-domain.com
  4. Declarar el dominio en Kimai

    Añade kimai.your-domain.com a TRUSTED_HOSTS y ejecuta docker compose up -d para recrear el contenedor. Si los enlaces generados siguen en http://, consulta la documentación de Kimai sobre proxies inversos: las cabeceras X-Forwarded-* solo se tienen en cuenta si vienen de un proxy de confianza.

  5. Cerrar lo que sobra

    En el cortafuegos abre solo los puertos 22, 80 y 443. MySQL no publica ningún puerto y no debe hacerlo.

Crear usuarios desde la línea de comandos

La interfaz basta para gestionar cuentas en el día a día, pero la consola Symfony de Kimai resulta muy útil para automatizar altas o recuperar un acceso. El comando kimai:user:create recibe un nombre de usuario, un correo y un rol, y después pide la contraseña:

docker compose exec kimai /opt/kimai/bin/console kimai:user:create alice [email protected] ROLE_TEAMLEAD

La misma consola ofrece kimai:reload para reconstruir la caché tras un cambio de configuración, y kimai:update para aplicar las migraciones de base de datos en instalaciones fuera de Docker. Ejecuta bin/console list kimai dentro del contenedor para ver los comandos disponibles en tu versión.

El modelo de datos: clientes, proyectos, actividades

Kimai organiza el tiempo en tres niveles. Un cliente lleva la moneda, la zona horaria y los datos de facturación. Un proyecto pertenece a un cliente y puede tener fechas de inicio y fin, un número de pedido y un presupuesto. Una actividad describe el tipo de trabajo (desarrollo, reunión, soporte); puede asociarse a un proyecto concreto o ser global y estar disponible en todos. Cada entrada del parte de horas une un usuario, un proyecto, una actividad, un intervalo de tiempo y, si hace falta, una descripción y etiquetas. Diseñar bien esta jerarquía desde el principio ahorra correcciones costosas: un cliente por entidad facturada, un proyecto por encargo o contrato y actividades globales para las tareas transversales.

Tarifas y presupuestos

  • Tarifa horaria — se define en el cliente, el proyecto, la actividad o el usuario; se aplica el nivel más específico a cada entrada.
  • Tarifa fija — un importe cerrado por entrada, útil para un servicio facturado a precio fijo sea cual sea su duración.
  • Tarifa interna — lo que realmente te cuesta una hora, separado del precio facturado, para medir la rentabilidad de cada proyecto.
  • Presupuesto en tiempo o en dinero — en un cliente, proyecto o actividad, con un indicador visual de consumo.
  • Presupuesto mensual o total — una bolsa de mantenimiento mensual se controla de forma distinta a un proyecto cerrado durante toda su vida.
  • Sobrepasos — los paneles muestran cuánto presupuesto se ha consumido y un ajuste de configuración permite autorizar o bloquear las entradas que lo superen.

Roles, equipos y permisos

Kimai trabaja con roles jerárquicos, y la pantalla Roles y permisos permite ajustar con detalle lo que cada rol ve y modifica. Los equipos completan el sistema: un cliente, proyecto o actividad restringido a un equipo solo es visible para sus miembros, y el jefe de equipo revisa y corrige las horas de su equipo sin ver el resto de la empresa. Para un colaborador externo, crea una cuenta de usuario limitada a un equipo dedicado.

  • ROLE_USER — registra y consulta sus propias horas en los proyectos a los que tiene acceso.
  • ROLE_TEAMLEAD — ve y modifica las horas de los miembros de sus equipos y consulta sus informes.
  • ROLE_ADMIN — gestiona clientes, proyectos, actividades, facturas y usuarios.
  • ROLE_SUPER_ADMIN — acceso completo, incluida la configuración del sistema y los permisos.

Facturar a partir de los partes de horas

El módulo de facturación convierte una selección de horas en un documento. Desde el menú Facturas eliges un cliente, un periodo, opcionalmente un proyecto y después una plantilla. Kimai calcula los importes a partir de las tarifas, muestra una vista previa y guarda la factura con un estado (pendiente, pagada, cancelada). Las entradas facturadas pueden marcarse como exportadas, lo que evita facturarlas dos veces y las protege de cambios posteriores.

Preparar tu primera plantilla de factura

  1. Crear la plantilla

    En Facturas → Plantillas, indica el emisor, la dirección, los datos bancarios, el plazo de pago y el texto del pie.

  2. Elegir el formato de salida

    Selecciona un formato PDF o HTML para un documento listo para enviar, o un formato ofimático si terminas la factura en otra herramienta.

  3. Definir la numeración

    Configura el formato del número de factura (prefijo, año, contador) para obtener una secuencia continua acorde con tu contabilidad.

  4. Configurar el impuesto

    Introduce el tipo impositivo aplicable en la plantilla; crea una plantilla por régimen si facturas a clientes con tipos distintos.

IVA y menciones obligatorias

Kimai calcula el impuesto a partir del tipo indicado en la plantilla, pero no conoce tu situación fiscal. Las menciones legales, el tipo aplicable y la conservación de facturas dependen de tu país y de tu forma jurídica: pide a tu asesor que revise la plantilla. Si llevas la contabilidad completa en un ERP como Dolibarr, Kimai puede seguir siendo la herramienta de registro de horas y su exportación servir de base para la factura final.

API REST e integraciones

Kimai expone una API REST que cubre clientes, proyectos, actividades, partes de horas y usuarios. Su documentación interactiva la sirve tu propia instancia en /api/doc, siempre al día con la versión instalada. Para autenticar un script, crea un token de API desde tu perfil de usuario y envíalo en una cabecera:

curl -s -H "Authorization: Bearer TU_TOKEN" \
  https://kimai.your-domain.com/api/timesheets

Un token hereda los permisos de su usuario: crea una cuenta de servicio con el rol mínimo necesario en lugar de usar el superadministrador. La API permite, por ejemplo, iniciar un temporizador desde un atajo, volcar las horas en un panel o sincronizar los proyectos con tu herramienta de tickets.

Ampliar Kimai con plugins

Kimai cuenta con una tienda de plugins en su web oficial, con extensiones gratuitas y de pago: gastos, campos personalizados, flujos de aprobación de partes de horas e importaciones desde otras herramientas. Un plugin es un directorio que se coloca en var/plugins/. Con Docker, monta ese directorio en un volumen o desaparecerá al recrear el contenedor; esa es la función de kimai_plugins en el compose anterior. Instalación típica:

docker compose cp NombreDelPluginBundle kimai:/opt/kimai/var/plugins/
docker compose exec kimai /opt/kimai/bin/console kimai:reload --env=prod

Algunos plugins añaden tablas y traen su propio comando de instalación; sigue la ficha del plugin y comprueba su compatibilidad con tu versión de Kimai antes de cada actualización.

Copia de seguridad y restauración

Casi todo está en la base MySQL; los volúmenes kimai_data y kimai_public completan la copia. Un volcado lógico es más portable que copiar en caliente los ficheros de 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 .

El nombre real del volumen lleva como prefijo el nombre del proyecto Compose: compruébalo con docker volume ls. Para restaurar, arranca un stack vacío con el mismo .env y vuelve a cargar el volcado:

docker compose exec -T db sh -c 'exec mysql -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DATABASE"' < kimai-AAAA-MM-DD.sql

Programa el volcado cada noche con cron, cópialo fuera del VPS (Restic, BorgBackup o almacenamiento de objetos) y prueba una restauración al menos una vez: una copia que nunca se ha restaurado es solo una hipótesis.

Actualizaciones sin sorpresas

  • Primero, la copia — un volcado justo antes de actualizar permite volver atrás si falla una migración.
  • Actualizar la imagen — docker compose pull kimai && docker compose up -d kimai, y después sigue docker compose logs -f kimai. Al arrancar, el contenedor aplica las migraciones de base de datos automáticamente.
  • Fijar una versión — en producción, sustituye apache-latest por una etiqueta versionada de la imagen para decidir cuándo subir de versión.
  • Leer las notas de versión — algunas versiones mayores cambian requisitos o el comportamiento de los plugins.
  • Exportar con regularidad — la exportación CSV o XLSX de los partes de horas es una copia legible, útil para una auditoría o una migración.

Resolución de problemas habituales

La mayoría de las incidencias de Kimai en Docker se deben a unas pocas causas conocidas. Empieza siempre por docker compose logs kimai y docker compose ps.

  • «Untrusted Host» o error 400 tras añadir un dominio — falta el nombre de host en TRUSTED_HOSTS. Añádelo y recrea el contenedor.
  • Error 500 y «Permission denied» en var/ — suele aparecer tras un comando de consola ejecutado con un usuario distinto al del servidor web. Restablece la propiedad con docker compose exec kimai chown -R www-data:www-data /opt/kimai/var y después kimai:reload.
  • Un cambio de configuración no surte efecto — la caché de Symfony sirve la versión anterior: docker compose exec kimai /opt/kimai/bin/console kimai:reload --env=prod.
  • Kimai se reinicia en bucle en el primer arranque — la base no está lista o DATABASE_URL es incorrecta. Revisa el healthcheck de db y las credenciales del .env.
  • Enlaces en http:// detrás del proxy HTTPS — las cabeceras X-Forwarded-Proto no se envían o no se consideran de confianza; revisa la configuración del proxy.
  • Contraseña olvidada sin correo configurado — MAILER_URL apunta a null://: restablece la contraseña desde una cuenta de administrador o crea un nuevo administrador por consola.

Kimai frente a Toggl Track, Clockify y Harvest

Desplace la tabla

CriterioKimai (self-hosted)Toggl TrackClockifyHarvest
LicenciaOpen source (MIT)PropietariaPropietariaPropietaria
AlojamientoTu VPSSaaS del proveedorSaaS del proveedorSaaS del proveedor
Ubicación de los datosTu base MySQLInfraestructura del proveedorInfraestructura del proveedorInfraestructura del proveedor
Modelo de costeSolo el servidor, sin cuota por usuarioNivel gratuito limitado y después suscripciónNivel gratuito y después suscripciónNivel gratuito limitado y después suscripción
FacturaciónMódulo integrado (plantillas, numeración, impuestos)Según el planSegún el planIntegrada en el producto
APIREST, tokens, documentación incluidaRESTRESTREST
PersonalizaciónCódigo fuente, plugins, configuraciónAjustes e integracionesAjustes e integracionesAjustes e integraciones

Dimensionar el VPS

Kimai es austero: la carga procede sobre todo de MySQL y de los informes que abarcan periodos largos. Para un freelance o un equipo pequeño bastan 1 vCPU y de 1 a 2 GB de RAM. A partir de una veintena de usuarios activos, o si generas a menudo informes anuales y exportaciones voluminosas, prevé 2 vCPU y 4 GB, lo que deja margen a la caché InnoDB de MySQL. El disco necesario es modesto: unos pocos gigabytes cubren años de partes de horas, pero reserva espacio para los volcados locales antes de enviarlos fuera del servidor.

Antes de invitar al equipo, fija las reglas en Ajustes: redondeo de duraciones, si se permiten entradas en el futuro y bloqueo de los periodos ya facturados. Es mucho más sencillo decidirlo en una instancia vacía que sobre meses de historial.

Despliega Kimai en tu VPS en 60 segundos

ServOrbit preconfigurea el stack completo (Apache/PHP + MySQL 8) y genera tus credenciales de admin — listo para registrar tus primeras horas.

¿Necesita ayuda?

Consulte nuestro centro de ayuda y nuestra FAQ, o contacte con nuestro equipo: llamada, WhatsApp o correo electrónico. Soporte en francés, inglés y árabe.

Escribir por WhatsAppse abre en una pestaña nueva