Time Tracking Made Easy: Installing Timetagger with Docker Compose
In this guide, you'll learn how to install Timetagger, an open-source time tracking tool, on your own server using Docker Compose.

Table of Contents
- Introduction
- What You Need (Prerequisites)
- Step 1: Connect to the Server and Create Directory Structure
- Step 2: Create and Configure the compose.yml File
- Step 3: Create the Data Directory
- Step 4: Generate Credentials
- Step 5: Insert Credentials
- Step 6: Start Timetagger
- Step 7: Access and Test Timetagger
- First Steps with Timetagger
- Conclusion
Introduction
In today’s working world, whether in the office or remotely, tracking work hours is often essential – be it for project billing, self-organization, or simply to keep an overview of one’s day. While there are many cloud services, some prefer full control over their data. This is where Timetagger comes in: An open-source time tracking tool with a simple, interactive web interface that you can host on your own server.
This post guides you step-by-step through the installation of Timetagger using Docker Compose. Docker simplifies the deployment of applications by packaging them along with their dependencies into containers. Docker Compose extends this by enabling the configuration and starting of multi-container applications (even though Timetagger is just one container here) in a single file. This guide is aimed at beginners but also explains the background, so you understand the ‘why’ behind the clicks.
What You Need (Prerequisites)
Before we start, make sure you have the following available:
- A Server: This could be a small Raspberry Pi on your home network, a virtual server from a hosting provider, or another Linux machine that runs continuously.
- SSH Access: You need a way to connect to your server via the command line (e.g., using Terminal/Console or a tool like PuTTY).
- Docker and Docker Compose: These must be installed on your server.
- If Docker is not yet installed, follow the official documentation for your operating system: Install Docker Engine
- Docker Compose is often included as a plugin with Docker or can be installed separately: Install Docker Compose
- Ensure your user is allowed to run Docker commands (for example, by using
sudo
).
Step 1: Connect to the Server and Create Directory Structure
Open your terminal or SSH console and connect to your server:
ssh your_username@your_server_ip
Replace your_username
and your_server_ip
accordingly.
After successful login, we create a directory for our Timetagger project and change into it directly:
mkdir timetagger && cd timetagger
Inside this timetagger
directory, we will soon create the configuration file and a subdirectory for persistent data.
Step 2: Create and Configure the compose.yml
File
Docker Compose uses a YAML file (typically compose.yml
or docker-compose.yml
) to define the services, networks, and volumes for an application. Create this file using a text editor of your choice (e.g., nano
):
nano compose.yml
Now, let’s add the content. We’ll base it on the template from the Timetagger repository (almarklein/timetagger
), but adapt it slightly:
services:
timetagger:
image: ghcr.io/almarklein/timetagger:latest # The official Docker image for Timetagger
container_name: timetagger # A unique name for the running container
restart: unless-stopped # Automatically restarts the container unless manually stopped
ports:
- "1234:80" # Maps port 1234 on your server to port 80 inside the container
volumes:
- ./data:/data # Persistently stores Timetagger data in the "data" subfolder on your server
environment:
- TIMETAGGER_LOG_LEVEL=warn # Sets the log level (e.g., debug, info, warn, error)
- TIMETAGGER_CREDENTIALS=your_user:YOUR_BCRYPT_HASH # Your login credentials (to be generated shortly)
- TZ=Europe/Berlin # Sets the timezone
Explanation of the Configuration:
services
: Defines the individual applications (only one here:timetagger
).image
: Specifies which Docker image to use.ghcr.io/almarklein/timetagger:latest
fetches the latest version from the GitHub Container Registry.container_name
: Gives the container a fixed name, making management easier.restart: unless-stopped
: An important setting for services that should always be running. The container restarts automatically, e.g., after a server reboot.ports
: This defines how you access Timetagger. The format is"HOST_PORT:CONTAINER_PORT"
. We forward requests to port1234
on your server to port80
, where the web server inside the Timetagger container is listening. You can choose the host port (1234
) freely, just ensure it’s not already in use on your server. If you use a reverse proxy (like Nginx Proxy Manager or Traefik) to access Timetagger, e.g., under a subdomain with HTTPS, you might omit thisports
section entirely and add network settings for the proxy instead.volumes
: To ensure your tracked times and settings persist even after restarting or updating the container, the data must be stored outside the container. The format isHOST_PATH:CONTAINER_PATH
. We map the/data
folder inside the container to a subdirectory nameddata
on your server (relative to thecompose.yml
file).environment
: Environment variables are set here to influence the container’s behavior.TIMETAGGER_LOG_LEVEL
: Controls how verbose Timetagger is in the logs.warn
is a good middle ground – it shows warnings and errors, but not purely informational messages.TIMETAGGER_CREDENTIALS
: Your login details go here. The format isusername:passwordhash
. Important: Never store your password in plain text here! We will generate a secure hash shortly.TZ
(optional): Sets the timezone for the container, which is important for correct timestamps.
Step 3: Create the Data Directory
According to our compose.yml
, Timetagger expects the data in the data
subdirectory. Let’s create this now in the main timetagger
directory (where compose.yml
is located):
mkdir data
Your directory structure should now look like this:
timetagger/
├── compose.yml
└── data/
Step 4: Generate Credentials
Timetagger uses bcrypt for hashing passwords. This is a secure method from which the original password cannot be recovered.
-
Open the Timetagger helper page in your browser: timetagger.app/cred
-
Enter your desired username (e.g.,
admin
or your name). -
Enter a secure password.
-
Click “Generate”.
-
Copy the line under “For Docker Compose (environment variable):“. It should start with your username, followed by a colon and a hash starting with
$$
(e.g.,admin:$$2b$$...
).Alternative: If you prefer not to use the website, you can also generate bcrypt hashes on the command line using tools like
htpasswd
(from theapache2-utils
package) or using Python libraries. Ensure the hash is in bcrypt format and escape the dollar signs ($
) correctly.
Step 5: Insert Credentials
Open the compose.yml
again with your editor:
nano compose.yml
Replace the line your_user:YOUR_BCRYPT_HASH
under environment
with the string you just copied. Make sure the indentation remains correct.
# ... (other parts of the file) ...
environment:
- TIMETAGGER_LOG_LEVEL=warn
- TIMETAGGER_CREDENTIALS=admin:$$2b$$12$$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # <-- Replace with your generated credentials
- TZ=Europe/Berlin
# ... (Rest of the file) ...
Save the file and close the editor (in nano
: Ctrl+X
, then Y
, and Enter
).
Step 6: Start Timetagger
Now we are ready to start the Timetagger container. In the timetagger
directory (where your compose.yml
is located), execute the following command:
sudo docker compose up -d
sudo
: Necessary if your user is not in thedocker
group.docker compose up
: Starts the services defined incompose.yml
.-d
: Starts the containers in “detached” mode, i.e., in the background. You get your command prompt back.
Docker will now download the Timetagger image (if not already present locally) and start the container according to your configuration.
You can check the container’s status with:
sudo docker compose ps
And follow the logs live (useful for troubleshooting) with:
sudo docker compose logs -f
(Exit with Ctrl+C
)
Step 7: Access and Test Timetagger
Open a web browser on your computer and enter your server’s IP address followed by the port you specified in the compose.yml
(in our example, 1234
):
http://your_server_ip:1234
You should see the Timetagger start page.
- Click on “App” and then “Login”.
- Log in with the username and password you used in Step 4.
If the login works – Congratulations! You have successfully installed Timetagger on your own server.
First Steps with Timetagger
Now you can start tracking your times:
- Start Recording: Click “Record”. Enter a description of what you are doing. Use hashtags (e.g.,
#projectA
,#meeting
) to categorize entries. The timer starts running. - Stop/Start New Recording: Click on the running entry at the bottom to stop it. You can immediately start a new entry that follows seamlessly.
- Adding Past Entries: Click on the timeline at the top to select past time periods and add entries manually.
- Reports: Use the “Report” function to group and export your tracked times based on various criteria (e.g., as a PDF).
- Views: Switch between day, week, and month views to get an overview.
Timetagger suggests previously used tags, which helps maintain consistency.
Conclusion
Installing Timetagger with Docker Compose is a manageable process that gives you full control over your time tracking data. Thanks to Docker, the setup is isolated and easy to manage. You now have a powerful yet easy-to-use tool at hand to manage your time effectively.
You can find more information and advanced configurations in the official Timetagger documentation or the GitHub repository. A good next step might be to set up a reverse proxy to access Timetagger securely via HTTPS and a custom subdomain.
Happy time tracking!