Skip to content

Add Docker deployment: docker/ directory, Dockerfiles, init scripts and .env-driven configuration#643

Open
tomasecastro wants to merge 6 commits intolirantal:masterfrom
tomasecastro:docker-composer
Open

Add Docker deployment: docker/ directory, Dockerfiles, init scripts and .env-driven configuration#643
tomasecastro wants to merge 6 commits intolirantal:masterfrom
tomasecastro:docker-composer

Conversation

@tomasecastro
Copy link
Copy Markdown

@tomasecastro tomasecastro commented Dec 26, 2025

User description

Summary

  • Add a docker/ directory with Dockerfiles and adjusted init scripts to run daloRADIUS + FreeRADIUS + MariaDB in Docker.
  • Add docker-compose.yml to orchestrate services (radius-mysql, radius, radius-web).
  • Make all DB credentials, RADIUS client secret, timezone and related settings configurable through .env.
  • Fix permissions and log directory handling so FreeRADIUS can write radacct/log files inside the container.
  • Provide migration/import guidance for NAS rows from an existing FreeRADIUS DB.

What changed

  • Added: docker/ (contains Dockerfiles for freeradius and daloradius, init scripts for DB and server)
  • Added: docker-compose.yml
  • Added: example .env (used by compose and init scripts)
  • Modified: daloRADIUS Dockerfile to work within the docker/ layout and honor .env values
  • Adjusted init scripts to read environment variables (MYSQL_*, DEFAULT_CLIENT_SECRET, TZ, etc.) and to create required dirs with correct ownership (freerad:freerad)

Configuration (important)

  • All secrets and environment values are driven by .env:
    • MYSQL_HOST, MYSQL_PORT, MYSQL_DATABASE, MYSQL_USER, MYSQL_PASSWORD, MYSQL_ROOT_PASSWORD
    • DEFAULT_CLIENT_SECRET, DEFAULT_FREERADIUS_SERVER, TZ
    • MAIL_SMTPADDR, MAIL_PORT, MAIL_FROM, MAIL_AUTH
  • Defaults in .env are placeholders; replace before production.

Migration notes

  • To migrate NAS rows from an existing RADIUS DB:
    1. Dump only the nas table from source: mysqldump --no-create-info --skip-lock-tables ... nas > nas_data.sql
    2. Convert INSERTs to REPLACE (avoid PK conflicts): sed -E 's/INSERT INTO nas/REPLACE INTO nas/g' nas_data.sql > nas_replace.sql
    3. Import to target: docker exec -i radius-mysql mysql -u${MYSQL_USER} -p"${MYSQL_PASSWORD}" ${MYSQL_DATABASE} < nas_replace.sql
    4. Ensure each nas.secret matches the shared secret configured on your NAS devices.
    5. Restart FreeRADIUS: docker-compose restart radius

How to test

  1. Copy a .env into the project root with proper values.
  2. docker-compose build
  3. docker-compose up -d
  4. Verify FreeRADIUS reads clients from SQL (read_clients = yes in mods-available/sql) and that nas.secret values match routers.
  5. Monitor logs: docker logs -f radius | grep -E "Ignoring request|unknown client|radacct|Permission denied"
  6. For debug, stop background freeradius and run freeradius -X inside the container.

Security & notes

  • Do not store production secrets in public repos.
  • Default example secrets are placeholders; replace them.
  • On Windows hosts prefer named Docker volumes for /var/log/freeradius to avoid host-bind permission issues.

Files of interest

  • docker/ (new)
    • docker/freeradius/Dockerfile (Freeradius build and init)
    • docker/daloradius/Dockerfile (web UI build)
    • docker/init-db-*.sh (DB/init helpers adjusted to Docker paths)
    • docker/init-freeradius.sh (creates DB schema, enables sql module, sets read_clients=yes)
  • docker-compose.yml (new)
  • .env (new/example)

Request

  • Please review Dockerfiles and init scripts for security and style.
  • Merge if acceptable; I can follow-up with tests or adjust variable names if you prefer different defaults.

PR Type

Enhancement


Description

  • Add Docker Compose orchestration with MariaDB, FreeRADIUS, and daloRADIUS services

  • Implement environment-driven configuration through .env file for all credentials and settings

  • Create initialization scripts for FreeRADIUS and daloRADIUS database and service setup

  • Configure FreeRADIUS SQL module with MySQL backend and client authentication from database

  • Update docker-compose.yml to use environment variables and fix volume mount paths


Diagram Walkthrough

flowchart LR
  ENV[".env file<br/>credentials & config"]
  COMPOSE["docker-compose.yml<br/>service orchestration"]
  MYSQL["MariaDB<br/>radius-mysql"]
  RADIUS["FreeRADIUS<br/>radius service"]
  DALO["daloRADIUS<br/>radius-web service"]
  
  ENV -->|environment vars| COMPOSE
  COMPOSE -->|defines services| MYSQL
  COMPOSE -->|defines services| RADIUS
  COMPOSE -->|defines services| DALO
  RADIUS -->|init-freeradius.sh| MYSQL
  DALO -->|init.sh| MYSQL
  RADIUS -->|reads clients| MYSQL
  DALO -->|web UI| RADIUS
Loading

File Walkthrough

Relevant files
Enhancement
init.sh
daloRADIUS initialization and database setup script           

docker/daloradius/init.sh

  • Initialize daloRADIUS configuration by copying sample config and
    substituting environment variables
  • Create MySQL database and user with proper permissions for Docker
    networking (host '%')
  • Import daloRADIUS database schema from mariadb-daloradius.sql
  • Use lock files to prevent re-initialization on container restart
  • Start Apache2 in foreground mode with proper signal handling
+90/-0   
init-freeradius.sh
FreeRADIUS SQL module configuration and initialization     

docker/freeradius/init-freeradius.sh

  • Configure FreeRADIUS SQL module to use MySQL driver with
    environment-based credentials
  • Enable read_clients from database and configure tunnel reply for UniFi
    support
  • Set up authentication logging with detailed message formatting
  • Create initial NAS client entry for Docker subnet with configurable
    secret
  • Implement graceful signal handling for foreground FreeRADIUS process
    with log tailing
+126/-0 
Dockerfile
Update daloRADIUS log file location                                           

Dockerfile

  • Update daloRADIUS log file path from /tmp to /var/log/freeradius for
    persistence
  • Ensure proper ownership of log directory for www-data user
+1/-1     
docker-compose.yml
Refactor docker-compose to use environment variables         

docker-compose.yml

  • Replace hardcoded values with environment variable substitution for
    all services
  • Update Dockerfile paths to reference docker/ subdirectory structure
  • Change volume mounts from named volumes to bind mounts for logs and
    data
  • Add port exposure for MariaDB (3306) and timezone environment variable
  • Add optional timezone file mounts for Linux hosts
  • Update service names and container naming for consistency
+36/-28 
Dockerfile
daloRADIUS Docker image with Apache2 and PHP                         

docker/daloradius/Dockerfile

  • Create Debian 13-based daloRADIUS image with Apache2 and PHP
    dependencies
  • Install required packages including freeradius-utils, PHP modules, and
    MariaDB client
  • Configure Apache2 with dual ports (80 and 8000) for users and
    operators interfaces
  • Add initialization script from docker directory with CRLF
    normalization
  • Set up log directories with proper ownership for www-data user
+85/-0   
Dockerfile-freeradius
FreeRADIUS Docker image with MySQL support                             

docker/freeradius/Dockerfile-freeradius

  • Create FreeRADIUS image based on official freeradius-server image
  • Install required utilities including ipcalc, mariadb-client, and
    timezone data
  • Add initialization script with CRLF normalization and executable
    permissions
  • Expose RADIUS ports 1812 and 1813 for authentication and accounting
  • Configure entrypoint to run initialization script in foreground mode
+53/-0   
Configuration changes
.env
Environment configuration file with service credentials   

.env

  • Define all database credentials (host, port, user, password, root
    password)
  • Configure FreeRADIUS client secret and server connection parameters
  • Set mail SMTP configuration for daloRADIUS notifications
  • Provide timezone setting for all services
  • Include sensible defaults that must be changed for production
+19/-0   

…nd .env-driven configuration

Summary
- Add a docker/ directory with Dockerfiles and adjusted init scripts to run daloRADIUS + FreeRADIUS + MariaDB in Docker.
- Add docker-compose.yml to orchestrate services (radius-mysql, radius, radius-web).
- Make all DB credentials, RADIUS client secret, timezone and related settings configurable through .env.
- Fix permissions and log directory handling so FreeRADIUS can write radacct/log files inside the container.
- Provide migration/import guidance for NAS rows from an existing FreeRADIUS DB.

What changed
- Added: docker/ (contains Dockerfiles for freeradius and daloradius, init scripts for DB and server)
- Added: docker-compose.yml
- Added: example .env (used by compose and init scripts)
- Modified: daloRADIUS Dockerfile to work within the docker/ layout and honor .env values
- Adjusted init scripts to read environment variables (MYSQL_*, DEFAULT_CLIENT_SECRET, TZ, etc.) and to create required dirs with correct ownership (freerad:freerad)

Configuration (important)
- All secrets and environment values are driven by .env:
  - MYSQL_HOST, MYSQL_PORT, MYSQL_DATABASE, MYSQL_USER, MYSQL_PASSWORD, MYSQL_ROOT_PASSWORD
  - DEFAULT_CLIENT_SECRET, DEFAULT_FREERADIUS_SERVER, TZ
  - MAIL_SMTPADDR, MAIL_PORT, MAIL_FROM, MAIL_AUTH
- Defaults in .env are placeholders; replace before production.

Migration notes
- To migrate NAS rows from an existing RADIUS DB:
  1. Dump only the nas table from source: mysqldump --no-create-info --skip-lock-tables ... nas > nas_data.sql
  2. Convert INSERTs to REPLACE (avoid PK conflicts): sed -E 's/INSERT INTO `nas`/REPLACE INTO `nas`/g' nas_data.sql > nas_replace.sql
  3. Import to target: docker exec -i radius-mysql mysql -u${MYSQL_USER} -p"${MYSQL_PASSWORD}" ${MYSQL_DATABASE} < nas_replace.sql
  4. Ensure each nas.secret matches the shared secret configured on your NAS devices.
  5. Restart FreeRADIUS: docker-compose restart radius

How to test
1. Copy a .env into the project root with proper values.
2. docker-compose build
3. docker-compose up -d
4. Verify FreeRADIUS reads clients from SQL (read_clients = yes in mods-available/sql) and that nas.secret values match routers.
5. Monitor logs: docker logs -f radius | grep -E "Ignoring request|unknown client|radacct|Permission denied"
6. For debug, stop background freeradius and run freeradius -X inside the container.

Security & notes
- Do not store production secrets in public repos.
- Default example secrets are placeholders; replace them.
- On Windows hosts prefer named Docker volumes for /var/log/freeradius to avoid host-bind permission issues.

Files of interest
- docker/ (new)
  - docker/freeradius/Dockerfile (Freeradius build and init)
  - docker/daloradius/Dockerfile (web UI build)
  - docker/init-db-*.sh (DB/init helpers adjusted to Docker paths)
  - docker/init-freeradius.sh (creates DB schema, enables sql module, sets read_clients=yes)
- docker-compose.yml (new)
- .env (new/example)

Request
- Please review Dockerfiles and init scripts for security and style.
- Merge if acceptable; I can follow-up with tests or adjust variable names if you prefer different defaults.
Copilot AI review requested due to automatic review settings December 26, 2025 13:03
@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented Dec 26, 2025

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
🔴
Hardcoded secrets in repo

Description: A plaintext .env containing database credentials and shared secrets (e.g., MYSQL_PASSWORD,
MYSQL_ROOT_PASSWORD, DEFAULT_CLIENT_SECRET) is added to the repo, which can lead to
credential leakage if committed/published or copied into other environments.
.env [1-19]

Referred Code
# docker environment overrides
# Timezone (set to your preferred TZ)
TZ=Europe/Madrid

# MariaDB settings (change as needed)
MYSQL_HOST=radius-mysql
MYSQL_PORT=3306
MYSQL_DATABASE=radius
MYSQL_USER=radius
MYSQL_PASSWORD=radiusdbpw
MYSQL_ROOT_PASSWORD=radiusrootdbpw

# daloRADIUS optional settings
DEFAULT_CLIENT_SECRET=testing123
DEFAULT_FREERADIUS_SERVER=radius
MAIL_SMTPADDR=127.0.0.1
MAIL_PORT=25
MAIL_FROM=root@daloradius.xdsl.by
MAIL_AUTH=
Exposed database port

Description: MariaDB is published on the host via ports: '3306:3306', expanding the attack surface
beyond the Docker network and enabling brute-force/remote access if host firewalling is
not strict.
docker-compose.yml [7-9]

Referred Code
ports:
  - '3306:3306'
environment:
DB TLS disabled

Description: The script explicitly disables SQL/TLS verification for the FreeRADIUS SQL module
(tls_required = no and comments out CA/cert/key settings), which can allow credential
interception or MITM if the DB connection is ever routed over an untrusted network.
init-freeradius.sh [12-17]

Referred Code
	sed -i 's|ca_file = "/etc/ssl/certs/my_ca.crt"|#ca_file = "/etc/ssl/certs/my_ca.crt"|' $RADIUS_PATH/mods-available/sql #disable sql encryption
        sed -i 's|ca_path = "/etc/ssl/certs/"|#ca_path = "/etc/ssl/certs/"|' $RADIUS_PATH/mods-available/sql #disable sql encryption
	sed -i 's|certificate_file = "/etc/ssl/certs/private/client.crt"|#certificate_file = "/etc/ssl/certs/private/client.crt"|' $RADIUS_PATH/mods-available/sql #disable sql encryption
	sed -i 's|private_key_file = "/etc/ssl/certs/private/client.key"|#private_key_file = "/etc/ssl/certs/private/client.key"|' $RADIUS_PATH/mods-available/sql #disable sql encryption
	sed -i 's|tls_required = yes|tls_required = no|' $RADIUS_PATH/mods-available/sql #disable sql encryption
	sed -i 's|#\s*read_clients = yes|read_clients = yes|' $RADIUS_PATH/mods-available/sql
MySQL SSL bypass

Description: The script forces non-TLS MySQL client connections using --skip-ssl for root and
application DB operations, which risks leaking database credentials/data in transit if the
DB is not strictly local to the Docker network.
init.sh [47-55]

Referred Code
mysql -h "$MYSQL_HOST" --skip-ssl -u root -p"$MYSQL_ROOT_PASSWORD" -e "CREATE DATABASE IF NOT EXISTS \`$MYSQL_DATABASE\`;"

# Create user for any host '%' and grant privileges (docker uses network connections, not localhost)
mysql -h "$MYSQL_HOST" --skip-ssl -u root -p"$MYSQL_ROOT_PASSWORD" -e "CREATE USER IF NOT EXISTS '$MYSQL_USER'@'%' IDENTIFIED BY '$MYSQL_PASSWORD';"
mysql -h "$MYSQL_HOST" --skip-ssl -u root -p"$MYSQL_ROOT_PASSWORD" -e "GRANT ALL PRIVILEGES ON \`$MYSQL_DATABASE\`.* TO '$MYSQL_USER'@'%'; FLUSH PRIVILEGES;"

# Import schema using client option to disable SSL if server does not have it
mysql --skip-ssl -h "$MYSQL_HOST" -u "$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DATABASE" < $DALORADIUS_PATH/contrib/db/mariadb-daloradius.sql
echo "Database initialization for daloRADIUS completed."
World-readable auth logs

Description: chmod -R a+rX /var/log/freeradius makes FreeRADIUS logs world-readable, which may expose
sensitive authentication metadata (usernames, NAS identifiers, network details) to any
process/user inside the container or via mounted volumes.
init-freeradius.sh [101-103]

Referred Code
# make logs directory world readable
chmod -R a+rX /var/log/freeradius
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🔴
Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status:
Abbreviated variables: Several new variables use non-descriptive abbreviations (e.g., IP, NM, CIDR, SECRET)
reducing readability and self-documentation.

Referred Code
IP=`ifconfig eth0 | awk '/inet/{ print $2;} '` # does also work: $IP=`hostname -I | awk '{print $1}'`
NM=`ifconfig eth0 | awk '/netmask/{ print $4;} '`
CIDR=`ipcalc $IP $NM | awk '/Network/{ print $2;} '`
SECRET=testing123
if [ -n "$DEFAULT_CLIENT_SECRET" ]; then
	SECRET=$DEFAULT_CLIENT_SECRET
fi

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Missing error handling: Initialization performs multiple failure-prone operations (e.g., mysql DDL/DCL and schema
import) without set -euo pipefail, return-code checks, or actionable error messages,
risking silent partial initialization.

Referred Code
function init_database {
    # Create database if not exists
    mysql -h "$MYSQL_HOST" --skip-ssl -u root -p"$MYSQL_ROOT_PASSWORD" -e "CREATE DATABASE IF NOT EXISTS \`$MYSQL_DATABASE\`;"

    # Create user for any host '%' and grant privileges (docker uses network connections, not localhost)
    mysql -h "$MYSQL_HOST" --skip-ssl -u root -p"$MYSQL_ROOT_PASSWORD" -e "CREATE USER IF NOT EXISTS '$MYSQL_USER'@'%' IDENTIFIED BY '$MYSQL_PASSWORD';"
    mysql -h "$MYSQL_HOST" --skip-ssl -u root -p"$MYSQL_ROOT_PASSWORD" -e "GRANT ALL PRIVILEGES ON \`$MYSQL_DATABASE\`.* TO '$MYSQL_USER'@'%'; FLUSH PRIVILEGES;"

    # Import schema using client option to disable SSL if server does not have it
    mysql --skip-ssl -h "$MYSQL_HOST" -u "$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DATABASE" < $DALORADIUS_PATH/contrib/db/mariadb-daloradius.sql
    echo "Database initialization for daloRADIUS completed."
}

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status:
Secret logged in plaintext: The init script logs the RADIUS shared secret to stdout (echo ... default secret $SECRET),
exposing a sensitive credential in logs.

Referred Code
SECRET=testing123
if [ -n "$DEFAULT_CLIENT_SECRET" ]; then
	SECRET=$DEFAULT_CLIENT_SECRET
fi
echo "Adding client for $CIDR with default secret $SECRET"
mysql -h "$MYSQL_HOST" -u "$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DATABASE" -e "INSERT INTO nas (nasname,shortname,type,ports,secret,server,community,description) VALUES ('$CIDR','docker NET','other',0,'$SECRET',NULL,'','')"

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status:
SQL injection via env: Environment variables (e.g., MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE) are interpolated
directly into mysql -e statements without sanitization/escaping, enabling SQL injection or
broken initialization if values contain quotes/metacharacters.

Referred Code
mysql -h "$MYSQL_HOST" --skip-ssl -u root -p"$MYSQL_ROOT_PASSWORD" -e "CREATE DATABASE IF NOT EXISTS \`$MYSQL_DATABASE\`;"

# Create user for any host '%' and grant privileges (docker uses network connections, not localhost)
mysql -h "$MYSQL_HOST" --skip-ssl -u root -p"$MYSQL_ROOT_PASSWORD" -e "CREATE USER IF NOT EXISTS '$MYSQL_USER'@'%' IDENTIFIED BY '$MYSQL_PASSWORD';"
mysql -h "$MYSQL_HOST" --skip-ssl -u root -p"$MYSQL_ROOT_PASSWORD" -e "GRANT ALL PRIVILEGES ON \`$MYSQL_DATABASE\`.* TO '$MYSQL_USER'@'%'; FLUSH PRIVILEGES;"

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status:
Insufficient audit context: Critical actions like DB/user creation and schema import are only logged via unstructured
echo without actor/context/outcome fields needed to reliably reconstruct events.

Referred Code
function init_database {
    # Create database if not exists
    mysql -h "$MYSQL_HOST" --skip-ssl -u root -p"$MYSQL_ROOT_PASSWORD" -e "CREATE DATABASE IF NOT EXISTS \`$MYSQL_DATABASE\`;"

    # Create user for any host '%' and grant privileges (docker uses network connections, not localhost)
    mysql -h "$MYSQL_HOST" --skip-ssl -u root -p"$MYSQL_ROOT_PASSWORD" -e "CREATE USER IF NOT EXISTS '$MYSQL_USER'@'%' IDENTIFIED BY '$MYSQL_PASSWORD';"
    mysql -h "$MYSQL_HOST" --skip-ssl -u root -p"$MYSQL_ROOT_PASSWORD" -e "GRANT ALL PRIVILEGES ON \`$MYSQL_DATABASE\`.* TO '$MYSQL_USER'@'%'; FLUSH PRIVILEGES;"

    # Import schema using client option to disable SSL if server does not have it
    mysql --skip-ssl -h "$MYSQL_HOST" -u "$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DATABASE" < $DALORADIUS_PATH/contrib/db/mariadb-daloradius.sql
    echo "Database initialization for daloRADIUS completed."
}

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status:
Errors may expose details: Direct invocation of mysql/mysqladmin without controlled error handling may print detailed
DB connection/query failures (potentially including host/user/db context) to container
stdout.

Referred Code
# wait for MySQL-Server to be ready
while ! mysqladmin ping -h"$MYSQL_HOST" --silent; do
	echo "Waiting for mysql ($MYSQL_HOST)..."
	sleep 20
done

Learn more about managing compliance generic rules or creating your own custom rules

  • Update
Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented Dec 26, 2025

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
High-level
Fix database initialization race condition

Consolidate the database initialization logic into a single service's script.
Both freeradius and daloradius services currently race to create the same lock
file, which results in only one service's schema being imported.

Examples:

docker/daloradius/init.sh [81-87]
DB_LOCK=/data/.db_init_done
if test -f "$DB_LOCK"; then
    echo "Database lock file exists, skipping initial setup of mysql database."
else
    init_database
    date > $DB_LOCK
fi
docker/freeradius/init-freeradius.sh [93-99]
DB_LOCK=/data/.db_init_done
if test -f "$DB_LOCK"; then
	echo "Database lock file exists, skipping initial setup of mysql database."
else
	init_database
	date > $DB_LOCK
fi

Solution Walkthrough:

Before:

# docker/daloradius/init.sh
DB_LOCK=/data/.db_init_done
if ! test -f "$DB_LOCK"; then
    init_database # Imports daloradius schema
    date > $DB_LOCK
fi

# docker/freeradius/init-freeradius.sh
DB_LOCK=/data/.db_init_done
if ! test -f "$DB_LOCK"; then
    init_database # Imports freeradius schema
    date > $DB_LOCK
fi

After:

# docker/daloradius/init.sh
DB_LOCK=/data/.db_init_done
if ! test -f "$DB_LOCK"; then
    # Imports both daloradius and freeradius schemas
    init_database_complete 
    date > $DB_LOCK
fi

# docker/freeradius/init-freeradius.sh
# (Database initialization logic is removed)
# Wait for DB to be ready before starting service.
while ! mysqladmin ping ...; do
  sleep 5
done
Suggestion importance[1-10]: 9

__

Why: This suggestion identifies a critical race condition where both services try to initialize the database using the same lock file, which would lead to an incomplete and broken database setup.

High
Consolidate duplicated Dockerfiles for clarity
Suggestion Impact:The commit changed docker-compose so the radius-web service no longer points at docker/daloradius/dockerfile and instead uses the default Dockerfile in the build context (build: .). This relates to the duplication/which Dockerfile is used, but it does not implement the suggested consolidation to docker/daloradius/Dockerfile nor does it remove the root Dockerfile; it effectively shifts usage back to the root Dockerfile.

code diff:

   radius-web:
-    build:
-      context: .
-      dockerfile: docker/daloradius/dockerfile
-    container_name: daloradius
+    build: .
+    container_name: radius-web
     restart: unless-stopped

Consolidate the new docker/daloradius/Dockerfile and the existing root
Dockerfile, which are nearly identical. Remove the redundant root Dockerfile to
improve maintainability.

Examples:

docker-compose.yml [50]
      dockerfile: docker/daloradius/dockerfile
docker/daloradius/Dockerfile [1-85]
# Official daloRADIUS dockerfile
# GitHub: https://github.com/lirantal/daloradius
#
# Build image:
# 1. git pull git@github.com:lirantal/daloradius.git
# 2. docker build . -t lirantal/daloradius
#
# Run the container:
# 1. docker run -p 80:80 -p 8000:8000 -d lirantal/daloradius


 ... (clipped 75 lines)

Solution Walkthrough:

Before:

# File structure
.
├── Dockerfile  # Modified but unused by docker-compose
├── docker-compose.yml
└── docker/
    └── daloradius/
        └── Dockerfile  # New, used by docker-compose

# docker-compose.yml
services:
  radius-web:
    build:
      context: .
      dockerfile: docker/daloradius/dockerfile
    ...

After:

# File structure
.
├── docker-compose.yml
└── docker/
    └── daloradius/
        └── Dockerfile  # Single, consolidated Dockerfile

# docker-compose.yml
services:
  radius-web:
    build:
      context: .
      dockerfile: docker/daloradius/Dockerfile
    ...
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies that the PR introduces a duplicate Dockerfile for the daloradius service, making the root Dockerfile unused by docker-compose and creating a maintenance issue.

Medium
Possible issue
Fix case-sensitive Dockerfile path
Suggestion Impact:The commit changed the `radius` service's `dockerfile` reference away from the lowercased path (`docker/freeradius/dockerfile-freeradius`) to `Dockerfile-freeradius`, addressing the case/path issue that could cause build failures on case-sensitive filesystems. However, the `radius-web` service was changed to `build: .` without an explicit Dockerfile path rather than updating it to `docker/daloradius/Dockerfile` as suggested.

code diff:

   radius:
     container_name: radius
     build:
       context: .
-      dockerfile: docker/freeradius/dockerfile-freeradius
+      dockerfile: Dockerfile-freeradius
     restart: unless-stopped
     depends_on: 
       - radius-mysql
@@ -30,25 +28,22 @@
       - '1812:1812/udp'
       - '1813:1813/udp'
     environment:
-      - MYSQL_HOST=${MYSQL_HOST}
-      - MYSQL_PORT=${MYSQL_PORT}
-      - MYSQL_DATABASE=${MYSQL_DATABASE}
-      - MYSQL_USER=${MYSQL_USER}
-      - MYSQL_PASSWORD=${MYSQL_PASSWORD}
-      - TZ=${TZ}
+      - MYSQL_HOST=radius-mysql
+      - MYSQL_PORT=3306
+      - MYSQL_DATABASE=radius
+      - MYSQL_USER=radius
+      - MYSQL_PASSWORD=radiusdbpw
       # Optional settings
-      - DEFAULT_CLIENT_SECRET=${DEFAULT_CLIENT_SECRET}
+      - DEFAULT_CLIENT_SECRET=testing123
     volumes:
       - ./data/freeradius:/data
-      - ./radius_logs:/var/log/freeradius
+      - radius_logs:/var/log/freeradius
     # Uncomment below to enable debug logging.
     #command: -X
 
   radius-web:
-    build:
-      context: .
-      dockerfile: docker/daloradius/dockerfile
-    container_name: daloradius
+    build: .
+    container_name: radius-web
     restart: unless-stopped

Correct the casing of dockerfile paths in docker-compose.yml to match the actual
filenames (Dockerfile-freeradius and Dockerfile) to prevent build failures on
case-sensitive filesystems.

docker-compose.yml [21-52]

 radius:
   container_name: radius
   build:
     context: .
-    dockerfile: docker/freeradius/dockerfile-freeradius
+    dockerfile: docker/freeradius/Dockerfile-freeradius
   restart: unless-stopped
 ...
 radius-web:
   build:
     context: .
-    dockerfile: docker/daloradius/dockerfile
+    dockerfile: docker/daloradius/Dockerfile
   container_name: daloradius
   restart: unless-stopped

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 9

__

Why: This suggestion correctly identifies a critical case-sensitivity issue in Dockerfile paths that would cause build failures on Linux systems, ensuring cross-platform compatibility.

High
Create log directory before touch

Add a mkdir -p /var/log/freeradius command before touching the log file to
prevent build failures caused by the missing directory.

Dockerfile [71]

-RUN touch /var/log/freeradius/daloradius.log && chown -R www-data:www-data /var/log/freeradius/daloradius.log
+RUN mkdir -p /var/log/freeradius \
+ && touch /var/log/freeradius/daloradius.log \
+ && chown -R www-data:www-data /var/log/freeradius
  • Apply / Chat
Suggestion importance[1-10]: 9

__

Why: This suggestion correctly identifies that the build will fail because the log directory does not exist, and provides a correct fix by creating the directory before the file.

High
General
Fix log file path in config

In init.sh, update the CONFIG_LOG_FILE path from /tmp/daloradius.log to
/var/log/freeradius/daloradius.log to match the new log location.

docker/daloradius/init.sh [40]

-sed -i "s/\$configValues\['CONFIG_LOG_FILE'\] = .*;/\$configValues\['CONFIG_LOG_FILE'\] = '\/tmp\/daloradius.log';/" $DALORADIUS_CONF_PATH
+sed -i "s/\$configValues\['CONFIG_LOG_FILE'\] = .*;/\$configValues\['CONFIG_LOG_FILE'\] = '\/var/log/freeradius\/daloradius.log';/" $DALORADIUS_CONF_PATH
  • Apply / Chat
Suggestion importance[1-10]: 9

__

Why: This suggestion fixes a bug where the application configuration points to an incorrect log file path, which mismatches the path changes made elsewhere in the PR.

High
Security
Avoid exposing database password in process list

To prevent exposing the MySQL root password in the process list, use the
MYSQL_PWD environment variable instead of the -p command-line argument for mysql
commands.

docker/daloradius/init.sh [45-56]

 function init_database {
     # Create database if not exists
-    mysql -h "$MYSQL_HOST" --skip-ssl -u root -p"$MYSQL_ROOT_PASSWORD" -e "CREATE DATABASE IF NOT EXISTS \`$MYSQL_DATABASE\`;"
+    export MYSQL_PWD="$MYSQL_ROOT_PASSWORD"
+    mysql -h "$MYSQL_HOST" --skip-ssl -u root -e "CREATE DATABASE IF NOT EXISTS \`$MYSQL_DATABASE\`;"
 
     # Create user for any host '%' and grant privileges (docker uses network connections, not localhost)
-    mysql -h "$MYSQL_HOST" --skip-ssl -u root -p"$MYSQL_ROOT_PASSWORD" -e "CREATE USER IF NOT EXISTS '$MYSQL_USER'@'%' IDENTIFIED BY '$MYSQL_PASSWORD';"
-    mysql -h "$MYSQL_HOST" --skip-ssl -u root -p"$MYSQL_ROOT_PASSWORD" -e "GRANT ALL PRIVILEGES ON \`$MYSQL_DATABASE\`.* TO '$MYSQL_USER'@'%'; FLUSH PRIVILEGES;"
+    mysql -h "$MYSQL_HOST" --skip-ssl -u root -e "CREATE USER IF NOT EXISTS '$MYSQL_USER'@'%' IDENTIFIED BY '$MYSQL_PASSWORD';"
+    mysql -h "$MYSQL_HOST" --skip-ssl -u root -e "GRANT ALL PRIVILEGES ON \`$MYSQL_DATABASE\`.* TO '$MYSQL_USER'@'%'; FLUSH PRIVILEGES;"
+    unset MYSQL_PWD
 
     # Import schema using client option to disable SSL if server does not have it
-    mysql --skip-ssl -h "$MYSQL_HOST" -u "$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DATABASE" < $DALORADIUS_PATH/contrib/db/mariadb-daloradius.sql
+    export MYSQL_PWD="$MYSQL_PASSWORD"
+    mysql --skip-ssl -h "$MYSQL_HOST" -u "$MYSQL_USER" "$MYSQL_DATABASE" < $DALORADIUS_PATH/contrib/db/mariadb-daloradius.sql
+    unset MYSQL_PWD
     echo "Database initialization for daloRADIUS completed."
 }
  • Apply / Chat
Suggestion importance[1-10]: 8

__

Why: This suggestion correctly identifies a security vulnerability where database passwords are exposed in the process list and provides a standard, secure alternative using the MYSQL_PWD environment variable.

Medium
  • Update

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds comprehensive Docker deployment support for daloRADIUS, enabling containerized deployment of the complete stack (FreeRADIUS, daloRADIUS web UI, and MariaDB) with environment-driven configuration.

Key Changes:

  • Docker orchestration via docker-compose.yml with three services (radius-mysql, radius, radius-web)
  • Environment-based configuration through .env file for all database credentials, RADIUS secrets, and mail settings
  • Automated initialization scripts for database schema creation and FreeRADIUS configuration

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 23 comments.

Show a summary per file
File Description
docker-compose.yml Orchestrates three services with environment variable interpolation from .env; updated to use docker/ subdirectory structure
.env Centralized environment configuration for MySQL credentials, RADIUS secrets, timezone, and mail settings
docker/freeradius/Dockerfile-freeradius FreeRADIUS container build based on official freeradius-server image with required utilities
docker/freeradius/init-freeradius.sh Initialization script that configures FreeRADIUS SQL modules, creates database schema, and manages container startup
docker/daloradius/Dockerfile daloRADIUS web UI container based on Debian 13 with Apache and PHP 8
docker/daloradius/init.sh Initialization script for daloRADIUS configuration and database setup
Dockerfile Updated log file path from /tmp to /var/log/freeradius for consistency with Docker deployment

Critical Issues Found:

  • Dockerfile path case mismatches in docker-compose.yml will cause build failures on Linux
  • .env file with production credentials should not be committed to version control
  • Several shell script issues with sed delimiter handling and exit code capture

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread docker/daloradius/Dockerfile Outdated
Comment thread docker/daloradius/init.sh
Comment thread .env Outdated
Comment on lines +1 to +19
# docker environment overrides
# Timezone (set to your preferred TZ)
TZ=Europe/Madrid

# MariaDB settings (change as needed)
MYSQL_HOST=radius-mysql
MYSQL_PORT=3306
MYSQL_DATABASE=radius
MYSQL_USER=radius
MYSQL_PASSWORD=radiusdbpw
MYSQL_ROOT_PASSWORD=radiusrootdbpw

# daloRADIUS optional settings
DEFAULT_CLIENT_SECRET=testing123
DEFAULT_FREERADIUS_SERVER=radius
MAIL_SMTPADDR=127.0.0.1
MAIL_PORT=25
MAIL_FROM=root@daloradius.xdsl.by
MAIL_AUTH= No newline at end of file
Copy link

Copilot AI Dec 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The .env file contains weak default credentials ('radiusdbpw', 'radiusrootdbpw', 'testing123') and should not be committed to version control with these values. Consider renaming this to '.env.example' and adding '.env' to .gitignore to prevent accidental commits of production credentials.

Copilot uses AI. Check for mistakes.
Comment thread docker/freeradius/init-freeradius.sh Outdated
Comment thread docker-compose.yml Outdated
build:
context: .
dockerfile: Dockerfile-freeradius
dockerfile: docker/freeradius/dockerfile-freeradius
Copy link

Copilot AI Dec 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dockerfile path uses lowercase 'dockerfile-freeradius' but should use consistent casing. Docker is case-sensitive on Linux systems, and this could cause build failures if the actual filename uses different casing.

Suggested change
dockerfile: docker/freeradius/dockerfile-freeradius
dockerfile: docker/freeradius/Dockerfile-freeradius

Copilot uses AI. Check for mistakes.
Comment thread docker-compose.yml
radius-mysql:
image: mariadb:10
container_name: radius-mysql
restart: unless-stopped
Copy link

Copilot AI Dec 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exposing MySQL port 3306 to the host could be a security risk in production environments. Consider removing this port mapping or adding a comment warning that it should be removed in production deployments.

Suggested change
restart: unless-stopped
restart: unless-stopped
# WARNING: Exposes MySQL to the host for local development only.
# Remove this port mapping in production deployments.

Copilot uses AI. Check for mistakes.
Comment thread docker/daloradius/init.sh
Comment on lines +20 to +39
sed -i "s/\$configValues\['CONFIG_DB_HOST'\] = .*;/\$configValues\['CONFIG_DB_HOST'\] = '$MYSQL_HOST';/" $DALORADIUS_CONF_PATH
sed -i "s/\$configValues\['CONFIG_DB_PORT'\] = .*;/\$configValues\['CONFIG_DB_PORT'\] = '$MYSQL_PORT';/" $DALORADIUS_CONF_PATH
sed -i "s/\$configValues\['CONFIG_DB_PASS'\] = .*;/\$configValues\['CONFIG_DB_PASS'\] = '$MYSQL_PASSWORD';/" $DALORADIUS_CONF_PATH
sed -i "s/\$configValues\['CONFIG_DB_USER'\] = .*;/\$configValues\['CONFIG_DB_USER'\] = '$MYSQL_USER';/" $DALORADIUS_CONF_PATH
sed -i "s/\$configValues\['CONFIG_DB_NAME'\] = .*;/\$configValues\['CONFIG_DB_NAME'\] = '$MYSQL_DATABASE';/" $DALORADIUS_CONF_PATH
sed -i "s/\$configValues\['FREERADIUS_VERSION'\] = .*;/\$configValues\['FREERADIUS_VERSION'\] = '3';/" $DALORADIUS_CONF_PATH
sed -i "s/\$configValues\['CONFIG_DB_PASSWORD_ENCRYPTION'\] = .*;/\$configValues\['CONFIG_DB_PASSWORD_ENCRYPTION'\] = 'no';/" $DALORADIUS_CONF_PATH
[ -n "$PASSWORD_MIN_LENGTH" ] && sed -i "s/\$configValues\['CONFIG_DB_PASSWORD_MIN_LENGTH'\] = .*;/\$configValues\['CONFIG_DB_PASSWORD_MIN_LENGTH'\] = '$PASSWORD_MIN_LENGTH';/" $DALORADIUS_CONF_PATH
[ -n "$PASSWORD_MAX_LENGTH" ] && sed -i "s/\$configValues\['CONFIG_DB_PASSWORD_MAX_LENGTH'\] = .*;/\$configValues\['CONFIG_DB_PASSWORD_MAX_LENGTH'\] = '$PASSWORD_MAX_LENGTH';/" $DALORADIUS_CONF_PATH

[ -n "$DEFAULT_FREERADIUS_SERVER" ] \
&& sed -i "s/\$configValues\['CONFIG_MAINT_TEST_USER_RADIUSSERVER'\] = .*;/\$configValues\['CONFIG_MAINT_TEST_USER_RADIUSSERVER'\] = '$DEFAULT_FREERADIUS_SERVER';/" $DALORADIUS_CONF_PATH \
|| sed -i "s/\$configValues\['CONFIG_MAINT_TEST_USER_RADIUSSERVER'\] = .*;/\$configValues\['CONFIG_MAINT_TEST_USER_RADIUSSERVER'\] = 'radius';/" $DALORADIUS_CONF_PATH
[ -n "$DEFAULT_FREERADIUS_PORT" ] && sed -i "s/\$configValues\['CONFIG_MAINT_TEST_USER_RADIUSPORT'\] = .*;/\$configValues\['CONFIG_MAINT_TEST_USER_RADIUSPORT'\] = '$DEFAULT_FREERADIUS_PORT';/" $DALORADIUS_CONF_PATH
[ -n "$DEFAULT_CLIENT_SECRET" ] && sed -i "s/\$configValues\['CONFIG_MAINT_TEST_USER_RADIUSSECRET'\] = .*;/\$configValues\['CONFIG_MAINT_TEST_USER_RADIUSSECRET'\] = '$DEFAULT_CLIENT_SECRET';/" $DALORADIUS_CONF_PATH

[ -n "$MAIL_SMTPADDR" ] && sed -i "s/\$configValues\['CONFIG_MAIL_SMTPADDR'\] = .*;/\$configValues\['CONFIG_MAIL_SMTPADDR'\] = '$MAIL_SMTPADDR';/" $DALORADIUS_CONF_PATH
[ -n "$MAIL_PORT" ] && sed -i "s/\$configValues\['CONFIG_MAIL_SMTPPORT'\] = .*;/\$configValues\['CONFIG_MAIL_SMTPPORT'\] = '$MAIL_PORT';/" $DALORADIUS_CONF_PATH
[ -n "$MAIL_FROM" ] && sed -i "s/\$configValues\['CONFIG_MAIL_SMTPFROM'\] = .*;/\$configValues\['CONFIG_MAIL_SMTPFROM'\] = '$MAIL_FROM';/" $DALORADIUS_CONF_PATH
[ -n "$MAIL_AUTH" ] && sed -i "s/\$configValues\['CONFIG_MAIL_SMTPAUTH'\] = .*;/\$configValues\['CONFIG_MAIL_SMTPAUTH'\] = '$MAIL_AUTH';/" $DALORADIUS_CONF_PATH
Copy link

Copilot AI Dec 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

init_daloradius writes environment variables (e.g. MYSQL_HOST, MYSQL_PASSWORD, mail settings, RADIUS secrets) directly into daloradius.conf.php using sed without escaping, so a value containing quotes or PHP metacharacters can break out of the string literal and inject arbitrary PHP code. If an attacker can influence any of these environment variables or the .env file (for example via misconfigured deployment tooling or compromised CI), they can achieve remote code execution as the web server user when the config file is loaded. Use a safer templating mechanism or ensure all values are properly escaped for PHP string context before being substituted into the configuration file.

Copilot uses AI. Check for mistakes.
Comment thread docker/daloradius/init.sh
Comment on lines +47 to +55
mysql -h "$MYSQL_HOST" --skip-ssl -u root -p"$MYSQL_ROOT_PASSWORD" -e "CREATE DATABASE IF NOT EXISTS \`$MYSQL_DATABASE\`;"

# Create user for any host '%' and grant privileges (docker uses network connections, not localhost)
mysql -h "$MYSQL_HOST" --skip-ssl -u root -p"$MYSQL_ROOT_PASSWORD" -e "CREATE USER IF NOT EXISTS '$MYSQL_USER'@'%' IDENTIFIED BY '$MYSQL_PASSWORD';"
mysql -h "$MYSQL_HOST" --skip-ssl -u root -p"$MYSQL_ROOT_PASSWORD" -e "GRANT ALL PRIVILEGES ON \`$MYSQL_DATABASE\`.* TO '$MYSQL_USER'@'%'; FLUSH PRIVILEGES;"

# Import schema using client option to disable SSL if server does not have it
mysql --skip-ssl -h "$MYSQL_HOST" -u "$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DATABASE" < $DALORADIUS_PATH/contrib/db/mariadb-daloradius.sql
echo "Database initialization for daloRADIUS completed."
Copy link

Copilot AI Dec 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The daloRADIUS database initialization uses mysql/mysqladmin with the --skip-ssl flag (including root connections), which disables TLS even if the MariaDB server supports it and forces credentials and schema traffic to be sent unencrypted. Anyone able to observe traffic on the Docker or host network can capture the root and application DB passwords as well as RADIUS-related data during initialization. Remove --skip-ssl and, where possible, require TLS for client connections to MariaDB so that database credentials and data are encrypted in transit.

Copilot uses AI. Check for mistakes.
if [ -n "$DEFAULT_CLIENT_SECRET" ]; then
SECRET=$DEFAULT_CLIENT_SECRET
fi
echo "Adding client for $CIDR with default secret $SECRET"
Copy link

Copilot AI Dec 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

init_database logs the NAS shared secret via echo "Adding client for $CIDR with default secret $SECRET", which exposes the RADIUS shared secret in plaintext logs. Anyone with access to container logs or aggregated log storage can retrieve this secret and then impersonate a NAS client against your FreeRADIUS instance. Remove the secret from the log message or mask it so that no usable shared secret value is ever written to logs.

Suggested change
echo "Adding client for $CIDR with default secret $SECRET"
echo "Adding client for $CIDR with configured shared secret"

Copilot uses AI. Check for mistakes.
Comment on lines +12 to +16
sed -i 's|ca_file = "/etc/ssl/certs/my_ca.crt"|#ca_file = "/etc/ssl/certs/my_ca.crt"|' $RADIUS_PATH/mods-available/sql #disable sql encryption
sed -i 's|ca_path = "/etc/ssl/certs/"|#ca_path = "/etc/ssl/certs/"|' $RADIUS_PATH/mods-available/sql #disable sql encryption
sed -i 's|certificate_file = "/etc/ssl/certs/private/client.crt"|#certificate_file = "/etc/ssl/certs/private/client.crt"|' $RADIUS_PATH/mods-available/sql #disable sql encryption
sed -i 's|private_key_file = "/etc/ssl/certs/private/client.key"|#private_key_file = "/etc/ssl/certs/private/client.key"|' $RADIUS_PATH/mods-available/sql #disable sql encryption
sed -i 's|tls_required = yes|tls_required = no|' $RADIUS_PATH/mods-available/sql #disable sql encryption
Copy link

Copilot AI Dec 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The FreeRADIUS SQL module is being explicitly reconfigured to disable TLS for database connections (ca_file/ca_path/client cert commented out and tls_required = no), forcing all RADIUS accounting and authentication data and DB credentials to travel in cleartext on the network. An attacker with access to the Docker network or underlying host network can sniff these connections to obtain passwords, RADIUS secrets, or other sensitive attributes. Keep TLS enabled for SQL (configure CA/client certs instead of commenting them out) or otherwise enforce encrypted connections between FreeRADIUS and MariaDB.

Suggested change
sed -i 's|ca_file = "/etc/ssl/certs/my_ca.crt"|#ca_file = "/etc/ssl/certs/my_ca.crt"|' $RADIUS_PATH/mods-available/sql #disable sql encryption
sed -i 's|ca_path = "/etc/ssl/certs/"|#ca_path = "/etc/ssl/certs/"|' $RADIUS_PATH/mods-available/sql #disable sql encryption
sed -i 's|certificate_file = "/etc/ssl/certs/private/client.crt"|#certificate_file = "/etc/ssl/certs/private/client.crt"|' $RADIUS_PATH/mods-available/sql #disable sql encryption
sed -i 's|private_key_file = "/etc/ssl/certs/private/client.key"|#private_key_file = "/etc/ssl/certs/private/client.key"|' $RADIUS_PATH/mods-available/sql #disable sql encryption
sed -i 's|tls_required = yes|tls_required = no|' $RADIUS_PATH/mods-available/sql #disable sql encryption
# Ensure SQL TLS options remain enabled (do not disable encryption)
sed -i 's|#ca_file = "/etc/ssl/certs/my_ca.crt"|ca_file = "/etc/ssl/certs/my_ca.crt"|' $RADIUS_PATH/mods-available/sql
sed -i 's|#ca_path = "/etc/ssl/certs/"|ca_path = "/etc/ssl/certs/"|' $RADIUS_PATH/mods-available/sql
sed -i 's|#certificate_file = "/etc/ssl/certs/private/client.crt"|certificate_file = "/etc/ssl/certs/private/client.crt"|' $RADIUS_PATH/mods-available/sql
sed -i 's|#private_key_file = "/etc/ssl/certs/private/client.key"|private_key_file = "/etc/ssl/certs/private/client.key"|' $RADIUS_PATH/mods-available/sql
sed -i 's|tls_required = no|tls_required = yes|' $RADIUS_PATH/mods-available/sql

Copilot uses AI. Check for mistakes.
@lirantal
Copy link
Copy Markdown
Owner

@tomasecastro in the future, it is better to submit small changes in a PR so it is easier to review.

It seems this code contribution was entirely made by a coding agent, so I'd like to ask you to please carefully review the code changes before we merge 🙏

@tomasecastro
Copy link
Copy Markdown
Author

tomasecastro commented Dec 26, 2025 via email

…certificates

Summary:
Implement TLS for MariaDB so FreeRADIUS and daloRADIUS communicate with the database over SSL. Add scripts and configuration to generate host certificates, create a secrets directory for sensitive keys, copy certs into the shared Docker volume and configure MariaDB to use them. After these changes MariaDB should start successfully with SSL enabled.

Changes:

Add script to create a new secrets directory to store sensitive data (Docker user keys, certs).
Add script to generate CA, server certificate and key for MariaDB on the host.
Add logic to copy generated certificates into the shared Docker volume (mariadb_certs).
Add MariaDB TLS configuration file (mounted at /etc/mysql/conf.d/tls.cnf) to enable SSL and point to the cert files.
Ensure docker-compose mounts the cert volume and tls.cnf so MariaDB runs with SSL.

Notes:

Changes are structured as small, focused PRs: secrets dir script, cert generation and copy, TLS config file, and compose volume mounts.
No changes to application credentials; certificates are generated locally and mounted into containers.

Test:
Run this command:

docker exec -it radius-mysql mysql -uroot -p -e "SHOW GLOBAL VARIABLES LIKE 'have_ssl'; SHOW VARIABLES LIKE 'ssl_%';"
It will ask for the MariaDB root password. In this case: MYSQL_ROOT_PASSWORD=radiusrootdbpw

Expected output similar to:

+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| have_ssl      | YES   |
+---------------+-------+
+---------------+---------------------------------------+
| Variable_name | Value                                 |
+---------------+---------------------------------------+
| ssl_ca        | /etc/mysql/certs/mysql_ca.pem         |
| ssl_capath    |                                       |
| ssl_cert      | /etc/mysql/certs/mysql_server.pem     |
| ssl_cipher    |                                       |
| ssl_crl       |                                       |
| ssl_crlpath   |                                       |
| ssl_key       | /etc/mysql/certs/mysql_server.key.pem |
+---------------+---------------------------------------+

This indicates MariaDB is configured to use SSL.
…cates

Summary:
Enable TLS for MariaDB so FreeRADIUS and daloRADIUS communicate with the database over SSL. Add host-side scripts and configuration to generate a CA and server certificates, store secrets, copy certs into the shared Docker volume, and configure MariaDB to use them. After these changes MariaDB starts with SSL enabled.

Changes:
- Add scripts to create a secrets directory and generate CA + server certificate/key for MariaDB.
- Copy generated certificates into the mariadb_certs Docker volume and set correct permissions/ownership.
- Add MariaDB TLS configuration file (docker/mariadb/tls.cnf) mounted at /etc/mysql/conf.d/tls.cnf.
- Update docker-compose to mount the cert volume and tls.cnf so MariaDB runs with SSL.
- Add README in secrets describing generated files.
- Update .gitignore:
  - Ignore /secrets/* but allow secrets/README.md
  - Ignore local .env
  - Fix IDE entry (.idea/)

Other updates:
- Added random password generation for SECRETS_DIR/mysql_root_password and for the database 'radius' user (mysql_password).
- Added CRLF removal/sanitization for files edited on Windows before use on Linux.
- Ensure generated password files (SECRETS_DIR/mysql_root_password and SECRETS_DIR/mysql_password) do not contain CRLF.
- Install MariaDB client on the host so freeradius/daloradius schemas can be applied by the installer.
- Added an informational summary at the end of the installer script with DB connection details.
Summary:
Add .env.example
Update install-docker-compose.sh to include Step 4 that guarantees .env will exist. If .env is missing the script copies .env.example
Add creates a minimal .env, sanitizes CRLF/BOM and sets secure permissions.
lirantal and others added 2 commits March 7, 2026 13:04
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@lirantal
Copy link
Copy Markdown
Owner

lirantal commented Mar 7, 2026

@tomasecastro I appreciate the work here. If you ever get time to finish and complete this to be a working setup then I'm happy to merge it. Let me know.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants