#!/bin/sh # ============================================================================= # Authelia + Authelia-API Container Entrypoint # # Starts both services, monitors their health, and handles graceful shutdown. # Authelia-API runs through a supervisor loop since it is the secondary service. # ============================================================================= set -e # --- Configuration defaults (overridable via env) --- AUTHELIA_CONFIG="${AUTHELIA_CONFIG:-/config/configuration.yml}" AUTHELIA_API_LISTEN="${AUTHELIA_API_LISTEN:-0.0.0.0:8080}" AUTHELIA_API_DB="${AUTHELIA_API_DB:-/data/authelia-api.db}" AUTHELIA_API_LOG_LEVEL="${AUTHELIA_API_LOG_LEVEL:-info}" AUTHELIA_PORT="${AUTHELIA_PORT:-9091}" # --- Colors for logging --- INFO="[INFO]" WARN="[WARN]" ERR="[ERROR]" echo "${INFO} ================================================" echo "${INFO} Authelia + Authelia-API Container" echo "${INFO} Authelia port: ${AUTHELIA_PORT}" echo "${INFO} API listen: ${AUTHELIA_API_LISTEN}" echo "${INFO} API database: ${AUTHELIA_API_DB}" echo "${INFO} API log level: ${AUTHELIA_API_LOG_LEVEL}" echo "${INFO} ================================================" # --- Signal handler --- cleanup() { echo "${INFO} Shutting down..." kill -TERM "${AUTHELIA_PID}" 2>/dev/null || true kill -TERM "${API_PID}" 2>/dev/null || true wait "${AUTHELIA_PID}" 2>/dev/null || true wait "${API_PID}" 2>/dev/null || true echo "${INFO} Shutdown complete" exit 0 } trap cleanup TERM INT # --- Helper: wait for a TCP port to be reachable --- wait_for_port() { local host="$1" port="$2" max_attempts="${3:-30}" interval="${4:-2}" echo "${INFO} Waiting for ${host}:${port} to be ready..." i=0 while [ "${i}" -lt "${max_attempts}" ]; do if nc -z "${host}" "${port}" 2>/dev/null; then echo "${INFO} ${host}:${port} is ready (attempt $((i + 1)))" return 0 fi i=$((i + 1)) sleep "${interval}" done echo "${ERR} ${host}:${port} not reachable after ${max_attempts} attempts" return 1 } # ============================================================================= # 1. Bootstrap required files # ============================================================================= # Create empty users database if missing (Authelia requires it to exist) if [ ! -f "/config/users_database.yml" ]; then echo "${INFO} Creating empty users database at /config/users_database.yml" echo 'users: {}' > /config/users_database.yml fi # Create empty notifications file if missing if [ ! -f "/config/notifications.yml" ]; then echo "${INFO} Creating empty notifications file at /config/notifications.yml" touch /config/notifications.yml fi # ============================================================================= # 2. Validate / generate configuration # ============================================================================= if [ ! -f "${AUTHELIA_CONFIG}" ]; then echo "${WARN} No Authelia config found at ${AUTHELIA_CONFIG}" echo "${WARN} Provide one via volume mount or set AUTHELIA_CONFIG env var" echo "${WARN} Starting with a minimal configuration instead..." mkdir -p /tmp/authelia-config cat > /tmp/authelia-config/configuration.yml << EOF ######################################## # Authelia minimal config — replace me ######################################## server: address: tcp://0.0.0.0:${AUTHELIA_PORT} log: level: info identity_validation: reset_password: jwt_secret: changeme_changeme_changeme_changeme_changeme default_redirection_url: https://auth.example.com totp: issuer: authelia authentication_backend: file: path: /config/users_database.yml access_control: default_policy: two_factor rules: - domain: example.com policy: bypass session: name: authelia_session secret: changeme_changeme_changeme_changeme_changeme expiration: 1h inactivity: 5m remember_me: 1M domain: example.com regulation: max_retries: 5 find_time: 2m ban_time: 5m storage: encryption_key: changeme_changeme_changeme_changeme_changeme local: path: /config/db.sqlite3 notifier: filesystem: filename: /config/notifications.yml EOF AUTHELIA_CONFIG="/tmp/authelia-config/configuration.yml" fi # ============================================================================= # 3. Start Authelia # ============================================================================= echo "${INFO} Starting Authelia..." authelia --config "${AUTHELIA_CONFIG}" & AUTHELIA_PID=$! echo "${INFO} Authelia started (PID: ${AUTHELIA_PID})" wait_for_port "127.0.0.1" "${AUTHELIA_PORT}" 30 2 || { echo "${ERR} Authelia failed to start within timeout" echo "${ERR} Check logs above for configuration errors." kill "${AUTHELIA_PID}" 2>/dev/null || true exit 1 } # ============================================================================= # 4. Start Authelia-API # ============================================================================= echo "${INFO} Starting Authelia-API..." authelia-api \ -config "${AUTHELIA_CONFIG}" \ -listen "${AUTHELIA_API_LISTEN}" \ -db "${AUTHELIA_API_DB}" \ -log-level "${AUTHELIA_API_LOG_LEVEL}" & API_PID=$! echo "${INFO} Authelia-API started (PID: ${API_PID})" echo "${INFO} ================================================" echo "${INFO} Both services are running" echo "${INFO} Authelia: http://0.0.0.0:${AUTHELIA_PORT}" echo "${INFO} Authelia-API: http://0.0.0.0:${AUTHELIA_API_LISTEN##*:}" echo "${INFO} ================================================" # ============================================================================= # 5. Monitor loop — exit if either process dies # ============================================================================= while true; do if ! kill -0 "${AUTHELIA_PID}" 2>/dev/null; then echo "${ERR} Authelia (PID ${AUTHELIA_PID}) exited unexpectedly" kill "${API_PID}" 2>/dev/null || true exit 1 fi if ! kill -0 "${API_PID}" 2>/dev/null; then echo "${ERR} Authelia-API (PID ${API_PID}) exited unexpectedly" kill "${AUTHELIA_PID}" 2>/dev/null || true exit 1 fi sleep 5 done