516 lines
13 KiB
Bash
516 lines
13 KiB
Bash
#!/usr/bin/env bash
|
|
set -Eeuo pipefail
|
|
|
|
CONTAINER="nextcloud"
|
|
OVERRIDE="/var/www/html/config/zz-docker-env.config.php"
|
|
|
|
FIX=false
|
|
|
|
if [[ "${1:-}" == "--fix" ]]; then
|
|
FIX=true
|
|
fi
|
|
|
|
PASS=0
|
|
FAIL=0
|
|
|
|
pass() {
|
|
echo "PASS: $1"
|
|
PASS=$((PASS + 1))
|
|
}
|
|
|
|
fail() {
|
|
echo "FAIL: $1"
|
|
FAIL=$((FAIL + 1))
|
|
}
|
|
|
|
# ============================================================
|
|
# Basic checks
|
|
# ============================================================
|
|
|
|
echo "=========================================="
|
|
echo " Nextcloud Docker configuration checker"
|
|
echo "=========================================="
|
|
echo
|
|
|
|
if ! docker inspect "$CONTAINER" >/dev/null 2>&1; then
|
|
echo "FAIL: Docker container '$CONTAINER' does not exist"
|
|
exit 1
|
|
fi
|
|
|
|
if [[ "$(docker inspect -f '{{.State.Running}}' "$CONTAINER")" != "true" ]]; then
|
|
echo "FAIL: Docker container '$CONTAINER' is not running"
|
|
exit 1
|
|
fi
|
|
|
|
if [[ ! -f ".env" ]]; then
|
|
echo "FAIL: .env not found"
|
|
exit 1
|
|
fi
|
|
|
|
# ============================================================
|
|
# Read .env
|
|
# ============================================================
|
|
|
|
declare -A ENV
|
|
|
|
while IFS='=' read -r key value; do
|
|
|
|
key="${key//$'\r'/}"
|
|
value="${value//$'\r'/}"
|
|
|
|
# Ignore empty lines
|
|
[[ -z "${key// /}" ]] && continue
|
|
|
|
# Ignore comments
|
|
[[ "$key" =~ ^[[:space:]]*# ]] && continue
|
|
|
|
# Trim whitespace
|
|
key="${key#"${key%%[![:space:]]*}"}"
|
|
key="${key%"${key##*[![:space:]]}"}"
|
|
|
|
# Remove "export "
|
|
key="${key#export }"
|
|
|
|
# Remove quotes
|
|
value="${value#\"}"
|
|
value="${value%\"}"
|
|
value="${value#\'}"
|
|
value="${value%\'}"
|
|
|
|
ENV["$key"]="$value"
|
|
|
|
done < .env
|
|
|
|
MYSQL_PASSWORD="${ENV[MYSQL_PASSWORD]:-}"
|
|
MYSQL_ROOT_PASSWORD="${ENV[MYSQL_ROOT_PASSWORD]:-}"
|
|
REDIS_PASSWORD="${ENV[REDIS_PASSWORD]:-}"
|
|
NEXTCLOUD_ADMIN_USER="${ENV[NEXTCLOUD_ADMIN_USER]:-}"
|
|
NEXTCLOUD_ADMIN_PASSWORD="${ENV[NEXTCLOUD_ADMIN_PASSWORD]:-}"
|
|
NEXTCLOUD_DOMAIN="${ENV[NEXTCLOUD_DOMAIN]:-}"
|
|
|
|
# ============================================================
|
|
# Environment checks
|
|
# ============================================================
|
|
|
|
echo "Checking .env variables"
|
|
echo "-----------------------"
|
|
|
|
for name in \
|
|
MYSQL_PASSWORD \
|
|
MYSQL_ROOT_PASSWORD \
|
|
REDIS_PASSWORD \
|
|
NEXTCLOUD_ADMIN_USER \
|
|
NEXTCLOUD_ADMIN_PASSWORD \
|
|
NEXTCLOUD_DOMAIN
|
|
do
|
|
if [[ -n "${ENV[$name]:-}" ]]; then
|
|
pass "$name is defined"
|
|
else
|
|
fail "$name is missing"
|
|
fi
|
|
done
|
|
|
|
echo
|
|
|
|
# ============================================================
|
|
# Read config.php
|
|
#
|
|
# PHP runs ONLY inside Docker.
|
|
# No PHP is required on the host.
|
|
# ============================================================
|
|
|
|
CONFIG_JSON="$(
|
|
docker exec "$CONTAINER" php -r '
|
|
$CONFIG = [];
|
|
|
|
include "/var/www/html/config/config.php";
|
|
|
|
echo json_encode([
|
|
"dbhost" =>
|
|
$CONFIG["dbhost"] ?? "",
|
|
|
|
"dbname" =>
|
|
$CONFIG["dbname"] ?? "",
|
|
|
|
"dbuser" =>
|
|
$CONFIG["dbuser"] ?? "",
|
|
|
|
"dbpassword" =>
|
|
$CONFIG["dbpassword"] ?? "",
|
|
|
|
"redis_host" =>
|
|
$CONFIG["redis"]["host"] ?? "",
|
|
|
|
"redis_password" =>
|
|
$CONFIG["redis"]["password"] ?? "",
|
|
|
|
"overwriteprotocol" =>
|
|
$CONFIG["overwriteprotocol"] ?? "",
|
|
|
|
"overwrite_cli_url" =>
|
|
$CONFIG["overwrite.cli.url"] ?? "",
|
|
|
|
"trusted_domains" =>
|
|
$CONFIG["trusted_domains"] ?? [],
|
|
|
|
"trusted_proxies" =>
|
|
$CONFIG["trusted_proxies"] ?? []
|
|
]);
|
|
'
|
|
)"
|
|
|
|
# ============================================================
|
|
# Extract configuration
|
|
# ============================================================
|
|
|
|
DB_HOST="$(jq -r '.dbhost' <<< "$CONFIG_JSON")"
|
|
DB_NAME="$(jq -r '.dbname' <<< "$CONFIG_JSON")"
|
|
DB_USER="$(jq -r '.dbuser' <<< "$CONFIG_JSON")"
|
|
DB_PASSWORD="$(jq -r '.dbpassword' <<< "$CONFIG_JSON")"
|
|
|
|
REDIS_HOST="$(jq -r '.redis_host' <<< "$CONFIG_JSON")"
|
|
REDIS_PASSWORD_CONFIG="$(jq -r '.redis_password' <<< "$CONFIG_JSON")"
|
|
|
|
OVERWRITE_PROTOCOL="$(jq -r '.overwriteprotocol' <<< "$CONFIG_JSON")"
|
|
OVERWRITE_CLI_URL="$(jq -r '.overwrite_cli_url' <<< "$CONFIG_JSON")"
|
|
|
|
# ============================================================
|
|
# Database
|
|
# ============================================================
|
|
|
|
echo "Checking database configuration"
|
|
echo "-------------------------------"
|
|
|
|
if [[ "$DB_HOST" == "mariadb" ]]; then
|
|
pass "dbhost = mariadb"
|
|
else
|
|
fail "dbhost: expected mariadb, got $DB_HOST"
|
|
fi
|
|
|
|
if [[ "$DB_NAME" == "nextcloud" ]]; then
|
|
pass "dbname = nextcloud"
|
|
else
|
|
fail "dbname: expected nextcloud, got $DB_NAME"
|
|
fi
|
|
|
|
if [[ "$DB_USER" == "nextcloud" ]]; then
|
|
pass "dbuser = nextcloud"
|
|
else
|
|
fail "dbuser: expected nextcloud, got $DB_USER"
|
|
fi
|
|
|
|
if [[ "$MYSQL_PASSWORD" == "$DB_PASSWORD" ]]; then
|
|
pass "dbpassword"
|
|
else
|
|
fail "dbpassword"
|
|
fi
|
|
|
|
echo
|
|
|
|
# ============================================================
|
|
# Redis
|
|
# ============================================================
|
|
|
|
echo "Checking Redis configuration"
|
|
echo "----------------------------"
|
|
|
|
if [[ "$REDIS_HOST" == "redis" ]]; then
|
|
pass "redis host = redis"
|
|
else
|
|
fail "redis host: expected redis, got $REDIS_HOST"
|
|
fi
|
|
|
|
if [[ "$REDIS_PASSWORD" == "$REDIS_PASSWORD_CONFIG" ]]; then
|
|
pass "redis password"
|
|
else
|
|
fail "redis password"
|
|
echo " expected: [hidden]"
|
|
echo " actual: [hidden]"
|
|
fi
|
|
|
|
echo
|
|
|
|
# ============================================================
|
|
# URL
|
|
# ============================================================
|
|
|
|
echo "Checking Nextcloud URL configuration"
|
|
echo "------------------------------------"
|
|
|
|
if [[ "$OVERWRITE_PROTOCOL" == "https" ]]; then
|
|
pass "overwriteprotocol = https"
|
|
else
|
|
fail "overwriteprotocol: expected https, got $OVERWRITE_PROTOCOL"
|
|
fi
|
|
|
|
EXPECTED_URL="https://${NEXTCLOUD_DOMAIN}"
|
|
|
|
if [[ "$OVERWRITE_CLI_URL" == "$EXPECTED_URL" ]]; then
|
|
pass "overwrite.cli.url = $EXPECTED_URL"
|
|
else
|
|
fail "overwrite.cli.url"
|
|
echo " expected: $EXPECTED_URL"
|
|
echo " actual: $OVERWRITE_CLI_URL"
|
|
fi
|
|
|
|
echo
|
|
|
|
# ============================================================
|
|
# Trusted domains
|
|
# ============================================================
|
|
|
|
echo "Checking trusted domains"
|
|
echo "-----------------------"
|
|
|
|
if jq -e \
|
|
--arg domain "$NEXTCLOUD_DOMAIN" \
|
|
'.trusted_domains | index($domain) != null' \
|
|
<<< "$CONFIG_JSON" >/dev/null
|
|
then
|
|
pass "trusted_domains contains $NEXTCLOUD_DOMAIN"
|
|
else
|
|
fail "trusted_domains does not contain $NEXTCLOUD_DOMAIN"
|
|
fi
|
|
|
|
echo
|
|
|
|
# ============================================================
|
|
# Trusted proxies
|
|
# ============================================================
|
|
|
|
echo "Checking trusted proxies"
|
|
echo "------------------------"
|
|
|
|
if jq -e \
|
|
'.trusted_proxies | index("172.16.0.0/12") != null' \
|
|
<<< "$CONFIG_JSON" >/dev/null
|
|
then
|
|
pass "trusted_proxies contains 172.16.0.0/12"
|
|
else
|
|
fail "trusted_proxies does not contain 172.16.0.0/12"
|
|
fi
|
|
|
|
echo
|
|
|
|
# ============================================================
|
|
# FIX
|
|
# ============================================================
|
|
|
|
if [[ "$FIX" == true ]]; then
|
|
|
|
echo "=========================================="
|
|
echo " Fixing Nextcloud configuration"
|
|
echo "=========================================="
|
|
echo
|
|
|
|
# --------------------------------------------------------
|
|
# Backup existing override
|
|
# --------------------------------------------------------
|
|
|
|
if docker exec "$CONTAINER" test -f "$OVERRIDE"; then
|
|
|
|
BACKUP="/var/www/html/config/zz-docker-env.config.php.backup.$(date +%Y%m%d-%H%M%S)"
|
|
|
|
docker exec "$CONTAINER" \
|
|
cp "$OVERRIDE" "$BACKUP"
|
|
|
|
echo "Backup created:"
|
|
echo " $BACKUP"
|
|
echo
|
|
fi
|
|
|
|
# --------------------------------------------------------
|
|
# Generate override INSIDE the container.
|
|
#
|
|
# Therefore PHP is NOT required on the host.
|
|
# --------------------------------------------------------
|
|
|
|
docker exec \
|
|
-e MYSQL_PASSWORD="$MYSQL_PASSWORD" \
|
|
-e REDIS_PASSWORD="$REDIS_PASSWORD" \
|
|
-e NEXTCLOUD_DOMAIN="$NEXTCLOUD_DOMAIN" \
|
|
"$CONTAINER" \
|
|
php -r '
|
|
$mysql = getenv("MYSQL_PASSWORD");
|
|
$redis = getenv("REDIS_PASSWORD");
|
|
$domain = getenv("NEXTCLOUD_DOMAIN");
|
|
|
|
$file = "/var/www/html/config/zz-docker-env.config.php";
|
|
|
|
$config = "<?php\n\n";
|
|
|
|
$config .= "\$CONFIG[\"dbhost\"] = "
|
|
. var_export("mariadb", true)
|
|
. ";\n";
|
|
|
|
$config .= "\$CONFIG[\"dbname\"] = "
|
|
. var_export("nextcloud", true)
|
|
. ";\n";
|
|
|
|
$config .= "\$CONFIG[\"dbuser\"] = "
|
|
. var_export("nextcloud", true)
|
|
. ";\n";
|
|
|
|
$config .= "\$CONFIG[\"dbpassword\"] = "
|
|
. var_export($mysql, true)
|
|
. ";\n\n";
|
|
|
|
$config .= "\$CONFIG[\"redis\"][\"host\"] = "
|
|
. var_export("redis", true)
|
|
. ";\n";
|
|
|
|
$config .= "\$CONFIG[\"redis\"][\"port\"] = 6379;\n";
|
|
|
|
$config .= "\$CONFIG[\"redis\"][\"password\"] = "
|
|
. var_export($redis, true)
|
|
. ";\n\n";
|
|
|
|
$config .= "\$CONFIG[\"overwriteprotocol\"] = "
|
|
. var_export("https", true)
|
|
. ";\n";
|
|
|
|
$config .= "\$CONFIG[\"overwrite.cli.url\"] = "
|
|
. var_export("https://" . $domain, true)
|
|
. ";\n\n";
|
|
|
|
$config .= "\$CONFIG[\"trusted_domains\"][] = "
|
|
. var_export($domain, true)
|
|
. ";\n";
|
|
|
|
$config .= "\$CONFIG[\"trusted_proxies\"][] = "
|
|
. var_export("172.16.0.0/12", true)
|
|
. ";\n";
|
|
|
|
file_put_contents($file, $config);
|
|
'
|
|
|
|
# --------------------------------------------------------
|
|
# Permissions
|
|
# --------------------------------------------------------
|
|
|
|
docker exec "$CONTAINER" \
|
|
chown www-data:www-data "$OVERRIDE"
|
|
|
|
docker exec "$CONTAINER" \
|
|
chmod 640 "$OVERRIDE"
|
|
|
|
echo "Configuration override written:"
|
|
echo " $OVERRIDE"
|
|
echo
|
|
|
|
# --------------------------------------------------------
|
|
# Show the file WITHOUT exposing passwords
|
|
# --------------------------------------------------------
|
|
|
|
echo "Configuration written:"
|
|
docker exec "$CONTAINER" \
|
|
sed -E \
|
|
's/(password"\] = ).*/\1"[HIDDEN]";/' \
|
|
"$OVERRIDE"
|
|
|
|
echo
|
|
|
|
# --------------------------------------------------------
|
|
# Verify
|
|
# --------------------------------------------------------
|
|
|
|
echo "=========================================="
|
|
echo " Verification"
|
|
echo "=========================================="
|
|
echo
|
|
|
|
# Important:
|
|
# config.php itself is not modified.
|
|
# Nextcloud loads the additional config file.
|
|
#
|
|
# Re-read effective Nextcloud configuration.
|
|
|
|
EFFECTIVE_JSON="$(
|
|
docker exec "$CONTAINER" php -r '
|
|
$CONFIG = [];
|
|
|
|
include "/var/www/html/config/config.php";
|
|
|
|
if (file_exists("/var/www/html/config/zz-docker-env.config.php")) {
|
|
include "/var/www/html/config/zz-docker-env.config.php";
|
|
}
|
|
|
|
echo json_encode([
|
|
"dbhost" => $CONFIG["dbhost"] ?? "",
|
|
"dbname" => $CONFIG["dbname"] ?? "",
|
|
"dbuser" => $CONFIG["dbuser"] ?? "",
|
|
"dbpassword" => $CONFIG["dbpassword"] ?? "",
|
|
|
|
"redis_host" => $CONFIG["redis"]["host"] ?? "",
|
|
"redis_password" => $CONFIG["redis"]["password"] ?? "",
|
|
|
|
"overwriteprotocol" =>
|
|
$CONFIG["overwriteprotocol"] ?? "",
|
|
|
|
"overwrite_cli_url" =>
|
|
$CONFIG["overwrite.cli.url"] ?? "",
|
|
|
|
"trusted_domains" =>
|
|
$CONFIG["trusted_domains"] ?? [],
|
|
|
|
"trusted_proxies" =>
|
|
$CONFIG["trusted_proxies"] ?? []
|
|
]);
|
|
'
|
|
)"
|
|
|
|
EFFECTIVE_REDIS_PASSWORD="$(
|
|
jq -r '.redis_password' <<< "$EFFECTIVE_JSON"
|
|
)"
|
|
|
|
EFFECTIVE_DOMAINS="$(
|
|
jq -r '.trusted_domains[]?' <<< "$EFFECTIVE_JSON"
|
|
)"
|
|
|
|
if [[ "$EFFECTIVE_REDIS_PASSWORD" == "$REDIS_PASSWORD" ]]; then
|
|
pass "Redis password fixed"
|
|
else
|
|
fail "Redis password was not fixed"
|
|
fi
|
|
|
|
if grep -Fxq "$NEXTCLOUD_DOMAIN" <<< "$EFFECTIVE_DOMAINS"; then
|
|
pass "trusted_domains fixed"
|
|
else
|
|
fail "trusted_domains was not fixed"
|
|
fi
|
|
|
|
echo
|
|
|
|
echo "=========================================="
|
|
echo " Fix complete"
|
|
echo "=========================================="
|
|
|
|
exit 0
|
|
fi
|
|
|
|
# ============================================================
|
|
# Summary
|
|
# ============================================================
|
|
|
|
echo "=========================================="
|
|
echo "Result"
|
|
echo "=========================================="
|
|
|
|
echo "PASS: $PASS"
|
|
echo "FAIL: $FAIL"
|
|
|
|
if [[ "$FAIL" -eq 0 ]]; then
|
|
echo
|
|
echo "PASS: configuration is consistent."
|
|
exit 0
|
|
else
|
|
echo
|
|
echo "FAIL: configuration has mismatches."
|
|
echo
|
|
echo "Run:"
|
|
echo
|
|
echo " $0 --fix"
|
|
echo
|
|
exit 1
|
|
fi
|