# Leantime

Project management system for teams that do not have a dedicated project manager.

- Replaces: [Asana](https://openlogs.fyi/alternatives/asana), [Jira](https://openlogs.fyi/alternatives/jira)
- Summary: Paid project management services, such as Asana and Jira.
- Stack: PHP (language), MySQL (database)
- Deployment: docker_compose
- License: AGPL-3.0 (osi) [source](https://github.com/Leantime/leantime/blob/8464a2eac9f6206f85e03269909c5227ea12f8ea/LICENSE)
- Business model: unknown. The README at the pinned commit does not state a business model, so it stays unknown. ([source](https://github.com/Leantime/leantime/blob/8464a2eac9f6206f85e03269909c5227ea12f8ea/README.md), read 2026-10-22)
- Difficulty: hard. 3 services (2 database or broker: mysql), 5 volume mounts, 1 env value to set, host access: cap_add. Heuristic score 7 of 11: hard.
- Requirements: not stated
- Repository: [Leantime/leantime](https://github.com/Leantime/leantime)

## Install

1. Docker with the Compose plugin ([source](https://github.com/Leantime/docker-leantime/blob/8718fac482d8af4ff98cb995baf5aa23d5e90bec/README.md))

   ```text
   A host with Docker and the Docker Compose plugin. This entry runs from a compose file.
   ```

2. Save the compose file as docker-compose.yml ([source](https://github.com/Leantime/docker-leantime/blob/8718fac482d8af4ff98cb995baf5aa23d5e90bec/docker-compose.yml))

   ```yaml
   version: '3.3'
   
   services:
     leantime_db:
       image: mysql:8.4
       container_name: mysql_leantime
       volumes:
         - db_data:/var/lib/mysql
       restart: unless-stopped
       env_file: ./.env                                        # Environment file with settings
       networks:
         - leantime-net
       command: --character-set-server=UTF8MB4 --collation-server=UTF8MB4_unicode_ci
       healthcheck:
         test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
         interval: 30s
         timeout: 10s
         retries: 3
   
     leantime:
       image: leantime/leantime:${LEAN_VERSION:-latest}
       restart: unless-stopped
       env_file: ./.env                                        # Environment file with settings
       # Add security options
       security_opt:
         - no-new-privileges:true
       # Add capabilities
       cap_add:
         # - CAP_NET_BIND_SERVICE
         - CAP_CHOWN
         - CAP_SETGID
         - CAP_SETUID
       ports:
         - "${LEAN_PORT:-8080}:8080"
       networks:
         - leantime-net
       volumes:
         - public_userfiles:/var/www/html/public/userfiles     # Volume to store public files, logo etc
         - userfiles:/var/www/html/userfiles                   # Original volume name for compatibility
         - plugins:/var/www/html/app/Plugins                   # Plugin storage
         - logs:/var/www/html/storage/logs                     # Log storage
       depends_on:
         leantime_db:
           condition: service_healthy
   
     # Add a helper container for volume permissions
     # Run via docker compose --profile mysql_helper up -d
     mysql_helper:
       image: mysql:8.4
       command: chown -R mysql:mysql /var/lib/mysql
       volumes:
         - db_data:/var/lib/mysql
       user: root
       profiles: [ "helper" ]
   
   volumes:
     db_data:
     userfiles:                                               # New volume for public files
     public_userfiles:
     plugins:
     logs:
   
   networks:
     leantime-net:
   ```

3. Save as .env next to the compose file ([source](https://github.com/Leantime/docker-leantime/blob/8718fac482d8af4ff98cb995baf5aa23d5e90bec/sample.env))

   ```dotenv
   # This is a sample configuration file with all possible configuration options.
   # If you don't want to maintain a file like this you can pass in all variables via Server Variables
   
   ## Minimum Configuration, these are required for installation
   
   # NOTE: PUID/PGID are BUILD arguments, not runtime settings. The published
   # leantime/leantime images are built with uid/gid 1000 and setting these here has
   # NO effect — they only apply if you build the image yourself and pass them with
   # --build-arg. To run the published image under a different uid, set `user:` in
   # docker-compose.yml with group 0, e.g. user: "1001:0".
   #
   # Upgrading an existing install? Docker only seeds a named volume from the image
   # when the volume is EMPTY, so userfiles/plugins/logs volumes created by an older
   # image keep their original ownership and will still throw permission errors under
   # a new uid. Fix them once from the host, e.g.
   #   docker run --rm -v leantime_userfiles:/v alpine chgrp -R 0 /v && chmod -R g=u /v
   # (repeat per volume), or recreate the volumes if you have no data to keep.
   
   LEAN_PORT = '8080'                                 # The port to expose and access Leantime
   LEAN_APP_URL = ''                                  # Base URL, needed for subfolder or proxy installs (including http:// or https://)
   LEAN_APP_DIR = ''                                  # Base of application without trailing slash (used for cookies), e.g, /leantime
   
   LEAN_DEBUG = 0                                     # Debug flag
   
   # Database - MySQL container
   MYSQL_ROOT_PASSWORD = 'changeme123'                # MySQL root password
   MYSQL_DATABASE = 'leantime'                        # Database name
   MYSQL_USER = 'lean'                                # Database username
   MYSQL_PASSWORD = 'changeme123'                     # Database password
   
   # Database - leantime container
   LEAN_DB_HOST = 'mysql_leantime'                    # Database host
   LEAN_DB_USER = 'lean'                              # Database username (needs to be the same as MYSQL_USER)
   LEAN_DB_PASSWORD = 'changeme123'                   # Database password (needs to be the same as MYSQL_PASSWORD)
   LEAN_DB_DATABASE = 'leantime'                      # Database name (needs to be the same as MYSQL_DATABASE)
   LEAN_DB_PORT = '3306'                              # Database port
   
   ## Session Management
   LEAN_SESSION_PASSWORD = '3evBlq9zdUEuzKvVJHWWx3QzsQhturBApxwcws2m'  # Salting sessions, replace with a strong password
   LEAN_SESSION_EXPIRATION = 28800                    # How many seconds after inactivity should we logout?  28800seconds = 8hours
   LEAN_SESSION_SECURE = false                        # Serve cookies via https only? Set to true when using https, set to false when using http. 
   
   
   ## Optional Configuration, you may omit these from your .env file
   
   ## Default Settings
   LEAN_SITENAME = 'Leantime'                         # Name of your site, can be changed later
   LEAN_LANGUAGE = 'en-US'                            # Default language
   LEAN_DEFAULT_TIMEZONE = 'America/Los_Angeles'      # Set default timezone
   LEAN_LOG_PATH = ''                                 # Default Log Path (including filename), if not set /logs/error.log will be used
   LEAN_DISABLE_LOGIN_FORM = false                    # If true then don't show the login form (useful only if additional auth method[s] are available)
   
   ## Look & Feel, these settings are available in the UI and can be overwritten there.
   LEAN_LOGO_PATH = '/dist/images/logo.svg'           # Default logo path, can be changed later
   LEAN_PRINT_LOGO_URL = '/dist/images/logo.png'      # Default logo URL use for printing (must be jpg or png format)
   LEAN_DEFAULT_THEME = 'default'                     # Default theme
   LEAN_PRIMARY_COLOR = '#006d9f'                     # Primary Theme color
   LEAN_SECONDARY_COLOR =' #00a886'                   # Secondary Theme Color
   
   
   ## Fileuploads
   
   # Local File Uploads
   LEAN_USER_FILE_PATH = 'userfiles/'                 # Local relative path to store uploaded files (if not using S3)
   LEAN_DB_BACKUP_PATH = 'backupdb/'                  # Local relative path to store backup files, need permission to write
   
   # S3 File Uploads
   LEAN_USE_S3 = false                                # Set to true if you want to use S3 instead of local files
   LEAN_S3_KEY = ''                                   # S3 Key
   LEAN_S3_SECRET = ''                                # S3 Secret
   LEAN_S3_BUCKET = ''                                # Your S3 bucket
   LEAN_S3_USE_PATH_STYLE_ENDPOINT = false            # Sets the endpoint style: false => https://[bucket].[endpoint] ; true => https://[endpoint]/[bucket]
   LEAN_S3_REGION = ''                                # S3 region
   LEAN_S3_FOLDER_NAME = ''                           # Foldername within S3 (can be empty)
   LEAN_S3_END_POINT = null                           # S3 EndPoint S3 Compatible (https://sfo2.digitaloceanspaces.com)
   
   ## Email
   LEAN_EMAIL_RETURN = ''                             # Return email address, needs to be valid email address format
   LEAN_EMAIL_USE_SMTP = false                        # Use SMTP? If set to false, the default php mail() function will be used
   LEAN_EMAIL_SMTP_HOSTS = ''                         # SMTP host
   LEAN_EMAIL_SMTP_AUTH = true                        # SMTP authentication required
   LEAN_EMAIL_SMTP_USERNAME = ''                      # SMTP username
   LEAN_EMAIL_SMTP_PASSWORD = ''                      # SMTP password
   LEAN_EMAIL_SMTP_AUTO_TLS = true                    # SMTP Enable TLS encryption automatically if a server supports it
   LEAN_EMAIL_SMTP_SECURE = ''                        # SMTP Security protocol (usually one of: TLS, SSL, STARTTLS)
   LEAN_EMAIL_SMTP_SSLNOVERIFY = false                # SMTP Allow insecure SSL: Don't verify certificate, accept self-signed, etc.
   LEAN_EMAIL_SMTP_PORT = ''                          # Port (usually one of 25, 465, 587, 2526)
   
   ## LDAP
   LEAN_LDAP_USE_LDAP = false                         # Set to true if you want to use LDAP
   LEAN_LDAP_LDAP_DOMAIN = ''                         # Domain name after username@ so users can login without domain definition
   LEAN_LDAP_LDAP_TYPE = 'OL'                         # Select the correct directory type. Currently Supported: OL - OpenLdap, AD - Active Directory
   LEAN_LDAP_HOST = ''                                # FQDN
   LEAN_LDAP_PORT = 389                               # Default Port
   LEAN_LDAP_URI = ''                                 # LDAP URI as alternative to hostname and port. Uses ldap://hostname:port
   LEAN_LDAP_DN = ''                                  # Location of users, example: CN=users,DC=example,DC=com
                                                      # Leantime->Ldap attribute mapping
   LEAN_LDAP_KEYS="{
           \"username\":\"uid\",
           \"groups\":\"memberOf\",
           \"email\":\"mail\",
           \"firstname\":\"displayname\",
           \"lastname\":\"\",
           \"phone\":\"telephoneNumber\",
           \"jobTitle\":\"title\"
           \"jobLevel\":\"level\"
           \"department\":\"department\"
   
   }"
   
   # For AD use these default attributes
   # LEAN_LDAP_KEYS="{
   #        \"username\":\"cn\",
   #        \"groups\":\"memberOf\",
   #        \"email\":\"mail\",
   #        \"firstname\":\"givenName\",
   #        \"lastname\":\"sn\",
   #        \"phone\":\"telephoneNumber\",
   #        \"jobTitle\":\"title\"
   #        \"jobLevel\":\"level\"
   #        \"department\":\"department\"
   #      }"
   
   LEAN_LDAP_DEFAULT_ROLE_KEY = 20;                   # Default Leantime Role on creation. (set to editor)
   
   # Default role assignments upon first login.
   # optional - Can be updated later in user settings for each user
   LEAN_LDAP_GROUP_ASSIGNMENT="{
                  \"5\": {
                    \"ltRole\":\"readonly\",
                    \"ldapRole\":\"readonly\"
                  },
                  \"10\": {
                    \"ltRole\":\"commenter\",
                     \"ldapRole\":\"commenter\"
                  },
                  \"20\": {
                    \"ltRole\":\"editor\",
                     \"ldapRole\":\"editor\"
                  },
                  \"30\": {
                    \"ltRole\":\"manager\",
                     \"ldapRole\":\"manager\"
                  },
                  \"40\": {
                    \"ltRole\":\"admin\",
                     \"ldapRole\":\"administrators\"
                  },
                  \"50\": {
                    \"ltRole\":\"owner\",
                    \"ldapRole\":\"administrators\"
                  }
   }"
   
   ## OpenID Connect
   # required
   LEAN_OIDC_ENABLE = false
   LEAN_OIDC_CLIENT_ID =
   LEAN_OIDC_CLIENT_SECRET =
   
   # required - the URL for your provider (examples down below)
   #LEAN_OIDC_PROVIDER_URL =
   
   #Create User if it doesn't exist in Leantime db, otherwise fail login
   LEAN_OIDC_CREATE_USER = false
   
   # Default role for users created via OIDC (20 is editor)
   LEAN_OIDC_DEFAULT_ROLE = 20
   
   # optional - these will be read from the well-known configuration if possible
   #LEAN_OIDC_AUTH_URL_OVERRIDE =
   #LEAN_OIDC_TOKEN_URL_OVERRIDE =
   #LEAN_OIDC_JWKS_URL_OVERRIDE =
   #LEAN_OIDC_USERINFO_URL_OVERRIDE =
   
   # optional - override the public key for RSA validation
   #LEAN_OIDC_CERTIFICATE_STRING =
   #LEAN_OIDC_CERTIFICATE_FILE =
   
   # optional - override the requested scopes
   #LEAN_OIDC_SCOPES =
   
   # optional - override the keys used for these fields
   #LEAN_OIDC_FIELD_EMAIL =
   #LEAN_OIDC_FIELD_FIRSTNAME =
   #LEAN_OIDC_FIELD_LASTNAME =
   #LEAN_OIDC_FIELD_PHONE =
   #LEAN_OIDC_FIELD_JOBTITLE =
   #LEAN_OIDC_FIELD_JOBLEVEL=
   #LEAN_OIDC_FIELD_DEPARTMENT =
   
   ## OpenID Connect setting for GitHub
   #LEAN_OIDC_PROVIDER_URL = https://token.actions.githubusercontent.com/
   #LEAN_OIDC_AUTH_URL_OVERRIDE = https://github.com/login/oauth/authorize
   #LEAN_OIDC_TOKEN_URL_OVERRIDE = https://github.com/login/oauth/access_token
   #LEAN_OIDC_USERINFO_URL_OVERRIDE = https://api.github.com/user,https://api.github.com/user/emails
   #LEAN_OIDC_SCOPES = user:email,read:user
   #LEAN_OIDC_FIELD_EMAIL = 0.email
   #LEAN_OIDC_FIELD_FIRSTNAME = name
   
   
   ## Redis (for session storage and cache)
   LEAN_USE_REDIS = false                             # Set to true to use redis as session cache
   LEAN_REDIS_URL = ''                                # Add URL path such as tcp://1.2.3.4:6379. If you are using a password, add ?auth=yourverycomplexpasswordhere to your URL
   LEAN_REDIS_HOST = ''
   LEAN_REDIS_PORT = 6379
   LEAN_REDIS_PASSWORD = ''
   LEAN_REDIS_SCHEME = ''
   
   ## Rate limiting
   LEAN_RATELIMIT_GENERAL = 1000
   LEAN_RATELIMIT_API = 10
   LEAN_RATELIMIT_AUTH = 20
   ```

4. What the compose file check ran with ([source](https://github.com/Leantime/docker-leantime/blob/8718fac482d8af4ff98cb995baf5aa23d5e90bec/README.md))

   ```text
   The compose file check ran together with sample.env from the same commit, saved as .env. The folder held only these files. The README of the project's docker-leantime repository tells the reader to clone it, copy sample.env to .env, edit the settings and run docker compose up -d.
   ```

5. Start it ([source](https://github.com/Leantime/docker-leantime/blob/8718fac482d8af4ff98cb995baf5aa23d5e90bec/README.md))

   ```bash
   docker compose up -d
   ```

6. Open the app ([source](https://github.com/Leantime/docker-leantime/blob/8718fac482d8af4ff98cb995baf5aa23d5e90bec/docker-compose.yml))

   ```text
   Open http://localhost:8080. The compose file publishes host port 8080 for the leantime service.
   ```

Compose file check: config_ok on 2026-10-22.

## Gotchas and maintenance

### Gotchas

- Some images use the latest tag or no tag: Images without a pinned version: leantime: leantime/leantime:${LEAN_VERSION:-latest}. A later pull can get a different version. ([source](https://github.com/Leantime/docker-leantime/blob/8718fac482d8af4ff98cb995baf5aa23d5e90bec/docker-compose.yml), checked 2026-10-22)
- The compose file publishes host ports: Host ports: 8080 (leantime). A port without a host address listens on all host network interfaces. ([source](https://github.com/Leantime/docker-leantime/blob/8718fac482d8af4ff98cb995baf5aa23d5e90bec/docker-compose.yml), checked 2026-10-22)
- Some services get elevated host access: leantime adds Linux capabilities. ([source](https://github.com/Leantime/docker-leantime/blob/8718fac482d8af4ff98cb995baf5aa23d5e90bec/docker-compose.yml), checked 2026-10-22)
- The example env file sample.env has placeholder values: The example env file sets placeholder text for: MYSQL_ROOT_PASSWORD, MYSQL_PASSWORD, LEAN_DB_PASSWORD. Replace them before you rely on the install. ([source](https://github.com/Leantime/docker-leantime/blob/8718fac482d8af4ff98cb995baf5aa23d5e90bec/sample.env), checked 2026-10-22)

### Signals

Computed from a GitHub snapshot taken 2026-10-22.

- Open issues and pull requests: 236
- Stars: 11882, forks: 1156
- Last push: 2026-10-21 (1 days ago)
- Latest release: v3.12.0 on 2026-10-15 (7 days ago)

## Sources

- [Repository: https://github.com/Leantime/leantime](https://github.com/Leantime/leantime)
- [License: https://github.com/Leantime/leantime/blob/8464a2eac9f6206f85e03269909c5227ea12f8ea/LICENSE](https://github.com/Leantime/leantime/blob/8464a2eac9f6206f85e03269909c5227ea12f8ea/LICENSE)
- [Business model: https://github.com/Leantime/leantime/blob/8464a2eac9f6206f85e03269909c5227ea12f8ea/README.md](https://github.com/Leantime/leantime/blob/8464a2eac9f6206f85e03269909c5227ea12f8ea/README.md)
- [Compose file: https://github.com/Leantime/docker-leantime/blob/8718fac482d8af4ff98cb995baf5aa23d5e90bec/docker-compose.yml](https://github.com/Leantime/docker-leantime/blob/8718fac482d8af4ff98cb995baf5aa23d5e90bec/docker-compose.yml)
- [Install step: https://github.com/Leantime/docker-leantime/blob/8718fac482d8af4ff98cb995baf5aa23d5e90bec/README.md](https://github.com/Leantime/docker-leantime/blob/8718fac482d8af4ff98cb995baf5aa23d5e90bec/README.md)
- [Install step: https://github.com/Leantime/docker-leantime/blob/8718fac482d8af4ff98cb995baf5aa23d5e90bec/sample.env](https://github.com/Leantime/docker-leantime/blob/8718fac482d8af4ff98cb995baf5aa23d5e90bec/sample.env)

---
Canonical: https://openlogs.fyi/tools/leantime  
Last updated: 2026-10-22
