-
CWP: Persistent PHP intl Fix and Safe Roundcube 1.5.15 โ 1.6.20 LTS Upgrade
Additional procedure for servers still running Roundcube 1.5.8The fleet migration script intentionally accepts only Roundcube 1.5.15 and 1.6.20. If it detects 1.5.8, it stops without changing the installation. For an older 1.5.8 installation, use a controlled two-stage upgrade: 1.5.8 โ 1.5.15 โ 1.6.20This provides a tested intermediate checkpoint and avoids bypassing the scriptโs version-safety gate. 1. Confirm the installed versiongrep "define('RCMAIL_VERSION'" \ /usr/local/cwpsrv/var/services/roundcube/program/include/iniset.phpExpected result for an affected server: define('RCMAIL_VERSION', '1.5.8');2. Create backupsDo not proceed without both a filesystem and database backup. Create a filesystem backup: BACKUP_DIR="/root/roundcube-1.5.8-backup-$(date +%Y%m%d-%H%M%S)" mkdir -p "$BACKUP_DIR" tar --xattrs --acls --selinux -czpf \ "$BACKUP_DIR/roundcube-files.tar.gz" \ -C /usr/local/cwpsrv/var/services \ roundcubeAlso create a database dump using the Roundcube database credentials stored in: /usr/local/cwpsrv/var/services/roundcube/config/config.inc.phpVerify that both backup files exist and are non-empty before continuing. 3. Download the official Roundcube 1.5.15 packageUse a temporary working directory: WORK_DIR="$(mktemp -d /usr/local/src/roundcube-1.5.15.XXXXXX)" cd "$WORK_DIR"Download the official complete package and its signature: curl --fail --location --proto '=https' --tlsv1.2 \ --output roundcubemail-1.5.15-complete.tar.gz \ https://github.com/roundcube/roundcubemail/releases/download/1.5.15/roundcubemail-1.5.15-complete.tar.gz curl --fail --location --proto '=https' --tlsv1.2 \ --output roundcubemail-1.5.15-complete.tar.gz.asc \ https://github.com/roundcube/roundcubemail/releases/download/1.5.15/roundcubemail-1.5.15-complete.tar.gz.asc curl --fail --location --proto '=https' --tlsv1.2 \ --output roundcube-pubkey.asc \ https://roundcube.net/download/pubkey.asc4. Verify the signing key and packageUse an isolated GPG directory: export GNUPGHOME="$WORK_DIR/gnupg" mkdir -m 700 "$GNUPGHOME"Display the downloaded key fingerprint: gpg --batch \ --with-fingerprint \ --keyid-format long \ --import-options show-only \ --import roundcube-pubkey.ascThe expected primary key fingerprint is: F3E4 C04B B3DB 5D42 15C4 5F7F 5AB2 BAA1 41C4 F7D5If the fingerprint differs, stop immediately. Import the verified key and check the release signature: gpg --batch --import roundcube-pubkey.asc gpg --batch --verify \ roundcubemail-1.5.15-complete.tar.gz.asc \ roundcubemail-1.5.15-complete.tar.gzProceed only after a valid signature result. 5. Extract Roundcube 1.5.15mkdir "$WORK_DIR/source" tar -xzf roundcubemail-1.5.15-complete.tar.gz \ -C "$WORK_DIR/source" \ --strip-components=1Confirm that the official installer exists: test -f "$WORK_DIR/source/bin/installto.sh"6. Ensure all migration commands use CWP PHPThe CWP PHP binary is: /usr/local/cwp/php71/bin/phpDespite the directory name, verify its real version: /usr/local/cwp/php71/bin/php -vCreate a temporary php PATH shim: mkdir "$WORK_DIR/cwp-php-bin" ln -s /usr/local/cwp/php71/bin/php \ "$WORK_DIR/cwp-php-bin/php"This is important because installto.sh may start additional commands using: php bin/...The shim ensures that these child commands also use the CWP PHP binary instead of the system default PHP. 7. Perform the 1.5.8 โ 1.5.15 upgradeStop the CWP web service during the file and database migration: systemctl stop cwpsrvRun the official installer: PATH="$WORK_DIR/cwp-php-bin:$PATH" \ /usr/local/cwp/php71/bin/php \ "$WORK_DIR/source/bin/installto.sh" \ -y \ /usr/local/cwpsrv/var/services/roundcubeRestart CWP: /scripts/restart_cwpsrvConfirm the service state: systemctl is-active cwpsrvExpected result: active8. Verify the intermediate versiongrep "define('RCMAIL_VERSION'" \ /usr/local/cwpsrv/var/services/roundcube/program/include/iniset.phpExpected result: define('RCMAIL_VERSION', '1.5.15');Test at least: direct webmail login; CWP administrator auto-login; opening an existing message; sending a test message; attachment upload and download; address-book access; logout and a new login. Do not continue to 1.6.20 until the 1.5.15 installation works correctly. 9. Run the protected 1.5.15 โ 1.6.20 migrationFirst run the fleet script without modifications: ./roundcube-cwp-1.5.15-to-1.6.20.shIf the preflight succeeds: ./roundcube-cwp-1.5.15-to-1.6.20.sh --applyThe second migration installs Roundcube 1.6.20 and also: disables the obsolete /scripts/update_roundcube; protects it against later CWP overwrites; removes the recurring redundant extension=intl configuration; installs the systemd path and timer guards; creates another complete filesystem and database backup. 10. Final verificationgrep "define('RCMAIL_VERSION'" \ /usr/local/cwpsrv/var/services/roundcube/program/include/iniset.php /usr/local/cwp/php71/bin/php -v /usr/local/cwp/php71/bin/php -m \ | grep -i '^intl$' systemctl is-active \ cwpsrv \ cwp-roundcube-guard.path \ cwp-roundcube-guard.timerExpected Roundcube version: 1.6.20Expected service results: active active activeOnce the final functional tests have passed, remove the temporary 1.5.15 working directory: rm -rf -- "$WORK_DIR"Keep both sets of backups until the upgraded server has completed at least one normal operational and nightly CWP update cycle.
-
CWP: Persistent PHP intl Fix and Safe Roundcube 1.5.15 โ 1.6.20 LTS Upgrade
I encountered a recurring PHP startup warning on CWP servers: PHP Warning: PHP Startup: Unable to load dynamic library 'intl'The affected CWP PHP binary was: /usr/local/cwp/php71/bin/phpDespite the directory name, this was actually PHP 7.4.33: PHP 7.4.33 PHP API: 20190902The important diagnostic result was: /usr/local/cwp/php71/bin/php -n -r \ 'var_dump(PHP_VERSION, extension_loaded("intl"), phpversion("intl"));'Output: string(6) "7.4.33" bool(true) string(6) "7.4.33"This proved that intl was already compiled into the CWP PHP binary. However, CWP repeatedly recreated: /usr/local/cwp/php71/php.d/intl.iniwith: extension=intlPHP then tried to load a separate intl.so, although no compatible dynamic module was required. The source of the recurring configuration was: /scripts/update_roundcubeThe old updater also contained outdated PHP API paths, downloaded third-party intl.so binaries, installed separate ICU packages, and recreated intl.ini. Simply renaming or deleting intl.ini was therefore not permanent: a later CWP update could recreate it. Why upgrade Roundcube 1.5.15?Roundcube 1.5.15 was the final security release in the 1.5 branch. New security corrections are now released for the 1.6 LTS and 1.7 branches. Roundcube 1.6.20 contains later security fixes that are not present in 1.5.15, including fixes related to: IMAP command injection; stored and zero-click XSS; SSRF filter bypasses; e-mail header injection; remote-content blocking bypasses; cross-user address-book access; Sieve script injection; denial-of-service conditions. For existing CWP installations using the internal PHP 7.4 binary, Roundcube 1.6.20 is the appropriate target: Roundcube 1.6.20 LTS PHP requirement: PHP 7.3 or newer CWP PHP tested: PHP 7.4.33Roundcube 1.7 is not a drop-in replacement in this environment because it requires PHP 8.1 or newer and introduces additional web-root changes. Idempotent fleet upgrade scriptI created an idempotent migration script for CWP servers: roundcube-cwp-1.5.15-to-1.6.20.shIts behavior is: Current version Result with --apply Roundcube 1.5.15 Installs the protection and upgrades to 1.6.20 Roundcube 1.6.20 Verifies/reinstalls the protection and skips migration Any other version Stops without performing an uncertain migration The script: verifies the installed Roundcube version; checks the CWP PHP version and required extensions; verifies whether intl is compiled into PHP; downloads the official Roundcube 1.6.20 complete package over HTTPS; verifies the official SHA-256 checksum; verifies the Roundcube PGP signature and full signing-key fingerprint; creates a complete Roundcube filesystem backup; creates a MariaDB/MySQL database backup; executes the official Roundcube installto.sh; ensures that both installto.sh and its child php bin/... commands use: /usr/local/cwp/php71/bin/phpstops and restarts cwpsrv during the migration; verifies the resulting Roundcube version; checks PHP syntax; preserves the previous /scripts/update_roundcube file for reference. It does not modify the verified Roundcube source package with sed. Instead, it starts installto.sh explicitly with CWP PHP and provides a temporary php PATH shim for any child migration commands. Preventing CWP from restoring the old updaterThe script replaces: /scripts/update_roundcubewith a harmless wrapper that logs the attempted invocation and exits successfully with status 0. This avoids disrupting the normal CWP nightly process while preventing the obsolete updater from: reinstalling an old Roundcube release; downloading incompatible intl.so files; reinstalling unnecessary ICU packages; recreating the faulty intl.ini configuration. A systemd path unit monitors: /scripts/update_roundcube /usr/local/cwp/php71/php.d/intl.iniIf a later CWP update overwrites either file, the guard: restores the safe /scripts/update_roundcube wrapper; removes the redundant dynamic intl loading when intl is proven to be compiled into the PHP binary. A systemd timer also performs a fallback check every five minutes. The solution intentionally does not use: chattr +iAn immutable file could cause a CWP update to fail when it attempts to replace the file. UsageCopy the script to the server and make it executable: chmod 750 roundcube-cwp-1.5.15-to-1.6.20.shRun the read-only preflight first: ./roundcube-cwp-1.5.15-to-1.6.20.shThis performs checks without changing the server. If the preflight succeeds: ./roundcube-cwp-1.5.15-to-1.6.20.sh --applyIf Roundcube 1.6.20 is already installed, the expected message is: Roundcube 1.6.20 is already installed. Migration skipped; guards verified.VerificationCheck the systemd protection: systemctl is-active \ cwp-roundcube-guard.path \ cwp-roundcube-guard.timerExpected output: active activeVerify that the protected updater is identical to the safe copy: cmp \ /usr/local/libexec/cwp-roundcube-guard/update_roundcube.disabled \ /scripts/update_roundcube echo $?Expected exit status: 0Verify PHP and intl: /usr/local/cwp/php71/bin/php -v /usr/local/cwp/php71/bin/php -m \ | grep -i '^intl$'The PHP command should no longer emit an intl startup warning, and the module list should contain: intlCheck all relevant services: systemctl is-active \ cwpsrv \ cwp-roundcube-guard.path \ cwp-roundcube-guard.timerBackups and logsBackups of replaced legacy scripts: /root/roundcube-upgrade-backups/legacy-script-backups/Full filesystem and database backups: /root/roundcube-upgrade-backups/YYYYMMDD-HHMMSS/Migration log: /var/log/cwp-roundcube-1.6.20-upgrade.logGuard activity: journalctl \ -u cwp-roundcube-guard.service \ --since today \ --no-pagerFunctional tests after upgradingI recommend testing: direct login through webmail.example.com; CWP administrator e-mail auto-login; opening plain-text and HTML messages; sending a test message; sending and downloading an attachment; address-book access; logout and a new login. On the first upgraded production server, all of the following worked: Roundcube 1.5.15 โ 1.6.20 migration; direct webmail access; CWP administrator auto-login; database migration; PHP 7.4 compatibility; sending and receiving mail; removal of the recurring intl warning. A temporary proxy error appeared during the first auto-login attempt immediately after the update, but it disappeared after the services and session state settled. It was not a persistent compatibility problem. What if the server still has Roundcube 1.5.8?Roundcube 1.5.8 is older and should not remain exposed as a production webmail installation. The current fleet script intentionally refuses to modify unknown source versions. It accepts only: 1.5.15 1.6.20This is a safety measure. Do not simply remove the version check on a production server. For a server still running 1.5.8, use this process: Create a complete backup of: the Roundcube installation directory; the Roundcube database; config/config.inc.php; installed plugins and custom CWP integration files. Download the official Roundcube 1.5.15 complete release package. Verify its PGP signature before extracting it. Upgrade 1.5.8 to 1.5.15 with the official bin/installto.sh, ensuring that the CWP PHP binary is used: /usr/local/cwp/php71/bin/phpVerify: direct webmail login; CWP auto-login; IMAP access; SMTP sending; attachments; address book; logout and login. Run the fleet script in preflight mode: ./roundcube-cwp-1.5.15-to-1.6.20.shIf the preflight succeeds, perform the protected 1.5.15 โ 1.6.20 migration: ./roundcube-cwp-1.5.15-to-1.6.20.sh --applyThis two-stage approach is deliberately conservative. It provides a tested checkpoint at 1.5.15 and avoids turning an old, possibly customized CWP Roundcube installation into an unverified direct migration. Do not use an old updater that downloads PHP modules or RPM packages from unrelated repositories. Roundcube source updates and PHP-extension repairs should remain separate operations, and downloaded release artifacts should always be authenticated before installation. And here is the script, save as `roundcube-cwp-1.5.15-to-1.6.20.sh` Controlled CWP Roundcube migration: 1.5.15 -> 1.6.20 LTS #!/usr/bin/env bash set -Eeuo pipefail umask 077 # Controlled CWP Roundcube migration: 1.5.15 -> 1.6.20 LTS # # This script deliberately does not install PHP extensions, ICU packages, or # third-party binaries. Run without --apply for a read-only preflight. readonly SOURCE_VERSION="1.5.15" readonly TARGET_VERSION="1.6.20" readonly TARGET_SHA256="46919c70c85609b57038903c4ecc4e1d7fa4e14c535fe5b14192d778dcd4a1ee" readonly RELEASE_BASE="https://github.com/roundcube/roundcubemail/releases/download/${TARGET_VERSION}" readonly ARCHIVE_NAME="roundcubemail-${TARGET_VERSION}-complete.tar.gz" readonly SIGNATURE_NAME="${ARCHIVE_NAME}.asc" readonly RELEASE_URL="${RELEASE_BASE}/${ARCHIVE_NAME}" readonly SIGNATURE_URL="${RELEASE_BASE}/${SIGNATURE_NAME}" readonly PUBKEY_URL="https://roundcube.net/download/pubkey.asc" readonly EXPECTED_KEY_FINGERPRINT="F3E4C04BB3DB5D4215C45F7F5AB2BAA141C4F7D5" readonly TARGET_DIR="/usr/local/cwpsrv/var/services/roundcube" readonly PHP_BIN="/usr/local/cwp/php71/bin/php" readonly RESTART_SCRIPT="/scripts/restart_cwpsrv" readonly LOG_FILE="/var/log/cwp-roundcube-1.6.20-upgrade.log" readonly BACKUP_ROOT="/root/roundcube-upgrade-backups" readonly CONFIG_FILE="${TARGET_DIR}/config/config.inc.php" readonly VERSION_FILE="${TARGET_DIR}/program/include/iniset.php" readonly INTL_INI="/usr/local/cwp/php71/php.d/intl.ini" readonly LEGACY_UPDATE_SCRIPT="/scripts/update_roundcube" readonly GUARD_DIR="/usr/local/libexec/cwp-roundcube-guard" readonly GUARD_SCRIPT="/usr/local/sbin/cwp-roundcube-guard" readonly GUARD_SERVICE="/etc/systemd/system/cwp-roundcube-guard.service" readonly GUARD_PATH="/etc/systemd/system/cwp-roundcube-guard.path" readonly GUARD_TIMER="/etc/systemd/system/cwp-roundcube-guard.timer" APPLY=0 KEEP_WORKDIR=0 WORK_DIR="" BACKUP_DIR="" CWPSRV_WAS_ACTIVE=0 usage() { cat <<'EOF' Usage: roundcube-cwp-1.5.15-to-1.6.20.sh roundcube-cwp-1.5.15-to-1.6.20.sh --apply roundcube-cwp-1.5.15-to-1.6.20.sh --apply --keep-workdir Without --apply, only preflight checks are performed. EOF } log() { printf '%s %s\n' "$(date '+%Y-%m-%d %H:%M:%S%z')" "$*" | tee -a "$LOG_FILE" } die() { log "ERROR: $*" exit 1 } cleanup() { local exit_code=$? if (( CWPSRV_WAS_ACTIVE == 1 )) && ! systemctl is-active --quiet cwpsrv; then log "Starting cwpsrv after interrupted or failed migration." "$RESTART_SCRIPT" >>"$LOG_FILE" 2>&1 || true fi if [[ -n "$WORK_DIR" && -d "$WORK_DIR" && $KEEP_WORKDIR -eq 0 ]]; then rm -rf -- "$WORK_DIR" elif [[ -n "$WORK_DIR" && -d "$WORK_DIR" ]]; then log "Working directory retained: $WORK_DIR" fi exit "$exit_code" } install_cwp_guards() { local legacy_backup_dir legacy_backup_dir="${BACKUP_ROOT}/legacy-script-backups" mkdir -p "$GUARD_DIR" "$legacy_backup_dir" if [[ -f "$LEGACY_UPDATE_SCRIPT" ]] && \ ! grep -q 'Managed by cwp-roundcube-guard' "$LEGACY_UPDATE_SCRIPT"; then cp -a "$LEGACY_UPDATE_SCRIPT" \ "${legacy_backup_dir}/update_roundcube.$(date '+%Y%m%d-%H%M%S')" fi cat >"${GUARD_DIR}/update_roundcube.disabled" <<'EOF' #!/bin/sh # Managed by cwp-roundcube-guard. The legacy CWP updater is intentionally disabled. logger -t cwp-roundcube-guard \ "Blocked obsolete /scripts/update_roundcube invocation; managed Roundcube updater is required." exit 0 EOF chmod 0755 "${GUARD_DIR}/update_roundcube.disabled" cat >"$GUARD_SCRIPT" <<'EOF' #!/usr/bin/env bash set -Eeuo pipefail readonly PHP_BIN="/usr/local/cwp/php71/bin/php" readonly INTL_INI="/usr/local/cwp/php71/php.d/intl.ini" readonly LEGACY_SCRIPT="/scripts/update_roundcube" readonly SAFE_SCRIPT="/usr/local/libexec/cwp-roundcube-guard/update_roundcube.disabled" readonly LOG_TAG="cwp-roundcube-guard" changed=0 if [[ -f "$SAFE_SCRIPT" ]] && ! cmp --silent "$SAFE_SCRIPT" "$LEGACY_SCRIPT" 2>/dev/null; then install -o root -g root -m 0755 "$SAFE_SCRIPT" "$LEGACY_SCRIPT" logger -t "$LOG_TAG" "Restored the safe /scripts/update_roundcube wrapper." changed=1 fi if [[ -x "$PHP_BIN" ]] && \ "$PHP_BIN" -n -r 'exit(extension_loaded("intl") ? 0 : 1);'; then if [[ -f "$INTL_INI" ]] && \ grep -Eq '^[[:space:]]*extension[[:space:]]*=[[:space:]]*"?intl(\.so)?"?[[:space:]]*$' "$INTL_INI"; then printf '%s\n' \ '; Disabled automatically: intl is compiled into the CWP PHP binary.' \ >"$INTL_INI" chmod 0644 "$INTL_INI" logger -t "$LOG_TAG" "Disabled redundant dynamic intl loading." changed=1 fi fi exit 0 EOF chmod 0750 "$GUARD_SCRIPT" cat >"$GUARD_SERVICE" <<EOF [Unit] Description=Protect managed CWP Roundcube and PHP intl configuration After=local-fs.target [Service] Type=oneshot ExecStart=$GUARD_SCRIPT EOF cat >"$GUARD_PATH" <<EOF [Unit] Description=Watch CWP Roundcube updater and PHP intl configuration [Path] PathChanged=$LEGACY_UPDATE_SCRIPT PathChanged=$INTL_INI Unit=cwp-roundcube-guard.service [Install] WantedBy=multi-user.target EOF cat >"$GUARD_TIMER" <<'EOF' [Unit] Description=Periodic fallback check for CWP Roundcube guard [Timer] OnBootSec=2min OnUnitActiveSec=5min AccuracySec=30s Persistent=true Unit=cwp-roundcube-guard.service [Install] WantedBy=timers.target EOF systemctl daemon-reload systemctl enable --now cwp-roundcube-guard.path cwp-roundcube-guard.timer \ >>"$LOG_FILE" 2>&1 systemctl start cwp-roundcube-guard.service cmp --silent "${GUARD_DIR}/update_roundcube.disabled" "$LEGACY_UPDATE_SCRIPT" || \ die "Failed to replace the legacy Roundcube updater." systemctl is-active --quiet cwp-roundcube-guard.path || \ die "Roundcube guard path unit is not active." systemctl is-active --quiet cwp-roundcube-guard.timer || \ die "Roundcube guard timer is not active." log "Legacy Roundcube updater disabled; persistent CWP/intl guard installed." } trap cleanup EXIT trap 'die "Failure at line $LINENO."' ERR for argument in "$@"; do case "$argument" in --apply) APPLY=1 ;; --keep-workdir) KEEP_WORKDIR=1 ;; -h|--help) usage; exit 0 ;; *) usage; die "Unknown argument: $argument" ;; esac done [[ $EUID -eq 0 ]] || die "This script must be run as root." for command_name in base64 curl gpg gzip sha256sum tar awk grep sed stat systemctl; do command -v "$command_name" >/dev/null 2>&1 || die "Required command not found: $command_name" done [[ -x "$PHP_BIN" ]] || die "CWP PHP binary not found: $PHP_BIN" [[ -d "$TARGET_DIR" ]] || die "Roundcube directory not found: $TARGET_DIR" [[ -f "$CONFIG_FILE" ]] || die "Roundcube configuration not found: $CONFIG_FILE" [[ -f "$VERSION_FILE" ]] || die "Roundcube version file not found: $VERSION_FILE" [[ -x "$RESTART_SCRIPT" ]] || die "CWP restart script not found: $RESTART_SCRIPT" INSTALLED_VERSION="$({ grep "define('RCMAIL_VERSION'" "$VERSION_FILE" || true } | awk -F"'" 'NR == 1 {print $4}')" if [[ "$INSTALLED_VERSION" != "$SOURCE_VERSION" && \ "$INSTALLED_VERSION" != "$TARGET_VERSION" ]]; then die "Expected Roundcube ${SOURCE_VERSION} or ${TARGET_VERSION}, found '${INSTALLED_VERSION:-unknown}'." fi PHP_VERSION="$($PHP_BIN -n -r 'echo PHP_VERSION;')" PHP_VERSION_ID="$($PHP_BIN -n -r 'echo PHP_VERSION_ID;')" (( PHP_VERSION_ID >= 70300 )) || die "Roundcube 1.6 requires PHP 7.3 or newer; found $PHP_VERSION." if "$PHP_BIN" -n -r 'exit(extension_loaded("intl") ? 0 : 1);'; then INTL_MODE="compiled-in" else INTL_MODE="configured extension" fi for extension_name in dom fileinfo intl json mbstring openssl pcre pdo session sockets; do "$PHP_BIN" -r 'exit(extension_loaded($argv[1]) ? 0 : 1);' "$extension_name" 2>/dev/null || \ die "Required PHP extension is not loaded: $extension_name" done log "Preflight: Roundcube $INSTALLED_VERSION, PHP $PHP_VERSION, intl mode: $INTL_MODE." if [[ "$INTL_MODE" == "compiled-in" && -f "$INTL_INI" ]] && \ grep -Eq '^[[:space:]]*extension[[:space:]]*=[[:space:]]*"?intl(\.so)?"?[[:space:]]*$' "$INTL_INI"; then if (( APPLY == 1 )); then cp -a "$INTL_INI" "${INTL_INI}.before-roundcube-1.6.20" printf '%s\n' '; Disabled: intl is compiled into the CWP PHP binary.' >"$INTL_INI" log "Disabled redundant dynamic intl loading." else log "Preflight warning: $INTL_INI contains redundant dynamic intl loading." fi fi if (( APPLY == 0 )); then if [[ "$INSTALLED_VERSION" == "$TARGET_VERSION" ]]; then log "Roundcube ${TARGET_VERSION} is already installed; migration would be skipped." fi log "Preflight completed. No changes were made. Re-run with --apply to install guards and migrate if needed." exit 0 fi mkdir -p "$BACKUP_ROOT" install_cwp_guards if [[ "$INSTALLED_VERSION" == "$TARGET_VERSION" ]]; then log "Roundcube ${TARGET_VERSION} is already installed. Migration skipped; guards verified." exit 0 fi WORK_DIR="$(mktemp -d /usr/local/src/roundcube-1.6.20-upgrade.XXXXXX)" readonly WORK_DIR BACKUP_DIR="${BACKUP_ROOT}/$(date '+%Y%m%d-%H%M%S')" readonly BACKUP_DIR mkdir -p "$BACKUP_DIR" log "Downloading the official Roundcube ${TARGET_VERSION} complete package." curl --fail --silent --show-error --location --proto '=https' --tlsv1.2 \ "$RELEASE_URL" --output "${WORK_DIR}/${ARCHIVE_NAME}" curl --fail --silent --show-error --location --proto '=https' --tlsv1.2 \ "$SIGNATURE_URL" --output "${WORK_DIR}/${SIGNATURE_NAME}" curl --fail --silent --show-error --location --proto '=https' --tlsv1.2 \ "$PUBKEY_URL" --output "${WORK_DIR}/roundcube-pubkey.asc" printf '%s %s\n' "$TARGET_SHA256" "${WORK_DIR}/${ARCHIVE_NAME}" | sha256sum --check --status || \ die "SHA-256 verification failed." GNUPGHOME="${WORK_DIR}/gnupg" export GNUPGHOME mkdir -m 700 "$GNUPGHOME" ACTUAL_FINGERPRINT="$( gpg --batch --quiet --with-colons --import-options show-only --import \ "${WORK_DIR}/roundcube-pubkey.asc" 2>/dev/null | awk -F: '$1 == "fpr" {print $10; exit}' )" [[ "$ACTUAL_FINGERPRINT" == "$EXPECTED_KEY_FINGERPRINT" ]] || \ die "Unexpected Roundcube signing-key fingerprint: $ACTUAL_FINGERPRINT" gpg --batch --quiet --import "${WORK_DIR}/roundcube-pubkey.asc" >>"$LOG_FILE" 2>&1 gpg --batch --verify "${WORK_DIR}/${SIGNATURE_NAME}" \ "${WORK_DIR}/${ARCHIVE_NAME}" >>"$LOG_FILE" 2>&1 || die "PGP signature verification failed." log "Release checksum and PGP signature verified." log "Creating filesystem backup: $BACKUP_DIR" tar --xattrs --acls --selinux -czpf "${BACKUP_DIR}/roundcube-files.tar.gz" \ -C "$(dirname "$TARGET_DIR")" "$(basename "$TARGET_DIR")" cp -a "$0" "${BACKUP_DIR}/migration-script.sh" cp -a "$CONFIG_FILE" "${BACKUP_DIR}/config.inc.php" # Try to create a database backup without printing credentials. Roundcube DSNs # normally use mysql:// or mysqli://. Unsupported/custom DSNs abort the upgrade. DB_ENV_FILE="${WORK_DIR}/read-db-config.php" cat >"$DB_ENV_FILE" <<'PHP' <?php $config = []; require $argv[1]; $dsn = $config['db_dsnw'] ?? ''; $parts = parse_url($dsn); if (!is_array($parts) || !isset($parts['scheme'], $parts['host'], $parts['user'], $parts['path'])) { exit(2); } $scheme = strtolower($parts['scheme']); if (!in_array($scheme, ['mysql', 'mysqli'], true)) { exit(3); } $values = [ rawurldecode($parts['host']), (string) ($parts['port'] ?? 3306), rawurldecode($parts['user']), rawurldecode((string) ($parts['pass'] ?? '')), rawurldecode(ltrim($parts['path'], '/')), ]; foreach ($values as $value) { echo base64_encode($value), "\n"; } PHP mapfile -t DB_FIELDS < <("$PHP_BIN" -n "$DB_ENV_FILE" "$CONFIG_FILE") || \ die "Could not parse a supported MySQL/MariaDB db_dsnw from Roundcube configuration." [[ ${#DB_FIELDS[@]} -eq 5 ]] || die "Incomplete Roundcube database configuration." decode_field() { printf '%s' "$1" | base64 --decode; } DB_HOST="$(decode_field "${DB_FIELDS[0]}")" DB_PORT="$(decode_field "${DB_FIELDS[1]}")" DB_USER="$(decode_field "${DB_FIELDS[2]}")" DB_PASS="$(decode_field "${DB_FIELDS[3]}")" DB_NAME="$(decode_field "${DB_FIELDS[4]}")" DUMP_BIN="$(command -v mariadb-dump || command -v mysqldump || true)" [[ -n "$DUMP_BIN" ]] || die "Neither mariadb-dump nor mysqldump is installed." DB_DEFAULTS="${WORK_DIR}/db-client.cnf" { printf '%s\n' '[client]' printf 'host=%s\n' "$DB_HOST" printf 'port=%s\n' "$DB_PORT" printf 'user=%s\n' "$DB_USER" printf 'password=%s\n' "$DB_PASS" } >"$DB_DEFAULTS" chmod 600 "$DB_DEFAULTS" "$DUMP_BIN" --defaults-extra-file="$DB_DEFAULTS" --single-transaction \ --skip-lock-tables --hex-blob --databases "$DB_NAME" | gzip -9 >"${BACKUP_DIR}/roundcube-database.sql.gz" [[ -s "${BACKUP_DIR}/roundcube-database.sql.gz" ]] || die "Database backup is empty." unset DB_PASS DB_FIELDS rm -f "$DB_DEFAULTS" log "Filesystem and database backups completed." mkdir -p "${WORK_DIR}/source" tar -xzf "${WORK_DIR}/${ARCHIVE_NAME}" -C "${WORK_DIR}/source" --strip-components=1 [[ -f "${WORK_DIR}/source/bin/installto.sh" ]] || die "installto.sh missing from verified archive." # installto.sh is started explicitly with CWP PHP below. It can also invoke # child commands in the form `php bin/...`; provide a temporary PATH shim so # those processes use the same CWP PHP binary without modifying signed source. mkdir -p "${WORK_DIR}/cwp-php-bin" ln -s "$PHP_BIN" "${WORK_DIR}/cwp-php-bin/php" if systemctl is-active --quiet cwpsrv; then CWPSRV_WAS_ACTIVE=1 log "Stopping cwpsrv for the migration." systemctl stop cwpsrv fi log "Migrating Roundcube files and database." PATH="${WORK_DIR}/cwp-php-bin:${PATH}" \ "$PHP_BIN" "${WORK_DIR}/source/bin/installto.sh" -y "$TARGET_DIR" \ >>"$LOG_FILE" 2>&1 NEW_VERSION="$({ grep "define('RCMAIL_VERSION'" "$VERSION_FILE" || true } | awk -F"'" 'NR == 1 {print $4}')" [[ "$NEW_VERSION" == "$TARGET_VERSION" ]] || die "Migration finished with unexpected version: $NEW_VERSION" "$PHP_BIN" -l "$TARGET_DIR/index.php" >>"$LOG_FILE" 2>&1 "$PHP_BIN" -l "$CONFIG_FILE" >>"$LOG_FILE" 2>&1 log "Restarting cwpsrv." "$RESTART_SCRIPT" >>"$LOG_FILE" 2>&1 systemctl is-active --quiet cwpsrv || die "cwpsrv did not become active." CWPSRV_WAS_ACTIVE=0 log "Roundcube ${SOURCE_VERSION} -> ${TARGET_VERSION} migration completed." log "Backup directory: $BACKUP_DIR" log "Verify webmail login, message display, sending, attachments, address book, and enabled plugins."
-
Fixing False Positive CWP Security Audit Alerts on AlmaLinux 9.x
Add a line to the ALLOWED_LIB_PATHS block! ALLOWED_LIB_PATHS=( "/usr/lib64/lib" "/usr/lib64/ld-" "/usr/local/ioncube/" "/usr/lib/locale/" "/usr/local/cwp/" "/usr/local/apache/modules/" "/usr/local/lib/" "/usr/lib64/gconv/" "/opt/php-build-deps/" )
-
Critical Vulnerability in CSF MESSENGER (CVE-2026-67402) - 03/September/2026
In this case, I suggest you open a ticket on GitHub about this.
-
Critical Vulnerability in CSF MESSENGER (CVE-2026-67402) - 03/September/2026
I am using the fork: https://github.com/aetherinox/csf-firewall It is fully compatible with CWP Pro, and the latest version is 15.10
-
-
Fixing False Positive CWP Security Audit Alerts on AlmaLinux 9.x
@SubZero5 I did not use the folder `/opt/php-build-deps/lib64/` in my severs, so you should check in your builds what is it.
-
Long-awaited CWP PHP 8.4 & 8.5 โ Finally on Test!
@Sandeep B. Hi Sandeep, CWP now officially supports compiling PHP 8.4 and 8.5, but the default PHP-FPM builds are still being linked against CWPโs legacy OpenSSL 1.1.1t: /opt/alt/php-fpm85/usr/bin/php --ri openssl openssl OpenSSL support => enabled OpenSSL Library Version => OpenSSL 1.1.1t 7 Feb 2023 OpenSSL Header Version => OpenSSL 1.1.1t 7 Feb 2023 Openssl default config => /usr/local/opensslso/openssl.cnf Directive => Local Value => Master Value openssl.cafile => no value => no value openssl.capath => no value => no value openssl.libctx => custom => custom This means that even newly compiled PHP 8.5 installations use the obsolete /usr/local/opensslso build instead of the current system OpenSSL provided by AlmaLinux 9. After correcting the compiler environment and linking PHP against the AlmaLinux 9 system libraries, the expected result is: /opt/alt/php-fpm85/usr/bin/php --ri openssl openssl OpenSSL support => enabled OpenSSL Library Version => OpenSSL 3.5.5 27 Jan 2026 OpenSSL Header Version => OpenSSL 3.5.5 27 Jan 2026 Openssl default config => /etc/pki/tls/openssl.cnf Directive => Local Value => Master Value openssl.cafile => no value => no value openssl.capath => no value => no value openssl.libctx => custom => custom This confirms that PHP 8.5 can be compiled correctly on AlmaLinux 9 against the current system OpenSSL. It also uses the correct system configuration file: /etc/pki/tls/openssl.cnf instead of: /usr/local/opensslso/openssl.cnf I previously supplied the required include and library configuration, but it appears that it was not incorporated into the official compiler setup. Could you please treat this as a priority and update the PHP-FPM 8.4/8.5 compiler so that it: uses the AlmaLinux 9 system OpenSSL headers and libraries; does not inject /usr/local/opensslso into the build environment; does not link new PHP binaries against OpenSSL 1.1.1; uses /etc/pki/tls/openssl.cnf as the default OpenSSL configuration; verifies the completed build with: /opt/alt/php-fpm85/usr/bin/php --ri openssl ldd /opt/alt/php-fpm85/usr/bin/php | grep -E 'ssl|crypto' Official PHP 8.4/8.5 support should not produce newly compiled binaries linked against an obsolete OpenSSL branch. Updating PHP alone does not provide a modern and maintainable runtime while its TLS and cryptographic functionality remains tied to OpenSSL 1.1.1t. Please review the include and library settings I sent earlier and integrate them into the official CWP compiler instead of requiring administrators to patch every generated build manually.
-
Long-awaited CWP PHP 8.4 & 8.5 โ Finally on Test!
@Sandeep B. Hi Sandeep, There is a related issue that needs to be addressed in the official PHP 8.4/8.5 compiler implementation. Every CWP update restores the old external_modules and pre_run scripts. These scripts contain legacy assumptions and configure options that are no longer compatible with PHP 8.4 and 8.5. As a result, locally corrected compiler configurations are repeatedly overwritten by the updater. IMAP is a clear example. You previously wrote: However, IMAP remains selectable in the CWP PHP-FPM configuration interface. Selecting it causes the old IMAP, Kerberos and IMAP-SSL handling to be injected into the build, even though these options are no longer supported by bundled PHP 8.4/8.5. This makes the interface a trap for administrators: CWP offers an option that its own compiler cannot validly process. The same legacy configuration problem affects options such as: --with-imap --with-imap-ssl --with-kerberos --with-pspell --with-zlib-dir --enable-opcache Please update the complete PHP 8.4/8.5 compiler chain, not only the visible version list: Remove unsupported bundled-extension options from the PHP 8.4/8.5 interface. Make the available options version-aware. Update the official external_modules and pre_run scripts. Stop CWP updates from restoring legacy PHP 8.4/8.5 compiler definitions. Remove the forced /usr/local/opensslso OpenSSL 1.1.1 integration and use the AlmaLinux 9 system OpenSSL. If IMAP or Pspell support is planned through PECL, expose it explicitly as a PECL extension rather than retaining obsolete PHP configure options. Test a clean PHP 8.4 and 8.5 compilation after a normal CWP update, without any administrator-applied patches. At present, CWP advertises official PHP 8.4/8.5 compilation support, but the surrounding compiler configuration still belongs to older PHP releases. An administrator who simply selects the options offered by the interface can generate a failed, obsolete or incorrectly linked build. I have already provided working corrections, but maintaining local patches is not a sustainable solution when every CWP update reinstalls the broken legacy scripts. These fixes need to be incorporated into the official update packages.
-
Long-awaited CWP PHP 8.4 & 8.5 โ Finally on Test!
Hello @oblique Yes, this appears to be an outdated CWP PHP configuration rather than a missing PHP 8.5 feature. PHP still requires the system zlib development library: dnf install -y zlib-develHowever, the legacy PHP configure option: --with-zlib-dir=...must be removed. It has not been supported since PHP 7.4. Modern PHP discovers zlib through pkg-config. Check the generated CWP configuration, usually the relevant php85.conf, and remove --with-zlib-dir. If the CWP editor itself refuses to save because the zlib block contains: include=zlib-dirthen that dependency reference is also stale and should be removed from the CWP editor definition. Keep zlib enabled and keep zlib-devel installed; only remove the obsolete zlib-dir configure option/dependency.
-
Long-awaited CWP PHP 8.4 & 8.5 โ Finally on Test!
@Sandeep B. Hello, This is a PHP 5.6 FPM script for El9 AlmaLinux 9 environment: #!/bin/bash # Usage: bash /root/build-php-fpm56-el9.sh 2>&1 | tee /root/php56-build.log # External modules: # /usr/local/cwpsrv/htdocs/resources/conf/el9/php-fpm_selector/external_modules/5.6 set -euo pipefail set -x # --- Basic variables --- PHPMAJOR="56" # php-fpm56 PHPVER="5.6.40" # PHP version FPMDIR="/opt/alt/php-fpm${PHPMAJOR}" CONFBASE="/usr/local/cwp/.conf/php-fpm_conf" SELECTOR_BASE="/usr/local/cwpsrv/htdocs/resources/conf/el9/php-fpm_selector" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" LOCAL_CONFBASE="${SCRIPT_DIR}/conf" PRE_RUN_BASE="${SELECTOR_BASE}/pre_run/5.6" EXT_BASE="${SELECTOR_BASE}/external_modules/5.6" OPENSSL_HACK_DIR="/usr/local/ssls" CURL_HACK_DIR="/usr/local/curls" IMAP_HACK_DIR="/usr/local/imap-2007f" arch=$(uname -m) if [[ "$arch" == "x86_64" ]]; then platform="x86-64" libdir="/usr/lib64" else platform="x86" libdir="/usr/lib" fi run_if_exists() { local script="$1" if [ -f "$script" ]; then bash "$script" || true fi } resolve_conf_file() { local name="$1" local primary="${CONFBASE}/${name}" local fallback="${LOCAL_CONFBASE}/${name}" if [ -f "$primary" ]; then echo "$primary" return 0 fi if [ -f "$fallback" ]; then echo "$fallback" return 0 fi return 1 } ensure_executable_config() { local config_file="$1" if [ -e "$config_file" ] && [ ! -x "$config_file" ]; then chmod +x "$config_file" 2>/dev/null || true fi } prepare_config_file() { local config_file="$1" local normalized_file="$2" cp "$config_file" "$normalized_file" # The generated 5.6 selector config can contain a malformed IMAP option # string. Normalize it before invoking configure so bash passes both flags # as separate arguments. sed -i \ -e "s|--with-imap=/usr/local/imap-2007f' '--with-imap-ssl=/usr/local/ssls|--with-imap=/usr/local/imap-2007f --with-imap-ssl=/usr/local/ssls|g" \ -e 's/ --enable-intl//g' \ -e 's/ --with-icu-dir=\/usr//g' \ "$normalized_file" chmod +x "$normalized_file" 2>/dev/null || true } ensure_imap_hack_layout() { mkdir -p "${IMAP_HACK_DIR}/include" "${IMAP_HACK_DIR}/lib" "${IMAP_HACK_DIR}/lib64" "${IMAP_HACK_DIR}/c-client" if [ -d "/usr/include/imap" ] && [ ! -e "${IMAP_HACK_DIR}/include/imap" ]; then ln -sfn /usr/include/imap "${IMAP_HACK_DIR}/include/imap" fi if [ -e "/usr/lib64/libc-client.so" ]; then ln -sfn /usr/lib64/libc-client.so "${IMAP_HACK_DIR}/lib64/libc-client.so" fi if [ -e "/usr/lib64/libc-client.a" ]; then ln -sfn /usr/lib64/libc-client.a "${IMAP_HACK_DIR}/lib64/libc-client.a" fi if [ -e "/usr/lib/libc-client.so" ]; then ln -sfn /usr/lib/libc-client.so "${IMAP_HACK_DIR}/lib/libc-client.so" fi if [ -e "/usr/lib/libc-client.a" ]; then ln -sfn /usr/lib/libc-client.a "${IMAP_HACK_DIR}/lib/libc-client.a" fi } CONFIG_FILE_TEMPLATE="" ENABLE_IMAP=0 # --- Packages for Build (EL9) --- dnf -y install \ autoconf automake bison gcc gcc-c++ make pkgconf-pkg-config re2c \ krb5-devel glibc-common gnutls-devel \ libxml2-devel libxslt-devel libicu-devel \ libjpeg-turbo-devel freetype-devel libpng-devel libXpm-devel \ libzip libzip-devel \ libbsd-devel \ libtidy-devel aspell aspell-devel \ perl \ uw-imap-devel \ openldap-devel \ bzip2-devel gettext-devel gmp-devel \ openssl-devel # PHP 5.6 on EL9 must use the old CWP OpenSSL 1.x hack. if [ -d /usr/local/opensslso ]; then echo "WARN: /usr/local/opensslso exists, but PHP 5.6.40 must be built against /usr/local/ssls." fi # --- Prepare old CWP 1.x dependencies --- run_if_exists "${PRE_RUN_BASE}/dep.sh" run_if_exists "${PRE_RUN_BASE}/ldap.sh" run_if_exists "${PRE_RUN_BASE}/firebird.sh" if ! CONFIG_FILE_TEMPLATE="$(resolve_conf_file "php${PHPMAJOR}.conf")"; then echo "ERROR: php${PHPMAJOR}.conf not found in ${CONFBASE} or ${LOCAL_CONFBASE}" exit 1 fi if grep -q -- '--with-imap' "${CONFIG_FILE_TEMPLATE}"; then ENABLE_IMAP=1 run_if_exists "${PRE_RUN_BASE}/imap.sh" fi if [ ! -d "${OPENSSL_HACK_DIR}" ]; then echo "ERROR: ${OPENSSL_HACK_DIR} is missing. Run the selector pre-run dependency step first." exit 1 fi if [ ! -d "${CURL_HACK_DIR}" ]; then echo "ERROR: ${CURL_HACK_DIR} is missing. Run the selector pre-run dependency step first." exit 1 fi export PKG_CONFIG_PATH="${OPENSSL_HACK_DIR}/lib/pkgconfig:${OPENSSL_HACK_DIR}/lib64/pkgconfig:${CURL_HACK_DIR}/lib/pkgconfig:${CURL_HACK_DIR}/lib64/pkgconfig:/usr/lib64/pkgconfig" export CPPFLAGS="-I${OPENSSL_HACK_DIR}/include -I${CURL_HACK_DIR}/include" export CFLAGS="${CFLAGS:-} -fcommon" export LDFLAGS="-L${OPENSSL_HACK_DIR}/lib -L${OPENSSL_HACK_DIR}/lib64 -L${CURL_HACK_DIR}/lib -L${CURL_HACK_DIR}/lib64" export LIBRARY_PATH="${OPENSSL_HACK_DIR}/lib:${OPENSSL_HACK_DIR}/lib64:${CURL_HACK_DIR}/lib:${CURL_HACK_DIR}/lib64" export LD_LIBRARY_PATH="${OPENSSL_HACK_DIR}/lib:${OPENSSL_HACK_DIR}/lib64:${CURL_HACK_DIR}/lib:${CURL_HACK_DIR}/lib64:${LD_LIBRARY_PATH:-}" export OPENSSL_CFLAGS="-I${OPENSSL_HACK_DIR}/include" export OPENSSL_LIBS="-L${OPENSSL_HACK_DIR}/lib -L${OPENSSL_HACK_DIR}/lib64 -lssl -lcrypto" if [ "${ENABLE_IMAP}" -eq 1 ]; then ensure_imap_hack_layout export CPPFLAGS="${CPPFLAGS} -I${IMAP_HACK_DIR}/include -I${IMAP_HACK_DIR}/include/imap -I${IMAP_HACK_DIR}/c-client" export LDFLAGS="${LDFLAGS} -L${IMAP_HACK_DIR}/lib -L${IMAP_HACK_DIR}/lib64 -L${IMAP_HACK_DIR}/c-client" export LIBRARY_PATH="${LIBRARY_PATH}:${IMAP_HACK_DIR}/lib:${IMAP_HACK_DIR}/lib64:${IMAP_HACK_DIR}/c-client" export LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${IMAP_HACK_DIR}/lib:${IMAP_HACK_DIR}/lib64:${IMAP_HACK_DIR}/c-client" fi echo "INFO: PHP 5.6 intl is disabled on EL9 because ICU 67+ is not compatible with ext/intl from PHP 5.6." # --- PHP source download: direct official php.net tarball --- PHPSOURCE="https://www.php.net/distributions/php-${PHPVER}.tar.gz" echo "Using source: $PHPSOURCE" # --- Build directory --- rm -rf /usr/local/src/php-build mkdir -p /usr/local/src/php-build cd /usr/local/src/php-build wget -q "${PHPSOURCE}" -O "php-${PHPVER}.tar.gz" if ! file "php-${PHPVER}.tar.gz" | grep -qiE "gzip compressed data|tar archive"; then echo "ERROR: Downloaded PHP source is not a valid tarball: ${PHPSOURCE}" exit 1 fi tar -xzf "php-${PHPVER}.tar.gz" cd "php-${PHPVER}" # --- Configure PHP 5.6.40 for EL9 + old CWP OpenSSL 1.x hack --- CONFIG_FILE="${CONFIG_FILE_TEMPLATE}" ensure_executable_config "$CONFIG_FILE" NORMALIZED_CONFIG_FILE="$(mktemp "/tmp/php${PHPMAJOR}.conf.XXXXXX")" prepare_config_file "$CONFIG_FILE" "$NORMALIZED_CONFIG_FILE" bash "$NORMALIZED_CONFIG_FILE" rm -f "$NORMALIZED_CONFIG_FILE" # --- Compiling --- if command -v nproc >/dev/null 2>&1; then make -j"$(nproc)" else make fi make install # --- PHP.ini + FPM scaffolding --- mkdir -p "${FPMDIR}/usr/php/php.d" mkdir -p "${FPMDIR}/usr/var/sockets" mkdir -p "${FPMDIR}/usr/etc/php-fpm.d" mkdir -p "${FPMDIR}/usr/etc/php-fpm.d/users" rsync php.ini-production "${FPMDIR}/usr/php/php.ini" sed -i 's/^short_open_tag.*/short_open_tag = On/' "${FPMDIR}/usr/php/php.ini" sed -i 's/^;cgi.fix_pathinfo=.*/cgi.fix_pathinfo=1/' "${FPMDIR}/usr/php/php.ini" sed -i 's/.*mail.add_x_header.*/mail.add_x_header = On/' "${FPMDIR}/usr/php/php.ini" sed -i 's@.*mail.log.*@mail.log = /usr/local/apache/logs/phpmail.log@' "${FPMDIR}/usr/php/php.ini" echo "include=${FPMDIR}/usr/etc/php-fpm.d/users/*.conf" > "${FPMDIR}/usr/etc/php-fpm.d/users.conf" echo "include=${FPMDIR}/usr/etc/php-fpm.d/*.conf" > "${FPMDIR}/usr/etc/php-fpm.conf" cat > "${FPMDIR}/usr/etc/php-fpm.d/cwpsvc.conf" <<EOF [cwpsvc] listen = ${FPMDIR}/usr/var/sockets/cwpsvc.sock listen.owner = cwpsvc listen.group = cwpsvc listen.mode = 0640 user = cwpsvc group = cwpsvc pm = ondemand pm.max_children = 25 pm.process_idle_timeout = 15s request_terminate_timeout = 0 EOF # --- Systemd service --- cp sapi/fpm/php-fpm.service "/usr/lib/systemd/system/php-fpm${PHPMAJOR}.service" sed -i "s|\${exec_prefix}|${FPMDIR}/usr|g" "/usr/lib/systemd/system/php-fpm${PHPMAJOR}.service" sed -i "s|\${prefix}|${FPMDIR}/usr|g" "/usr/lib/systemd/system/php-fpm${PHPMAJOR}.service" systemctl daemon-reload systemctl enable "php-fpm${PHPMAJOR}" # --- Loading Apache FPM module if not already present --- if [ ! -e "/usr/local/apache/conf.d/php-fpm.conf" ]; then cat > /usr/local/apache/conf.d/php-fpm.conf <<EOF <IfModule !proxy_fcgi_module> LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so </IfModule> EOF fi # --- External modules (imagick, redis, imap, etc.) --- if EXTERNAL_FILE="$(resolve_conf_file "php${PHPMAJOR}_external.conf")"; then ensure_executable_config "$EXTERNAL_FILE" bash "$EXTERNAL_FILE" || true else for module in \ imagick.sh \ ioncube.sh \ mailparse.sh \ memcache.sh \ mongodb.sh \ opcache.sh \ redis.sh \ sourceguardian.sh \ ssh2.sh \ xcache.sh \ yaz.sh \ zendgl.sh do run_if_exists "${EXT_BASE}/${module}" done fi # --- CSF pignore --- if [ -e "/etc/csf/csf.pignore" ]; then if ! grep -q "${FPMDIR}/usr/sbin/php-fpm" /etc/csf/csf.pignore; then echo "exe:${FPMDIR}/usr/sbin/php-fpm" >> /etc/csf/csf.pignore fi if ! grep -q "${FPMDIR}/usr/bin/php" /etc/csf/csf.pignore; then echo "exe:${FPMDIR}/usr/bin/php" >> /etc/csf/csf.pignore fi if command -v memcached >/dev/null 2>&1; then if ! grep -q "exe:/usr/bin/memcached" /etc/csf/csf.pignore; then echo "exe:/usr/bin/memcached" >> /etc/csf/csf.pignore fi fi if command -v redis-server >/dev/null 2>&1; then if ! grep -q "exe:/usr/bin/redis-server" /etc/csf/csf.pignore; then echo "exe:/usr/bin/redis-server" >> /etc/csf/csf.pignore fi fi csf -r || true fi # --- Monitor integration --- if [ -d "/etc/monit.d" ]; then if [ ! -e "/etc/monit.d/php-fpm${PHPMAJOR}" ]; then if [ -e "/usr/local/cwpsrv/htdocs/resources/conf/monit.d/php-fpm${PHPMAJOR}" ]; then cp "/usr/local/cwpsrv/htdocs/resources/conf/monit.d/php-fpm${PHPMAJOR}" /etc/monit.d/ 2>/dev/null || true monit reload || true fi fi fi rm -rf /usr/local/src/php-build rm -rf /usr/local/src/build-dir systemctl restart "php-fpm${PHPMAJOR}" echo "PHP ${PHPVER} (php-fpm${PHPMAJOR}) build finished successfully." Sometimes it is necessary for a legacy system to be able to operate temporarily even under AlmaLinux 9.
-
Long-awaited CWP PHP 8.4 & 8.5 โ Finally on Test!
@Sandeep B. Hello, here is the latest working EL9 script for PHP 8.5 FPM for AlmaLinux 9.x #!/bin/bash # Usage: bash /root/build-php-fpm85-el9.sh 2>&1 | tee /root/php85-build.log # External modules: # /usr/local/cwpsrv/htdocs/resources/conf/el9/php-fpm_selector/external_modules/8.5 set -euo pipefail set -x # --- Basic variables --- PHPMAJOR="85" # php-fpm85 PHPVER="8.5.9" # PHP version FPMDIR="/opt/alt/php-fpm${PHPMAJOR}" CONFBASE="/usr/local/cwp/.conf/php-fpm_conf" arch=$(uname -m) if [[ "$arch" == "x86_64" ]]; then platform="x86-64" libdir="/usr/lib64" else platform="x86" libdir="/usr/lib" fi # --- Packages for Build (EL9) --- dnf -y install \ krb5-devel glibc-common gnutls-devel \ libargon2 libargon2-devel libbsd-devel \ perl libzip libzip-devel pcre2 pcre2-devel \ libavif libavif-devel \ uw-imap-devel \ openssl-devel # If there is any old CWP OpenSSL hack left, don't use it.: if [ -d /usr/local/opensslso ]; then echo "WARN: /usr/local/opensslso exists, but we DO NOT USE for compiling PHP (OpenSSL 1.1 hack)." fi # --- Force OpenSSL 3.x --- export PKG_CONFIG_PATH=/usr/lib64/pkgconfig export OPENSSL_CFLAGS="-I/usr/include" export OPENSSL_LIBS="-L/usr/lib64" export LDFLAGS="-lssl -lcrypto" # --- CWP pre-conf, if exists (e.g.: pcre2, & other libs) --- if [ -e "${CONFBASE}/php${PHPMAJOR}_pre.conf" ]; then bash "${CONFBASE}/php${PHPMAJOR}_pre.conf" fi # --- PHP SOURCE DOWNLOAD CHECK: CWP CDN โ OFFICIAL php.net โ GitHub fallback --- CWP_URL="http://static.cdn-cwp.com/files/php/php-${PHPVER}.tar.gz" PHPNET_URL="https://www.php.net/distributions/php-${PHPVER}.tar.gz" GITHUB_URL="https://codeload.github.com/php/php-src/tar.gz/refs/tags/php-${PHPVER}" # Function: check HTTP 200 + verify tar.gz content check_and_verify() { local url="$1" local testfile="/tmp/php-test-${PHPVER}.tar.gz" echo "Checking: $url" # First check HTTP status code if ! curl -I -L -s "$url" | grep -q "200"; then echo " โ HTTP check failed" return 1 fi # Download temporary test file if ! wget -q "$url" -O "$testfile"; then echo " โ Download failed" return 1 fi # Validate MIME type of tar.gz if file "$testfile" | grep -qiE "gzip compressed data|tar archive"; then rm -f "$testfile" echo " โ Valid TAR.GZ" return 0 fi echo " โ Invalid TAR.GZ (HTML or wrong file)" rm -f "$testfile" return 1 } # Check sources in order (CWP โ php.net โ GitHub) if check_and_verify "$CWP_URL"; then PHPSOURCE="$CWP_URL" elif check_and_verify "$PHPNET_URL"; then PHPSOURCE="$PHPNET_URL" elif check_and_verify "$GITHUB_URL"; then PHPSOURCE="$GITHUB_URL" else echo "ERROR: Could not download a valid PHP source for version ${PHPVER}" exit 1 fi echo "Using source: $PHPSOURCE" # --- Build directory --- rm -rf /usr/local/src/php-build mkdir -p /usr/local/src/php-build cd /usr/local/src/php-build wget -q "${PHPSOURCE}" -O "php-${PHPVER}.tar.gz" tar -xzf "php-${PHPVER}.tar.gz" cd "php-${PHPVER}" # --- Configure: CWP's own php85.conf, but already wired to OpenSSL 3.x from env --- if [ ! -x "${CONFBASE}/php${PHPMAJOR}.conf" ]; then chmod +x "${CONFBASE}/php${PHPMAJOR}.conf" 2>/dev/null || true fi # PHP 8.5 no longer accepts several legacy configure flags that CWP may keep # in an already generated php85.conf. sed -i -E \ -e '/^[[:space:]]*--with-pspell(=[^[:space:]]*)?[[:space:]]*\\?[[:space:]]*$/d' \ -e '/^[[:space:]]*--with-zlib-dir=[^[:space:]]*[[:space:]]*\\?[[:space:]]*$/d' \ -e '/^[[:space:]]*--with-kerberos(=[^[:space:]]*)?[[:space:]]*\\?[[:space:]]*$/d' \ -e '/^[[:space:]]*--with-imap-ssl(=[^[:space:]]*)?[[:space:]]*\\?[[:space:]]*$/d' \ -e '/^[[:space:]]*--with-imap(=[^[:space:]]*)?[[:space:]]*\\?[[:space:]]*$/d' \ -e '/^[[:space:]]*--enable-opcache[[:space:]]*\\?[[:space:]]*$/d' \ -e 's/[[:space:]]--with-pspell(=[^[:space:]]*)?//g' \ -e 's/[[:space:]]--with-zlib-dir=[^[:space:]]*//g' \ -e 's/[[:space:]]--with-kerberos(=[^[:space:]]*)?//g' \ -e 's/[[:space:]]--with-imap-ssl(=[^[:space:]]*)?//g' \ -e 's/[[:space:]]--with-imap(=[^[:space:]]*)?//g' \ -e 's/[[:space:]]--enable-opcache//g' \ "${CONFBASE}/php${PHPMAJOR}.conf" # IMPORTANT: LDFLAGS + PKG_CONFIG_PATH already exported bash "${CONFBASE}/php${PHPMAJOR}.conf" # --- Compiling --- if command -v nproc >/dev/null 2>&1; then make -j"$(nproc)" else make fi make install # --- PHP.ini + FPM scaffolding --- mkdir -p "${FPMDIR}/usr/php/php.d" mkdir -p "${FPMDIR}/usr/var/sockets" mkdir -p "${FPMDIR}/usr/etc/php-fpm.d" mkdir -p "${FPMDIR}/usr/etc/php-fpm.d/users" rsync php.ini-production "${FPMDIR}/usr/php/php.ini" sed -i 's/^short_open_tag.*/short_open_tag = On/' "${FPMDIR}/usr/php/php.ini" sed -i 's/^;cgi.fix_pathinfo=.*/cgi.fix_pathinfo=1/' "${FPMDIR}/usr/php/php.ini" sed -i 's/.*mail.add_x_header.*/mail.add_x_header = On/' "${FPMDIR}/usr/php/php.ini" sed -i 's@.*mail.log.*@mail.log = /usr/local/apache/logs/phpmail.log@' "${FPMDIR}/usr/php/php.ini" echo "include=${FPMDIR}/usr/etc/php-fpm.d/users/*.conf" > "${FPMDIR}/usr/etc/php-fpm.d/users.conf" echo "include=${FPMDIR}/usr/etc/php-fpm.d/*.conf" > "${FPMDIR}/usr/etc/php-fpm.conf" cat > "${FPMDIR}/usr/etc/php-fpm.d/cwpsvc.conf" <<EOF [cwpsvc] listen = ${FPMDIR}/usr/var/sockets/cwpsvc.sock listen.owner = cwpsvc listen.group = cwpsvc listen.mode = 0640 user = cwpsvc group = cwpsvc pm = ondemand pm.max_children = 25 pm.process_idle_timeout = 15s request_terminate_timeout = 0 EOF # --- Systemd service --- cp sapi/fpm/php-fpm.service "/usr/lib/systemd/system/php-fpm${PHPMAJOR}.service" sed -i "s|\${exec_prefix}|${FPMDIR}/usr|g" "/usr/lib/systemd/system/php-fpm${PHPMAJOR}.service" sed -i "s|\${prefix}|${FPMDIR}/usr|g" "/usr/lib/systemd/system/php-fpm${PHPMAJOR}.service" systemctl daemon-reload systemctl enable "php-fpm${PHPMAJOR}" # --- Loading Apache FPM module if not already present --- if [ ! -e "/usr/local/apache/conf.d/php-fpm.conf" ]; then cat > /usr/local/apache/conf.d/php-fpm.conf <<EOF <IfModule !proxy_fcgi_module> LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so </IfModule> EOF fi # --- External modules (imagick, redis, imap, etc.) --- if [ -e "${CONFBASE}/php${PHPMAJOR}_external.conf" ]; then bash "${CONFBASE}/php${PHPMAJOR}_external.conf" || true fi # These extensions are unbundled from PHP 8.5 and may be absent from stale # CWP-generated external configs. for late_module in imap7.sh pspell.sh; do late_script="/usr/local/cwpsrv/htdocs/resources/conf/el9/php-fpm_selector/external_modules/8.5/${late_module}" if [ -x "${late_script}" ]; then bash "${late_script}" || true fi done # --- Monit integration for custom PHP-FPM --- MONIT_CONF_DIR="/etc/monit.d" MONIT_CONF_FILE="${MONIT_CONF_DIR}/php-fpm${PHPMAJOR}" PHPFPM_SERVICE="php-fpm${PHPMAJOR}.service" PHPFPM_BASE="/opt/alt/php-fpm${PHPMAJOR}" PHPFPM_CONF="${PHPFPM_BASE}/usr/etc/php-fpm.conf" PHPFPM_SOCKET="${PHPFPM_BASE}/usr/var/sockets/cwpsvc.sock" PHPVER_LABEL="${PHPMAJOR:0:1}.${PHPMAJOR:1:1}" echo "" echo "===== Monit integration for PHP-FPM ${PHPVER_LABEL} =====" if ! command -v monit >/dev/null 2>&1; then echo "Monit is not installed. Installing..." dnf -y install monit fi mkdir -p "${MONIT_CONF_DIR}" cat > "${MONIT_CONF_FILE}" <<EOF # PHP-FPM ${PHPVER_LABEL} - CWP alt-php custom build check process php-fpm${PHPMAJOR} matching ".*/opt/alt/php-fpm${PHPMAJOR}/usr/etc/php-fpm.conf.*" start program "/usr/bin/systemctl start ${PHPFPM_SERVICE}" stop program "/usr/bin/systemctl stop ${PHPFPM_SERVICE}" if failed unixsocket ${PHPFPM_SOCKET} then restart if cpu > 95% for 12 cycles then restart if 4 restarts within 8 cycles then timeout EOF chmod 0644 "${MONIT_CONF_FILE}" if [ ! -f "${PHPFPM_CONF}" ]; then echo "WARNING: PHP-FPM config not found yet: ${PHPFPM_CONF}" fi systemctl enable "${PHPFPM_SERVICE}" >/dev/null 2>&1 || true systemctl enable monit >/dev/null 2>&1 || true if systemctl is-active --quiet "${PHPFPM_SERVICE}"; then echo "PHP-FPM service is active: ${PHPFPM_SERVICE}" else echo "PHP-FPM service is not active yet; trying to start it..." systemctl start "${PHPFPM_SERVICE}" || true fi systemctl restart monit || true if command -v monit >/dev/null 2>&1; then monit reload || true monit validate || true fi echo "Monit config installed: ${MONIT_CONF_FILE}" echo "===== Monit integration completed =====" systemctl restart "php-fpm${PHPMAJOR}" # --- CSF pignore --- if [ -e "/etc/csf/csf.pignore" ]; then # PHP-FPM + PHP binary if ! grep -q "${FPMDIR}/usr/sbin/php-fpm" /etc/csf/csf.pignore; then echo "exe:${FPMDIR}/usr/sbin/php-fpm" >> /etc/csf/csf.pignore fi if ! grep -q "${FPMDIR}/usr/bin/php" /etc/csf/csf.pignore; then echo "exe:${FPMDIR}/usr/bin/php" >> /etc/csf/csf.pignore fi # memcached daemon if command -v memcached >/dev/null 2>&1; then if ! grep -q "exe:/usr/bin/memcached" /etc/csf/csf.pignore; then echo "exe:/usr/bin/memcached" >> /etc/csf/csf.pignore fi fi # redis-server daemon if command -v redis-server >/dev/null 2>&1; then if ! grep -q "exe:/usr/bin/redis-server" /etc/csf/csf.pignore; then echo "exe:/usr/bin/redis-server" >> /etc/csf/csf.pignore fi fi # Restart CSF/LFD to apply changes csf -r fi rm -rf /usr/local/src/php-build rm -rf /usr/local/src/build-dir echo "PHP ${PHPVER} (php-fpm${PHPMAJOR}) build finished successfully." You can use it. Critical part: /usr/local/cwpsrv/htdocs/resources/conf/el9/php-fpm_selector/pre_run/8.5/imap7.shThe working script is: #!/bin/bash set -euo pipefail echo "" echo "===== PHP-FPM 8.5 IMAP setup =====" PHPFPM="/opt/alt/php-fpm85" PHPBIN="${PHPFPM}/usr/bin/php" PHPCONFIG="${PHPFPM}/usr/bin/php-config" PHPIZE="${PHPFPM}/usr/bin/phpize" PHPINIDIR="${PHPFPM}/usr/php/php.d" IMAP_VERSION="1.0.3" echo "Installing IMAP build dependencies..." dnf -y install uw-imap-devel krb5-devel openssl-devel pkgconf make gcc autoconf if [ ! -x "${PHPCONFIG}" ] || [ ! -x "${PHPIZE}" ]; then echo "PHP-FPM 8.5 is not built yet. Dependencies are installed; run this script again after PHP 8.5 is installed to build PECL imap." exit 0 fi if "${PHPBIN}" -m 2>/dev/null | grep -qi '^imap$'; then echo "IMAP extension is already loaded for PHP-FPM 8.5." exit 0 fi mkdir -p "${PHPINIDIR}" cd /usr/local/src rm -rf "imap-${IMAP_VERSION}" imap.tgz echo "Downloading PECL imap-${IMAP_VERSION}..." curl -fL "https://pecl.php.net/get/imap-${IMAP_VERSION}.tgz" -o imap.tgz tar -xzf imap.tgz cd "imap-${IMAP_VERSION}" echo "Running phpize..." "${PHPIZE}" echo "Configuring IMAP extension..." ./configure \ --with-php-config="${PHPCONFIG}" \ --with-libdir=lib64 \ --with-imap=/usr \ --with-imap-ssl \ --with-kerberos echo "Building IMAP extension..." make -j"$(nproc)" make install PHPEXTDIR="$("${PHPCONFIG}" --extension-dir)" if [ ! -f "${PHPEXTDIR}/imap.so" ]; then echo "ERROR: imap.so was not installed to ${PHPEXTDIR}" exit 1 fi echo "extension=imap.so" > "${PHPINIDIR}/imap.ini" if "${PHPBIN}" -m 2>/dev/null | grep -qi '^imap$'; then echo "IMAP extension installed and enabled for PHP-FPM 8.5." else echo "ERROR: imap.ini was created, but PHP does not load the IMAP extension." "${PHPBIN}" -d display_errors=1 -m exit 1 fi if command -v systemctl >/dev/null 2>&1; then systemctl restart php-fpm85 || true fi echo "===== PHP-FPM 8.5 IMAP setup completed =====" These are designed to supplement the CWP UI until the system PHP 8.4, 8.5 scripts arrive.
-
CWP Pro 1.3/1.4 โ Missing jquery.sparkline.js breaks PHP, ModSecurity and dashboard functions
Since I need to fix the admin interface of 15+ servers at least at a basic level, I summarized the above steps in a correction script. #!/usr/bin/env bash set -Eeuo pipefail DESIGN_DIR="/usr/local/cwpsrv/htdocs/admin/design" CHARTS_DIR="${DESIGN_DIR}/charts" SPARKLINE_DIR="${CHARTS_DIR}/sparklines" SOURCE_FILE="${DESIGN_DIR}/plugins/charts/sparklines/jquery.sparkline.js" LINK_FILE="${SPARKLINE_DIR}/jquery.sparkline.js" design_was_immutable=0 design_unlocked=0 log() { printf '[cwp-sparkline-fix] %s\n' "$*" } fail() { log "ERROR: $*" >&2 exit 1 } restore_design_protection() { if (( design_unlocked == 1 && design_was_immutable == 1 )); then if chattr +i "$DESIGN_DIR"; then design_unlocked=0 log "Restored the immutable flag on ${DESIGN_DIR}." else log "WARNING: Could not restore the immutable flag on ${DESIGN_DIR}." >&2 fi fi } on_error() { local exit_code=$? log "The repair stopped because a command failed." >&2 restore_design_protection exit "$exit_code" } trap on_error ERR trap restore_design_protection EXIT [[ ${EUID:-$(id -u)} -eq 0 ]] || fail "Run this script as root." command -v chattr >/dev/null 2>&1 || fail "The chattr command is not available." command -v lsattr >/dev/null 2>&1 || fail "The lsattr command is not available." [[ -d "$DESIGN_DIR" ]] || fail "CWP design directory not found: ${DESIGN_DIR}" [[ -f "$SOURCE_FILE" ]] || fail "Sparkline source file not found: ${SOURCE_FILE}" if [[ -L "$LINK_FILE" ]]; then resolved_link=$(readlink -f "$LINK_FILE" || true) resolved_source=$(readlink -f "$SOURCE_FILE") if [[ "$resolved_link" == "$resolved_source" ]]; then log "The correct symlink already exists. No changes are required." exit 0 fi fail "A symlink already exists at ${LINK_FILE}, but it points to ${resolved_link:-an invalid target}." fi [[ ! -e "$LINK_FILE" ]] || fail "A non-symlink file already exists at ${LINK_FILE}." design_attributes=$(lsattr -d "$DESIGN_DIR" | awk '{print $1}') if [[ "$design_attributes" == *i* ]]; then design_was_immutable=1 log "Temporarily removing the immutable flag from ${DESIGN_DIR}." chattr -i "$DESIGN_DIR" design_unlocked=1 else log "The design directory is not immutable; no flag change is needed." fi log "Creating the missing CWP asset path." mkdir -p "$SPARKLINE_DIR" chown root:root "$CHARTS_DIR" "$SPARKLINE_DIR" chmod 750 "$CHARTS_DIR" "$SPARKLINE_DIR" log "Creating the Sparkline symlink." ln -s "$SOURCE_FILE" "$LINK_FILE" resolved_link=$(readlink -f "$LINK_FILE") resolved_source=$(readlink -f "$SOURCE_FILE") [[ "$resolved_link" == "$resolved_source" ]] || fail "Symlink verification failed." log "Protecting the new directories with the immutable flag." chattr +i "$SPARKLINE_DIR" chattr +i "$CHARTS_DIR" restore_design_protection log "Repair completed successfully." log "Symlink: ${LINK_FILE} -> ${resolved_link}" log "Reload the CWP admin interface with Ctrl+Shift+R."On the given server, copy it to the /root directory, then: cd /root chmod 750 cwp-fix-sparkline-path.sh ./cwp-fix-sparkline-path.shOr simple sh /root/cwp-fix-sparkline-path.shThe script: checks root permissions and the source file; detects if the fix already exists; does not overwrite any invalid or unknown files/symlinks; temporarily unsets the immutable attribute of the design; creates the directories and symlinks; checks the target of the symlink; resets immutable protection; attempts to reset the design directory protection even if an error occurs.
-
CWP Pro 1.3/1.4 โ Missing jquery.sparkline.js breaks PHP, ModSecurity and dashboard functions
Temporary workaround for the missing Sparkline asset in CWP Pro 1.4The issue is caused by an incorrect asset path generated by the CWP admin interface. CWP requests: /admin/design/charts/sparklines/jquery.sparkline.js but the file is actually installed at: /admin/design/plugins/charts/sparklines/jquery.sparkline.js Creating a symlink from the requested location to the existing CWP file restored most of the affected admin functions, including: ModSecurity installation; PHP-FPM configuration; starting the PHP compiler; several AJAX-based administration functions. The CWP admin directories may have the immutable filesystem attribute enabled. Therefore, running mkdir directly may fail with: Operation not permitted The following temporary workaround worked on the affected servers. Run these commands as root. 1. Confirm the immutable attributelsattr -d \ /usr/local/cwpsrv/htdocs/admin \ /usr/local/cwpsrv/htdocs/admin/design The result may look like: ----i---------e------- /usr/local/cwpsrv/htdocs/admin ----i---------e------- /usr/local/cwpsrv/htdocs/admin/design The i flag means that the directory is immutable. 2. Temporarily remove the immutable flag from the design directoryOnly the design directory needs to be changed: chattr -i /usr/local/cwpsrv/htdocs/admin/design There is no need to remove the immutable flag from the parent admin directory. 3. Create the missing directory structuremkdir -p \ /usr/local/cwpsrv/htdocs/admin/design/charts/sparklines Set appropriate ownership and permissions: chown root:root \ /usr/local/cwpsrv/htdocs/admin/design/charts \ /usr/local/cwpsrv/htdocs/admin/design/charts/sparklines chmod 750 \ /usr/local/cwpsrv/htdocs/admin/design/charts \ /usr/local/cwpsrv/htdocs/admin/design/charts/sparklines 4. Create the symlinkln -s \ /usr/local/cwpsrv/htdocs/admin/design/plugins/charts/sparklines/jquery.sparkline.js \ /usr/local/cwpsrv/htdocs/admin/design/charts/sparklines/jquery.sparkline.js Verify the target: readlink -f \ /usr/local/cwpsrv/htdocs/admin/design/charts/sparklines/jquery.sparkline.js The expected result is: /usr/local/cwpsrv/htdocs/admin/design/plugins/charts/sparklines/jquery.sparkline.js 5. Restore the filesystem protectionProtect the newly created directories: chattr +i \ /usr/local/cwpsrv/htdocs/admin/design/charts/sparklines \ /usr/local/cwpsrv/htdocs/admin/design/charts Restore the immutable flag on the original design directory: chattr +i /usr/local/cwpsrv/htdocs/admin/design 6. Verify the final statelsattr -d \ /usr/local/cwpsrv/htdocs/admin/design \ /usr/local/cwpsrv/htdocs/admin/design/charts \ /usr/local/cwpsrv/htdocs/admin/design/charts/sparklines ls -l \ /usr/local/cwpsrv/htdocs/admin/design/charts/sparklines/jquery.sparkline.js Finally, reload the CWP admin interface using a hard refresh: Ctrl+Shift+R This is only a temporary workaround. The permanent CWP correction should change the generated asset URL from: - /admin/design/charts/sparklines/jquery.sparkline.js + /admin/design/plugins/charts/sparklines/jquery.sparkline.js A future CWP update may remove the workaround, so the official package or admin template should be corrected. @Sandeep B. Please use the findings in the corrections in the CWP update.
-
CWP Pro 1.3/1.4 โ Missing jquery.sparkline.js breaks PHP, ModSecurity and dashboard functions
Hello, I am experiencing a CWP admin interface issue on multiple servers, and I would like to know whether anyone has already found a fix or workaround. The problem occurs both: on a fresh CWP installation; and after upgrading working CWP 0.9.x installations to CWP Pro 1.2, 1.3 or 1.4. The affected systems run AlmaLinux 9.x latest Several essential CWP functions no longer complete their AJAX operations. For example: PHP installation; DNF update; ModSecurity installation; some dashboard and main-page lists. The loading icon keeps spinning, while the browser console reports the following errors: GET https://hostname:2031/<CWP_ADMIN_SECURE_PATH>/admin/design/charts/sparklines/jquery.sparkline.js net::ERR_ABORTED 404 (Not Found) blank.js:13 Uncaught TypeError: $(...).sparkline is not a function at blank.js:13:13 Another error is also displayed on some affected pages: Uncaught TypeError: Cannot read properties of undefined (reading 'ext') The first error appears to be the primary problem: CWPโs own admin interface requests: /admin/design/charts/sparklines/jquery.sparkline.js but the file is not available at that location. Consequently, the sparkline() function is undefined, and CWPโs blank.js fails. CWP support has already corrected part of the underlying installation problem, but these frontend errors remain and prevent several admin functions from working properly. I have also noticed that CWPโs directories contain a node_modules directory. This raises another possibility: perhaps the affected CWP release requires an internal frontend asset build or deployment step that was not executed, failed silently, or was omitted from the installation/update process. There may be a CWP-specific build command, deployment script or package-maintenance command responsible for copying the JavaScript dependencies into the public admin asset directory. Has anyone encountered and resolved this in CWP Pro 1.3 or 1.4? In particular, I would appreciate information about: Where jquery.sparkline.js is supposed to be installed in the current CWP version. Whether the CWP packages or node_modules contain the file under another path. Whether there is an official CWP asset build, deployment or repair command that restores the missing frontend files. Whether the installer or updater normally runs an npm, Webpack, Gulp, Vite or other asset-processing step. Whether a package reinstall can safely restore the missing assets. Whether copying or symlinking the file from its actual location is a safe temporary workaround. Whether additional JavaScript dependencies are missing, which might explain the reading 'ext' error. If someone has a working CWP Pro 1.4 installation, it would also be helpful to compare: the relevant package.json scripts; the location of jquery.sparkline.js; the contents and permissions of the public sparklines asset directory; any CWP installer or updater logs related to frontend asset deployment. The relevant public directory may be similar to: /usr/local/cwpsrv/htdocs/resources/admin/design/charts/sparklines/or another corresponding directory used by the current release. For safety, I do not want to run npm install, npm update or an unknown build command inside CWPโs production directories without first identifying the official CWP procedure. Such a command could change dependency versions or overwrite vendor-managed assets. Any confirmed workaround, official command, package name, file location or diagnostic result would be very useful. I can also forward the technical findings to @Sandeep B. . at CWP support to assist with the permanent correction. Thank you.
-
How to Add Custom PHP-FPM 8.4 / 8.5 Support to CWP on AlmaLinux 9.x
@SeaScoot Hello, In my 8.4.ini [config-path] default=1 required=1 option="--prefix=/opt/alt/php-fpm84/usr --with-config-file-path=/opt/alt/php-fpm84/usr/php" info-file=config-path.txt pre-script="php84.sh" [config-scan] default=1 required=1 option="--with-config-file-scan-dir=/opt/alt/php-fpm84/usr/php/php.d" info-file=config-scan.txtand in my 8.5.ini [config-path] default=1 required=1 option="--prefix=/opt/alt/php-fpm85/usr --with-config-file-path=/opt/alt/php-fpm85/usr/php" info-file=config-path.txt pre-script="php85.sh" [config-scan] default=1 required=1 option="--with-config-file-scan-dir=/opt/alt/php-fpm85/usr/php/php.d" info-file=config-scan.txtthere are lines to select the correct folder and version.
TheHolbi
Priority Members
-
Joined
-
Last visited