Skip to content
This repository was archived by the owner on Oct 10, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 27 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,31 +56,31 @@ This project implements a complete [twelve-factor app](https://12factor.net/) ar
clear separation between infrastructure provisioning and application deployment:

```text
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Configuration Management β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Configuration Management β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β€’ Environment Templates (local.env.tpl, production.env.tpl) β”‚
β”‚ β€’ Configuration Processing (configure-env.sh) β”‚
β”‚ β€’ Template Rendering (.tpl β†’ actual configs) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚ β€’ Configuration Processing (configure-env.sh) β”‚
β”‚ β€’ Template Rendering (.tpl β†’ actual configs) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Infrastructure Layer β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β€’ VM Provisioning (provision-infrastructure.sh) β”‚
β”‚ β€’ Environment-specific Setup (templated cloud-init) β”‚
β”‚ β€’ Provider Abstraction (local implemented, cloud planned) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Infrastructure Layer β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β€’ VM Provisioning (provision-infrastructure.sh) β”‚
β”‚ β€’ Environment-specific Setup (templated cloud-init) β”‚
β”‚ β€’ Provider Abstraction (local implemented, cloud planned) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Application Layer β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β€’ Environment-aware Deployment (templated configs) β”‚
β”‚ β€’ Dynamic Service Configuration β”‚
β”‚ β€’ Comprehensive Health Validation β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Application Layer β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β€’ Environment-aware Deployment (templated configs) β”‚
β”‚ β€’ Dynamic Service Configuration β”‚
β”‚ β€’ Comprehensive Health Validation β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```

### Key Features
Expand All @@ -105,6 +105,9 @@ peer connections, and system health.

## πŸš€ Quick Start

**New users start here**: [**Deployment Guide**](docs/guides/cloud-deployment-guide.md) -
Complete guide for deploying Torrust Tracker locally or in the cloud

For detailed setup instructions, see the specific documentation:

- **Infrastructure**: [Infrastructure Quick Start](infrastructure/docs/quick-start.md)
Expand Down Expand Up @@ -153,7 +156,8 @@ make dev-deploy ENVIRONMENT=local # Does all steps 3-4
deployment
- [Production Setup](application/docs/production-setup.md) - Production
deployment with MySQL
- [Deployment Guide](application/docs/deployment.md) - Deployment procedures
- [Application Deployment Procedures](application/docs/deployment.md) - Detailed
application deployment procedures
- [Backup Procedures](application/docs/backups.md) - Data backup and recovery
- [Rollback Guide](application/docs/rollbacks.md) - Application rollbacks
- [Useful Commands](application/docs/useful-commands.md) - Common operations
Expand All @@ -162,6 +166,8 @@ make dev-deploy ENVIRONMENT=local # Does all steps 3-4

### General Documentation

- [Deployment Guide](docs/guides/cloud-deployment-guide.md) - **Main deployment
guide** for local development and planned cloud deployment
- [Documentation Structure](docs/README.md) - Cross-cutting documentation
- [Architecture Decisions](docs/adr/) - Design decisions and rationale
- [ADR-001: Makefile Location](docs/adr/001-makefile-location.md) - Why the
Expand Down
106 changes: 106 additions & 0 deletions application/share/bin/mysql-backup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#!/bin/bash
# MySQL database backup script for Torrust Tracker
# Creates daily MySQL dumps with automatic cleanup and logging

set -euo pipefail

# Configuration
APP_DIR="/home/torrust/github/torrust/torrust-tracker-demo/application"
BACKUP_DIR="/var/lib/torrust/mysql/backups"
DATE=$(date +%Y%m%d_%H%M%S)
LOG_PREFIX="[$(date '+%Y-%m-%d %H:%M:%S')]"

# Change to application directory
cd "$APP_DIR"

# Source environment variables from the deployment location
ENV_FILE="/var/lib/torrust/compose/.env"
if [[ -f "$ENV_FILE" ]]; then
# shellcheck source=/dev/null
source "$ENV_FILE"
else
echo "$LOG_PREFIX ERROR: Environment file not found at $ENV_FILE"
exit 1
fi

# Validate required environment variables
if [[ -z "${MYSQL_ROOT_PASSWORD:-}" ]]; then
echo "$LOG_PREFIX ERROR: MYSQL_ROOT_PASSWORD not set in environment"
exit 1
fi

if [[ -z "${MYSQL_DATABASE:-}" ]]; then
echo "$LOG_PREFIX ERROR: MYSQL_DATABASE not set in environment"
exit 1
fi

# Use BACKUP_RETENTION_DAYS from environment, default to 7 days
RETENTION_DAYS="${BACKUP_RETENTION_DAYS:-7}"

# Validate retention days is numeric
if ! [[ "$RETENTION_DAYS" =~ ^[0-9]+$ ]]; then
echo "$LOG_PREFIX WARNING: BACKUP_RETENTION_DAYS '$RETENTION_DAYS' is not numeric, using default 7 days"
RETENTION_DAYS=7
fi

# Create backup directory if it doesn't exist
mkdir -p "$BACKUP_DIR"

# Create backup filename
BACKUP_FILE="torrust_tracker_backup_${DATE}.sql"
BACKUP_PATH="$BACKUP_DIR/$BACKUP_FILE"

echo "$LOG_PREFIX Starting MySQL backup: $BACKUP_FILE"

# Check if MySQL container is running
if ! docker compose --env-file "$ENV_FILE" ps mysql | grep -q "Up"; then
echo "$LOG_PREFIX ERROR: MySQL container is not running"
exit 1
fi

# Create MySQL dump
echo "$LOG_PREFIX Creating database dump..."
if docker compose --env-file "$ENV_FILE" exec -T mysql mysqldump \
-u root -p"$MYSQL_ROOT_PASSWORD" \
--single-transaction \
--routines \
--triggers \
--add-drop-database \
--databases "$MYSQL_DATABASE" > "$BACKUP_PATH"; then
echo "$LOG_PREFIX Database dump created successfully"
else
echo "$LOG_PREFIX ERROR: Failed to create database dump"
rm -f "$BACKUP_PATH"
exit 1
fi

# Compress the backup
echo "$LOG_PREFIX Compressing backup..."
if gzip "$BACKUP_PATH"; then
COMPRESSED_BACKUP="${BACKUP_PATH}.gz"
echo "$LOG_PREFIX Backup compressed: $(basename "$COMPRESSED_BACKUP")"
echo "$LOG_PREFIX Backup size: $(du -h "$COMPRESSED_BACKUP" | cut -f1)"
else
echo "$LOG_PREFIX ERROR: Failed to compress backup"
rm -f "$BACKUP_PATH"
exit 1
fi

# Clean up old backups
echo "$LOG_PREFIX Cleaning up old backups (retention: $RETENTION_DAYS days)..."
OLD_BACKUPS_COUNT=$(find "$BACKUP_DIR" -name "torrust_tracker_backup_*.sql.gz" -mtime +"$RETENTION_DAYS" | wc -l)

if [[ "$OLD_BACKUPS_COUNT" -gt 0 ]]; then
find "$BACKUP_DIR" -name "torrust_tracker_backup_*.sql.gz" -mtime +"$RETENTION_DAYS" -delete
echo "$LOG_PREFIX Removed $OLD_BACKUPS_COUNT old backup(s)"
else
echo "$LOG_PREFIX No old backups to remove"
fi

# Show current backup status
CURRENT_BACKUPS_COUNT=$(find "$BACKUP_DIR" -name "torrust_tracker_backup_*.sql.gz" | wc -l)
TOTAL_BACKUP_SIZE=$(du -sh "$BACKUP_DIR" 2>/dev/null | cut -f1 || echo "unknown")

echo "$LOG_PREFIX Backup completed successfully"
echo "$LOG_PREFIX Current backups: $CURRENT_BACKUPS_COUNT files, total size: $TOTAL_BACKUP_SIZE"
echo "$LOG_PREFIX Backup location: $COMPRESSED_BACKUP"
8 changes: 6 additions & 2 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,12 @@ that span multiple components.

- [Integration Testing Guide](guides/integration-testing-guide.md) - Step-by-step
guide for running integration tests following twelve-factor methodology
- [Quick Start Guide](guides/quick-start.md) - Fast setup guide for getting
started quickly
- [Infrastructure Quick Start Guide](../infrastructure/docs/quick-start.md) - Fast
setup guide for getting started quickly with local development
- [Cloud Deployment Guide](guides/cloud-deployment-guide.md) - Complete deployment
guide for local development and planned cloud deployment
- [Grafana Setup Guide](guides/grafana-setup-guide.md) - Manual setup and
configuration of Grafana monitoring dashboards
- [Smoke Testing Guide](guides/smoke-testing-guide.md) - End-to-end testing
using official Torrust client tools

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ selective use of environment variables:
- External IP addresses
- Domain names
- Infrastructure-specific settings
- **Deployment automation configuration** (SSL automation, backup settings)

## Rationale

Expand Down Expand Up @@ -116,6 +117,19 @@ USER_ID=1000
MYSQL_DATABASE=torrust_tracker
```

#### 4. Deployment Automation Configuration

```bash
# SSL certificate automation
DOMAIN_NAME=tracker.example.com
[email protected]
ENABLE_SSL=true

# Database backup automation
ENABLE_DB_BACKUPS=true
BACKUP_RETENTION_DAYS=7
```

## Implementation Examples

### **File-based Configuration** (`tracker.toml`)
Expand Down Expand Up @@ -183,6 +197,13 @@ MYSQL_USER=torrust
# Grafana admin
GF_SECURITY_ADMIN_USER=admin
GF_SECURITY_ADMIN_PASSWORD=admin_password

# Deployment automation
DOMAIN_NAME=tracker.example.com
[email protected]
ENABLE_SSL=true
ENABLE_DB_BACKUPS=true
BACKUP_RETENTION_DAYS=7
```

## Benefits
Expand Down Expand Up @@ -249,6 +270,34 @@ This is an acceptable exception because:
- The token is only for internal monitoring within the Docker network
- The configuration is regenerated when environment changes

### **Deployment Automation Configuration**

Deployment automation settings that control the infrastructure provisioning and application
deployment process are stored as environment variables, even though they are not secrets:

```bash
# SSL certificate automation
DOMAIN_NAME=tracker.example.com
[email protected]
ENABLE_SSL=true

# Database backup automation
ENABLE_DB_BACKUPS=true
BACKUP_RETENTION_DAYS=7
```

This is an acceptable exception because:

- These variables control **deployment scripts and automation**, not service configuration
- They don't belong to any specific service in the Docker Compose stack
- They are used by infrastructure scripts (`deploy-app.sh`, SSL generation, backup automation)
- They are environment-specific values that vary between local/production deployments
- They follow 12-factor principles for deployment automation configuration

**Rationale**: These variables configure the deployment process itself rather than any
individual service, making environment variables the appropriate choice as they're consumed
by shell scripts and automation tools rather than application config files.

## Consequences

### **Configuration Management Process**
Expand Down
Loading