Solidtime
Modern open-source time-tracking app for freelancers and agencies
Alternative to: toggl, clockify, harvest
Solidtime is a modern, open-source time tracking application built for freelancers and agencies. It lets teams track time, manage projects, tasks, and clients, configure billable rates at multiple levels, and supports multiple organizations with role-based permissions, plus data import from Toggl and Clockify.
Solidtime Docker Compose example
Self-host Solidtime on your own server, homelab, or VPS starting from this Docker Compose example.
It runs Solidtime in Docker containers using the official solidtime/solidtime:latest, solidtime/solidtime:latest, solidtime/solidtime:latest, postgres:15, gotenberg/gotenberg:8 images, with persistent volumes and automatic restarts preconfigured.
Review the environment variables and adjust them to your setup, save the file as compose.yml (or docker-compose.yml), and start the stack with docker compose up -d.
# Shared application environment for the solidtime PHP containers (app,
# scheduler, queue). Anchored here and merged into each service below.
x-solidtime-env: &solidtime-env
APP_NAME: "solidtime"
APP_ENV: "production"
APP_DEBUG: "false"
# Public URL where solidtime is reached, including the scheme.
APP_URL: "https://solidtime.example.com"
# Redirect all generated URLs to HTTPS (the reverse proxy terminates TLS).
APP_FORCE_HTTPS: "true"
# Trust the reverse proxy for the X-Forwarded-* headers.
TRUSTED_PROXIES: "*"
# Laravel application key. Generate one with: php artisan key:generate --show
APP_KEY: "base64:t0s7QVnBv0PWt/KtLQdMPueJJobdHS1idvEmMYXB6B4="
# RSA keypair for Laravel Passport (OAuth / API tokens). Generate both with:
# docker compose exec app php artisan self-host:generate-keys
PASSPORT_PRIVATE_KEY: ""
PASSPORT_PUBLIC_KEY: ""
# Comma-separated list of super-admin email addresses.
SUPER_ADMINS: ""
LOG_CHANNEL: "stderr_daily"
LOG_LEVEL: "info"
DB_CONNECTION: "pgsql"
DB_HOST: "database"
DB_PORT: "5432"
# SSL mode for the bundled Postgres (which has no TLS): prefer plaintext.
DB_SSLMODE: "prefer"
DB_DATABASE: "solidtime"
DB_USERNAME: "solidtime"
# Password for the bundled Postgres database user.
DB_PASSWORD: "changeme"
QUEUE_CONNECTION: "database"
# Run pending database migrations automatically on container start.
AUTO_DB_MIGRATE: "true"
MAIL_MAILER: "smtp"
# SMTP server hostname used to send invitations and notifications.
MAIL_HOST: "changeme"
# SMTP server port.
MAIL_PORT: "587"
MAIL_ENCRYPTION: "tls"
MAIL_FROM_ADDRESS: "no-reply@solidtime.example.com"
MAIL_FROM_NAME: "solidtime"
# SMTP username.
MAIL_USERNAME: ""
# SMTP password.
MAIL_PASSWORD: ""
FILESYSTEM_DISK: "local"
PUBLIC_FILESYSTEM_DISK: "public"
GOTENBERG_URL: "http://gotenberg:3000"
services:
app:
image: solidtime/solidtime:latest
restart: unless-stopped
environment:
<<: *solidtime-env
CONTAINER_MODE: "http"
volumes:
- app_storage:/var/www/html/storage
healthcheck:
test: ["CMD", "curl", "--fail", "http://localhost:8000/health-check/up"]
interval: 10s
timeout: 5s
retries: 10
depends_on:
database:
condition: service_healthy
scheduler:
image: solidtime/solidtime:latest
restart: unless-stopped
environment:
<<: *solidtime-env
CONTAINER_MODE: "scheduler"
volumes:
- app_storage:/var/www/html/storage
healthcheck:
test: ["CMD", "healthcheck"]
interval: 30s
timeout: 5s
retries: 5
depends_on:
database:
condition: service_healthy
queue:
image: solidtime/solidtime:latest
restart: unless-stopped
environment:
<<: *solidtime-env
CONTAINER_MODE: "worker"
WORKER_COMMAND: "php /var/www/html/artisan queue:work"
volumes:
- app_storage:/var/www/html/storage
healthcheck:
test: ["CMD", "healthcheck"]
interval: 30s
timeout: 5s
retries: 5
depends_on:
database:
condition: service_healthy
database:
image: postgres:15
restart: unless-stopped
environment:
POSTGRES_DB: "solidtime"
POSTGRES_USER: "solidtime"
# Must match DB_PASSWORD above (internal-only; Postgres is not published).
POSTGRES_PASSWORD: "changeme"
volumes:
- database_storage:/var/lib/postgresql/data
healthcheck:
test: ["CMD", "pg_isready", "-q", "-d", "solidtime", "-U", "solidtime"]
interval: 10s
timeout: 5s
retries: 5
gotenberg:
image: gotenberg/gotenberg:8
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "--silent", "--fail", "http://localhost:3000/health"]
interval: 10s
timeout: 5s
retries: 5
volumes:
app_storage:
database_storage:
Values set to changeme are required — replace them with your own
values before starting Solidtime.
Prefer a managed setup? WinterFlow installs, configures, and updates Solidtime for you using this same Docker Compose configuration.