torrust-tracker-deployer 0.1.0

Torrust Tracker Deployer - Deployment Infrastructure with Ansible and OpenTofu
Documentation
# Tracker Database Driver Double Specification Issue

**Issue Date**: December 14, 2025  
**Affected Component**: Torrust Tracker Container (`torrust/tracker:develop`)  
**Status**: Documented - Issue to be filed in tracker repository

## Problem Description

The tracker container's entrypoint script requires the database driver to be specified **twice**:

1. **In the tracker configuration file** (`tracker.toml`): `[core.database] driver = "mysql"`
2. **As an environment variable**: `TORRUST_TRACKER_CONFIG_OVERRIDE_CORE__DATABASE__DRIVER=mysql`

Even when mounting a complete, valid `tracker.toml` configuration file with the correct driver setting, the container entrypoint will **overwrite** the mounted config file if the environment variable is not set.

## Root Cause

The tracker container's entrypoint script ([`entry_script_sh`](https://github.com/torrust/torrust-tracker/blob/develop/share/container/entry_script_sh)) **requires** the `TORRUST_TRACKER_CONFIG_OVERRIDE_CORE__DATABASE__DRIVER` environment variable to be set, and uses it to select a default configuration template:

```bash
# Entrypoint exits with error if variable not set
if [ -n "$TORRUST_TRACKER_CONFIG_OVERRIDE_CORE__DATABASE__DRIVER" ]; then
    if cmp_lc "$TORRUST_TRACKER_CONFIG_OVERRIDE_CORE__DATABASE__DRIVER" "sqlite3"; then
        default_config="/usr/share/torrust/default/config/tracker.container.sqlite3.toml"
    elif cmp_lc "$TORRUST_TRACKER_CONFIG_OVERRIDE_CORE__DATABASE__DRIVER" "mysql"; then
        default_config="/usr/share/torrust/default/config/tracker.container.mysql.toml"
    else
        echo "Error: Unsupported Database Type"
        exit 1
    fi
else
    echo "Error: \$TORRUST_TRACKER_CONFIG_OVERRIDE_CORE__DATABASE__DRIVER was not set!"
    exit 1
fi

# Then installs the selected default config
inst "$default_config" "$install_config"  # Copies to /etc/torrust/tracker/tracker.toml
```

This behavior occurs **before** the tracker application starts and loads the configuration, meaning:

- Container starts
- Entrypoint script runs
- **Checks for `TORRUST_TRACKER_CONFIG_OVERRIDE_CORE__DATABASE__DRIVER`**
- **If not set → exits with error (container fails to start)**
- If set → copies appropriate default template to `/etc/torrust/tracker/tracker.toml`
- **Overwrites any mounted configuration file at that path**
- Tracker application loads the (now overwritten) config file

## Impact

When the environment variable is missing:

1. **Container fails to start** with error message: `Error: $TORRUST_TRACKER_CONFIG_OVERRIDE_CORE__DATABASE__DRIVER was not set!`

When the environment variable is set but doesn't match the mounted config:

1. The entrypoint overwrites the mounted configuration with the default template for the specified driver
2. If driver value mismatches user's intent, tracker may fail to start or exhibit unexpected behavior

**Previous behavior** (legacy containers): Would default to `sqlite3` and overwrite mounted MySQL configs, causing:

- Configuration with driver/path mismatch: `driver: sqlite3` + `path: mysql://...`
- SQLite driver attempting to open MySQL connection string
- Container panic and crash loop:

  ```text
  thread 'main' panicked at 'unable to open database file: mysql://tracker_user:tracker_password@mysql:3306/torrust_tracker'
  ```

## Current Workaround

### Docker Compose

Set the database driver environment variable in `docker-compose.yml`:

```yaml
services:
  tracker:
    environment:
      - TORRUST_TRACKER_CONFIG_OVERRIDE_CORE__DATABASE__DRIVER=${DATABASE_DRIVER}
```

And define it in `.env`:

```dotenv
# Database driver type - tells the container entrypoint which config template to use
# Must match the driver specified in tracker.toml
# Uses standardized TORRUST_TRACKER_CONFIG_OVERRIDE_* naming convention
TORRUST_TRACKER_CONFIG_OVERRIDE_CORE__DATABASE__DRIVER='mysql'
```

**Note**: The standardized variable name `TORRUST_TRACKER_CONFIG_OVERRIDE_CORE__DATABASE__DRIVER` is used by the current `develop` branch. Legacy container versions may have used `DATABASE_DRIVER`.

### Direct Docker

```bash
docker run -e TORRUST_TRACKER_CONFIG_OVERRIDE_CORE__DATABASE__DRIVER=mysql torrust/tracker:develop
```

## Environment Variable Naming

**Resolution**: The current `torrust/tracker:develop` image uses the **standardized** naming convention:

- **Current entrypoint** ([`develop` branch]https://github.com/torrust/torrust-tracker/blob/develop/share/container/entry_script_sh): `TORRUST_TRACKER_CONFIG_OVERRIDE_CORE__DATABASE__DRIVER`
- **Live demo** ([`torrust-demo`]https://github.com/torrust/torrust-demo/blob/main/compose.yaml): `TORRUST_TRACKER_CONFIG_OVERRIDE_CORE__DATABASE__DRIVER`
- **Our templates**: Now updated to use `TORRUST_TRACKER_CONFIG_OVERRIDE_CORE__DATABASE__DRIVER`

The entrypoint script checks for this variable and **requires** it to be set, otherwise it exits with an error:

```bash
if [ -n "$TORRUST_TRACKER_CONFIG_OVERRIDE_CORE__DATABASE__DRIVER" ]; then
    # Select appropriate config template
    if cmp_lc "$TORRUST_TRACKER_CONFIG_OVERRIDE_CORE__DATABASE__DRIVER" "sqlite3"; then
        default_config="/usr/share/torrust/default/config/tracker.container.sqlite3.toml"
    elif cmp_lc "$TORRUST_TRACKER_CONFIG_OVERRIDE_CORE__DATABASE__DRIVER" "mysql"; then
        default_config="/usr/share/torrust/default/config/tracker.container.mysql.toml"
    else
        echo "Error: Unsupported Database Type"
        exit 1
    fi
else
    echo "Error: \$TORRUST_TRACKER_CONFIG_OVERRIDE_CORE__DATABASE__DRIVER was not set!"
    exit 1
fi
```

**Note**: Legacy container versions may have used `DATABASE_DRIVER`, but this is no longer supported in current images.

## Expected vs Actual Behavior

### Expected Behavior

When mounting a complete configuration file:

```bash
docker run \
  -v ./tracker.toml:/etc/torrust/tracker/tracker.toml:ro \
  torrust/tracker:develop
```

The tracker should:

- Load the mounted configuration file as-is
- Respect all settings from the file
- Not require environment variables for settings already in the config

### Actual Behavior

The entrypoint script requires environment variables **even when config file is complete**:

```bash
# Without TORRUST_TRACKER_CONFIG_OVERRIDE_CORE__DATABASE__DRIVER env var:
# → Entrypoint exits with error: "$TORRUST_TRACKER_CONFIG_OVERRIDE_CORE__DATABASE__DRIVER was not set!"
# → Container fails to start

# With TORRUST_TRACKER_CONFIG_OVERRIDE_CORE__DATABASE__DRIVER env var:
docker run \
  -e TORRUST_TRACKER_CONFIG_OVERRIDE_CORE__DATABASE__DRIVER=mysql \
  -v ./tracker.toml:/etc/torrust/tracker/tracker.toml:ro \
  torrust/tracker:develop
# → Entrypoint selects MySQL default template
# → Overwrites mounted config with default MySQL template
# → Tracker starts with default MySQL configuration (not the mounted one!)
```

**Note**: The mounted configuration is **always overwritten**, regardless of whether the environment variable is set. The variable only controls which default template is used.

## Design Concern

This behavior creates a tight coupling between:

1. The entrypoint script's template selection logic
2. The application's configuration loading
3. The user's environment variable management

It requires users to specify the driver in **two places** that must remain synchronized, which violates the DRY (Don't Repeat Yourself) principle and creates potential for configuration drift.

## Recommended Solution

The tracker entrypoint script should be modified to:

1. **Check if config file already exists** before template copying
2. **Only copy default template if no config mounted**
3. **Trust mounted configurations** when provided
4. **Remove requirement** for environment variable when complete config is available

Example improved logic:

```bash
# Only generate config if one doesn't exist
if [ ! -f /etc/torrust/tracker/tracker.toml ]; then
    driver=${DATABASE_DRIVER:-sqlite3}
    cp /usr/share/torrust/default/config/tracker.container.${driver}.toml /etc/torrust/tracker/tracker.toml
fi
```

## References

- **Tracker Entrypoint**: <https://github.com/torrust/torrust-tracker/blob/develop/share/container/entry_script_sh>
- **Demo Compose**: <https://github.com/torrust/torrust-demo/blob/main/compose.yaml>
- **Configuration Override Pattern**: Uses `TORRUST_TRACKER_CONFIG_OVERRIDE_*` prefix for environment variable overrides
- **Related**: Environment variable naming decision - [`docs/decisions/environment-variable-prefix.md`]../../decisions/environment-variable-prefix.md

## Action Items

- [ ] Open issue in `torrust/torrust-tracker` repository documenting this requirement
- [ ] Propose entrypoint script improvement to respect mounted configs
- [ ] Investigate which Docker image version we're using and why variable name differs
- [ ] Update tracker documentation to clarify environment variable requirements
- [ ] Consider adding health check that detects driver/path mismatches

## Related Documentation

- **Our Environment Variable Injection**: [`docs/decisions/environment-variable-injection-in-docker-compose.md`]../../decisions/environment-variable-injection-in-docker-compose.md
- **Template System**: [`docs/contributing/templates/template-system-architecture.md`]../../contributing/templates/template-system-architecture.md
- **Output Handling**: [`docs/contributing/output-handling.md`]../../contributing/output-handling.md