Skip to content
View in the app

A better way to browse. Learn more.

AlphaGNU

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

TheHolbi

Priority Members
  • Joined

  • Last visited

Everything posted by TheHolbi

  1. 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.
  2. 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."
  3. 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/" )
  4. In this case, I suggest you open a ticket on GitHub about this.
  5. 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
  6. @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.
  7. @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.
  8. @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.
  9. 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.
  10. @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.
  11. @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.
  12. 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.
  13. 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.
  14. 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.
  15. @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.
  16. After recent CWP updates, some AlmaLinux 9.x servers may report false security alerts when running: sh /scripts/cwp_security_audit A typical false positive looks like this: ------------------------------------------------------ [INFO] Auditing cwpsrv (PID: 767572) [OK] cwpsrv looks clean. ------------------------------------------------------ [INFO] Auditing php-fpm-cwp (PID: 710) [SECURITY ALERT] Unknown/Untrusted file: /usr/lib64/gconv/gconv-modules.cache Error:Can't add notification![SECURITY ALERT] Unauthorized port: php-fpm Error:Can't add notification!------------------------------------------------------ [INFO] Auditing apache (PID: 768077) [OK] apache looks clean. ------------------------------------------------------ [DONE] Security audit finished. In this case the warning is misleading. On AlmaLinux 9.x, the file: /usr/lib64/gconv/gconv-modules.cache is a normal system file used by the GNU C Library character conversion system. The original CWP audit script does not include /usr/lib64/gconv/ in the allowed library paths, so it incorrectly reports this file as unknown or untrusted. There is also a second parsing issue in the port audit section. The original script extracts listening ports using a simple awk -F':' expression against generic lsof output. In some cases this can incorrectly parse process-related text and produce an alert such as: [SECURITY ALERT] Unauthorized port: php-fpm Obviously, php-fpm is not a port number. What needs to be fixedThere are two small changes that solve the false positives. First, add this path to ALLOWED_LIB_PATHS: "/usr/lib64/gconv/" Second, replace the port audit line with a more precise lsof command that only checks TCP listening sockets: local CURRENT_PORTS=$(lsof -Pan -p $PID -iTCP -sTCP:LISTEN 2>/dev/null | awk 'NR>1 {split($9,a,":"); print a[length(a)]}') This avoids parsing unrelated lsof lines and prevents values like php-fpm from being treated as ports. Patched version of /scripts/cwp_security_auditBelow is the corrected version. It keeps the original logic but fixes the AlmaLinux 9.x false positives. #!/bin/bash # --- CONFIGURATION --- 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/" ) ALLOWED_BINARIES=( "/usr/local/cwpsrv/bin/cwpsrv" "/usr/local/cwp/php71/sbin/php-fpm" "/usr/local/apache/bin/httpd" ) ALLOWED_PORTS=("2030" "2031" "2082" "2083" "2086" "2087" "2095" "2096" "9000" "2302" "2304" "8181" "8443" "80" "443") # --- INITIALIZATION --- if ! command -v lsof &> /dev/null; then yum install -y lsof fi # --- FUNCTIONS --- check_process() { local PROC_NAME=$1 local SEARCH_PATTERN=$2 local PID=$(ps aux | grep "$SEARCH_PATTERN" | grep -v grep | awk '{print $2}' | head -n 1) if [ -z "$PID" ]; then echo "[SKIP] Process '$PROC_NAME' not found." return fi echo "------------------------------------------------------" echo "[INFO] Auditing $PROC_NAME (PID: $PID)" local GLOBAL_ERROR=0 # 1. Detect GHOST Files (DELETED or missing via stat) local GHOST_DATA=$(lsof -p $PID -n | grep -E "DEL|\(stat:" | grep -v "/dev/zero") if [ ! -z "$GHOST_DATA" ]; then echo "[!!! CRITICAL ALERT !!!] Ghost files (deleted but running) found:" echo "$GHOST_DATA" /usr/local/cwp/php71/bin/php /usr/local/cwpsrv/htdocs/resources/admin/include/libs/notifications/cli.php --level="danger" --subject="CWP Security Audit - Ghost files (deleted but running)" --message="[!!! CRITICAL ALERT !!!] Ghost files (deleted but running) found, for more info run: sh /scripts/cwp_security_audit" GLOBAL_ERROR=1 fi # 2. Deep Memory Audit (Path + RPM Package Check) local CURRENT_MEM=$(lsof -p $PID -n | grep "mem" | awk '{for(i=9;i<=NF;i++) printf "%s ", $i; print ""}' | sed 's/(stat:.*//' | xargs) for FILE in $CURRENT_MEM; do [[ -z "$FILE" || "$FILE" == "REG" || "$FILE" == "mem" || "$FILE" == "/" ]] && continue local MATCH=0 for ALLOWED in "${ALLOWED_LIB_PATHS[@]}"; do if [[ "$FILE" == "$ALLOWED"* ]]; then MATCH=1; break; fi done for ALLOWED in "${ALLOWED_BINARIES[@]}"; do if [[ "$FILE" == "$ALLOWED" ]]; then MATCH=1; break; fi done if [ $MATCH -eq 0 ]; then echo "[SECURITY ALERT] Unknown/Untrusted file: $FILE" /usr/local/cwp/php71/bin/php /usr/local/cwpsrv/htdocs/resources/admin/include/libs/notifications/cli.php --level="danger" --subject="CWP Security Audit - Unknown/Untrusted file" --message="[SECURITY ALERT] Unknown/Untrusted file: $FILE" GLOBAL_ERROR=1 else if [[ "$FILE" == "/usr/lib64/"* ]]; then if ! rpm -qf "$FILE" &>/dev/null; then echo "[!!! DANGER !!!] File in system path but NOT owned by any package: $FILE" /usr/local/cwp/php71/bin/php /usr/local/cwpsrv/htdocs/resources/admin/include/libs/notifications/cli.php --level="danger" --subject="CWP Security Audit - File in system path" --message="[!!! DANGER !!!] File in system path but NOT owned by any package, for more info run: sh /scripts/cwp_security_audit" GLOBAL_ERROR=1 fi fi fi done # 3. Port Audit local CURRENT_PORTS=$(lsof -Pan -p $PID -iTCP -sTCP:LISTEN 2>/dev/null | awk 'NR>1 {split($9,a,":"); print a[length(a)]}') for PORT in $CURRENT_PORTS; do local PORT_MATCH=0 for ALLOWED in "${ALLOWED_PORTS[@]}"; do if [ "$PORT" == "$ALLOWED" ]; then PORT_MATCH=1; break; fi done if [ $PORT_MATCH -eq 0 ]; then echo "[SECURITY ALERT] Unauthorized port: $PORT" /usr/local/cwp/php71/bin/php /usr/local/cwpsrv/htdocs/resources/admin/include/libs/notifications/cli.php --level="danger" --subject="CWP Security Audit - Unauthorized port: $PORT" --message="[SECURITY ALERT] Unauthorized port, for more info run: sh /scripts/cwp_security_audit" GLOBAL_ERROR=1 fi done [ $GLOBAL_ERROR -eq 0 ] && echo "[OK] $PROC_NAME looks clean." } # --- EXECUTION --- check_process "cwpsrv" "cwpsrv: master process" check_process "php-fpm-cwp" "php-fpm: master process .*cwpsrv.conf" check_process "apache" "/usr/local/apache/bin/httpd" echo "------------------------------------------------------" echo "[DONE] Security audit finished." Problem: CWP updates may overwrite the fixCWP updates may overwrite /scripts/cwp_security_audit, so manually patching the file once is not always enough. One practical solution is to keep a local fixed copy and automatically restore it if CWP replaces the file during an update. The following installer creates: /root/cwp-overrides/cwp_security_audit.fixed /root/cwp-overrides/repair-cwp-security-audit.sh /etc/systemd/system/cwp-security-audit-override.service /etc/systemd/system/cwp-security-audit-override.path /etc/cron.d/cwp-security-audit-override The systemd.path unit watches /scripts/cwp_security_audit. If the file changes, the repair script compares it to the fixed version and restores the patched file if needed. A daily cron fallback is also added in case the file watch misses an event. Installer scriptSave this as: install-cwp-security-audit-override.sh Then run it as root: chmod +x install-cwp-security-audit-override.sh ./install-cwp-security-audit-override.sh #!/bin/bash set -euo pipefail # ============================================================ # CWP security audit override installer # Restores the locally fixed /scripts/cwp_security_audit # if CWP updates overwrite it. # ============================================================ if [ "$(id -u)" -ne 0 ]; then echo "ERROR: This installer must be run as root." exit 1 fi OVERRIDE_DIR="/root/cwp-overrides" BACKUP_DIR="${OVERRIDE_DIR}/backups" FIXED_FILE="${OVERRIDE_DIR}/cwp_security_audit.fixed" REPAIR_SCRIPT="${OVERRIDE_DIR}/repair-cwp-security-audit.sh" TARGET="/scripts/cwp_security_audit" SERVICE_FILE="/etc/systemd/system/cwp-security-audit-override.service" PATH_FILE="/etc/systemd/system/cwp-security-audit-override.path" CRON_FILE="/etc/cron.d/cwp-security-audit-override" LOG_FILE="/var/log/cwp-security-audit-override.log" echo "------------------------------------------------------" echo "[INFO] Installing CWP security audit override" echo "------------------------------------------------------" mkdir -p "$OVERRIDE_DIR" "$BACKUP_DIR" chmod 700 "$OVERRIDE_DIR" chmod 700 "$BACKUP_DIR" if ! command -v lsof >/dev/null 2>&1; then echo "[INFO] lsof not found. Installing..." if command -v dnf >/dev/null 2>&1; then dnf install -y lsof elif command -v yum >/dev/null 2>&1; then yum install -y lsof else echo "WARNING: Neither dnf nor yum found. Please install lsof manually." fi fi if [ -f "$TARGET" ]; then INITIAL_BACKUP="${BACKUP_DIR}/cwp_security_audit.initial.$(date '+%Y%m%d-%H%M%S').bak" cp -a "$TARGET" "$INITIAL_BACKUP" echo "[INFO] Current target backed up to: $INITIAL_BACKUP" else echo "[WARNING] Target file does not exist yet: $TARGET" fi cat > "$FIXED_FILE" <<'CWP_FIXED_SCRIPT' #!/bin/bash # --- CONFIGURATION --- 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/" ) ALLOWED_BINARIES=( "/usr/local/cwpsrv/bin/cwpsrv" "/usr/local/cwp/php71/sbin/php-fpm" "/usr/local/apache/bin/httpd" ) ALLOWED_PORTS=("2030" "2031" "2082" "2083" "2086" "2087" "2095" "2096" "9000" "2302" "2304" "8181" "8443" "80" "443") if ! command -v lsof &> /dev/null; then yum install -y lsof fi check_process() { local PROC_NAME=$1 local SEARCH_PATTERN=$2 local PID=$(ps aux | grep "$SEARCH_PATTERN" | grep -v grep | awk '{print $2}' | head -n 1) if [ -z "$PID" ]; then echo "[SKIP] Process '$PROC_NAME' not found." return fi echo "------------------------------------------------------" echo "[INFO] Auditing $PROC_NAME (PID: $PID)" local GLOBAL_ERROR=0 local GHOST_DATA=$(lsof -p $PID -n | grep -E "DEL|\(stat:" | grep -v "/dev/zero") if [ ! -z "$GHOST_DATA" ]; then echo "[!!! CRITICAL ALERT !!!] Ghost files (deleted but running) found:" echo "$GHOST_DATA" /usr/local/cwp/php71/bin/php /usr/local/cwpsrv/htdocs/resources/admin/include/libs/notifications/cli.php --level="danger" --subject="CWP Security Audit - Ghost files (deleted but running)" --message="[!!! CRITICAL ALERT !!!] Ghost files (deleted but running) found, for more info run: sh /scripts/cwp_security_audit" GLOBAL_ERROR=1 fi local CURRENT_MEM=$(lsof -p $PID -n | grep "mem" | awk '{for(i=9;i<=NF;i++) printf "%s ", $i; print ""}' | sed 's/(stat:.*//' | xargs) for FILE in $CURRENT_MEM; do [[ -z "$FILE" || "$FILE" == "REG" || "$FILE" == "mem" || "$FILE" == "/" ]] && continue local MATCH=0 for ALLOWED in "${ALLOWED_LIB_PATHS[@]}"; do if [[ "$FILE" == "$ALLOWED"* ]]; then MATCH=1; break; fi done for ALLOWED in "${ALLOWED_BINARIES[@]}"; do if [[ "$FILE" == "$ALLOWED" ]]; then MATCH=1; break; fi done if [ $MATCH -eq 0 ]; then echo "[SECURITY ALERT] Unknown/Untrusted file: $FILE" /usr/local/cwp/php71/bin/php /usr/local/cwpsrv/htdocs/resources/admin/include/libs/notifications/cli.php --level="danger" --subject="CWP Security Audit - Unknown/Untrusted file" --message="[SECURITY ALERT] Unknown/Untrusted file: $FILE" GLOBAL_ERROR=1 else if [[ "$FILE" == "/usr/lib64/"* ]]; then if ! rpm -qf "$FILE" &>/dev/null; then echo "[!!! DANGER !!!] File in system path but NOT owned by any package: $FILE" /usr/local/cwp/php71/bin/php /usr/local/cwpsrv/htdocs/resources/admin/include/libs/notifications/cli.php --level="danger" --subject="CWP Security Audit - File in system path" --message="[!!! DANGER !!!] File in system path but NOT owned by any package, for more info run: sh /scripts/cwp_security_audit" GLOBAL_ERROR=1 fi fi fi done local CURRENT_PORTS=$(lsof -Pan -p $PID -iTCP -sTCP:LISTEN 2>/dev/null | awk 'NR>1 {split($9,a,":"); print a[length(a)]}') for PORT in $CURRENT_PORTS; do local PORT_MATCH=0 for ALLOWED in "${ALLOWED_PORTS[@]}"; do if [ "$PORT" == "$ALLOWED" ]; then PORT_MATCH=1; break; fi done if [ $PORT_MATCH -eq 0 ]; then echo "[SECURITY ALERT] Unauthorized port: $PORT" /usr/local/cwp/php71/bin/php /usr/local/cwpsrv/htdocs/resources/admin/include/libs/notifications/cli.php --level="danger" --subject="CWP Security Audit - Unauthorized port: $PORT" --message="[SECURITY ALERT] Unauthorized port, for more info run: sh /scripts/cwp_security_audit" GLOBAL_ERROR=1 fi done [ $GLOBAL_ERROR -eq 0 ] && echo "[OK] $PROC_NAME looks clean." } check_process "cwpsrv" "cwpsrv: master process" check_process "php-fpm-cwp" "php-fpm: master process .*cwpsrv.conf" check_process "apache" "/usr/local/apache/bin/httpd" echo "------------------------------------------------------" echo "[DONE] Security audit finished." CWP_FIXED_SCRIPT chmod 600 "$FIXED_FILE" cat > "$REPAIR_SCRIPT" <<'REPAIR_SCRIPT' #!/bin/bash set -euo pipefail TARGET="/scripts/cwp_security_audit" FIXED="/root/cwp-overrides/cwp_security_audit.fixed" BACKUP_DIR="/root/cwp-overrides/backups" LOG="/var/log/cwp-security-audit-override.log" mkdir -p "$BACKUP_DIR" timestamp="$(date '+%Y-%m-%d %H:%M:%S')" notify_cwp() { local level="$1" local subject="$2" local message="$3" if [ -x /usr/local/cwp/php71/bin/php ] && [ -f /usr/local/cwpsrv/htdocs/resources/admin/include/libs/notifications/cli.php ]; then /usr/local/cwp/php71/bin/php \ /usr/local/cwpsrv/htdocs/resources/admin/include/libs/notifications/cli.php \ --level="$level" \ --subject="$subject" \ --message="$message" \ >/dev/null 2>&1 || true fi } if [ ! -f "$FIXED" ]; then echo "[$timestamp] ERROR: fixed file not found: $FIXED" >> "$LOG" notify_cwp "danger" \ "CWP override error" \ "Fixed CWP security audit file not found: $FIXED" exit 1 fi if [ ! -f "$TARGET" ]; then echo "[$timestamp] WARNING: target file missing, restoring: $TARGET" >> "$LOG" install -m 755 "$FIXED" "$TARGET" notify_cwp "warning" \ "CWP security audit restored" \ "Target file was missing and has been restored: $TARGET" exit 0 fi target_hash="$(sha256sum "$TARGET" | awk '{print $1}')" fixed_hash="$(sha256sum "$FIXED" | awk '{print $1}')" if [ "$target_hash" != "$fixed_hash" ]; then backup="$BACKUP_DIR/cwp_security_audit.$(date '+%Y%m%d-%H%M%S').bak" cp -a "$TARGET" "$backup" install -m 755 "$FIXED" "$TARGET" echo "[$timestamp] RESTORED: $TARGET was changed. Backup saved to: $backup" >> "$LOG" notify_cwp "warning" \ "CWP override restored cwp_security_audit" \ "CWP update changed /scripts/cwp_security_audit. The local fixed version was restored. Backup: $backup" else echo "[$timestamp] OK: no change detected." >> "$LOG" fi REPAIR_SCRIPT chmod 700 "$REPAIR_SCRIPT" cat > "$SERVICE_FILE" <<'SERVICE_UNIT' [Unit] Description=Restore local fixed CWP security audit script if overwritten [Service] Type=oneshot ExecStart=/root/cwp-overrides/repair-cwp-security-audit.sh SERVICE_UNIT chmod 644 "$SERVICE_FILE" cat > "$PATH_FILE" <<'PATH_UNIT' [Unit] Description=Watch CWP security audit script for changes [Path] PathChanged=/scripts/cwp_security_audit PathModified=/scripts/cwp_security_audit Unit=cwp-security-audit-override.service [Install] WantedBy=multi-user.target PATH_UNIT chmod 644 "$PATH_FILE" cat > "$CRON_FILE" <<'CRON_FALLBACK' # CWP security audit override fallback check # Runs daily in case systemd.path missed a file change. 17 3 * * * root /root/cwp-overrides/repair-cwp-security-audit.sh >/dev/null 2>&1 CRON_FALLBACK chmod 644 "$CRON_FILE" systemctl daemon-reload systemctl enable --now cwp-security-audit-override.path echo "[INFO] Running first repair/check..." "$REPAIR_SCRIPT" echo "------------------------------------------------------" echo "[OK] Installation finished." echo echo "Status:" systemctl --no-pager status cwp-security-audit-override.path || true echo echo "Last log entries:" tail -n 10 "$LOG_FILE" 2>/dev/null || true echo "------------------------------------------------------" VerificationAfter installation, run: systemctl status cwp-security-audit-override.path tail -n 30 /var/log/cwp-security-audit-override.log sha256sum /scripts/cwp_security_audit /root/cwp-overrides/cwp_security_audit.fixed The two sha256sum values should be identical. Then run the CWP audit again: sh /scripts/cwp_security_audit On a clean AlmaLinux 9.x server, the previous false alerts for: /usr/lib64/gconv/gconv-modules.cache and: Unauthorized port: php-fpm should be gone. NotesThis does not disable the CWP security audit. It only fixes two false-positive conditions: missing allowed path for /usr/lib64/gconv/, unsafe parsing of listening ports from generic lsof output. The script also keeps backups of any CWP-provided version that gets overwritten, so you can later compare what changed after an update: ls -lah /root/cwp-overrides/backups/ This approach is safer than using: chattr +i /scripts/cwp_security_audit because CWP updates are not blocked. The update can complete normally, and the local fixed version is restored afterwards.
  17. This phenomenon typically occurs after a MariaDB upgrade.Typical log fragments in the maillog: warning: connect to 127.0.0.1:10031: Connection timed out warning: problem talking to server 127.0.0.1:10031 451 4.3.5 Recipient address rejected: Server configuration problem install_driver(mysql) failed: Can't locate DBD/mysql.pmThis indicates that cbpolicyd (Cluebringer) cannot load the required Perl database driver. Root CausePolicyd relies on a Perl DBI driver to connect to its MariaDB/MySQL backend. If the DBD::mysql module is removed or mismatched, Policyd child processes exit with status 2, and Postfix rejects all RCPT requests due to policy service timeout. AlmaLinux 8 vs AlmaLinux 9 BehaviorAlmaLinux 8 (EL8)Policyd requires: perl-DBD-MySQL The configuration remains in /etc/cbpolicyd/cbpolicyd.conf DSN=DBI:mysql:database=postfix_policyd;host=localhostInstalling perl-DBD-MySQL resolves the issue. AlmaLinux 9 (EL9)EL9 introduces a packaging change where installing perl-DBD-MySQL may attempt to pull MySQL 8 libraries that conflict with MariaDB. Instead, install: dnf install perl-DBD-MariaDBThen update the Policyd configuration: Edit: /etc/cbpolicyd/cbpolicyd.confReplace: DSN=DBI:mysql:database=postfix_policyd;host=localhostWith: DSN=DBI:MariaDB:database=postfix_policyd;host=localhostThis forces Policyd to load the DBD::MariaDB driver instead of DBD::mysql. After modification: systemctl restart cbpolicyd systemctl restart postfixKey TakeawayEL8 → install perl-DBD-MySQL EL9 → install perl-DBD-MariaDB and change the DSN driver in /etc/cbpolicyd/cbpolicyd.conf Failure to update the DSN on EL9 will cause continuous Policyd crashes and complete mail flow disruption. This distinction is critical for maintaining stable CWP mail servers after MariaDB upgrades or package maintenance.
  18. Still CWP Pro with EL9 based op.system. It's true that it needs some tweaking after installation, but it still offers far better services than other alternatives.
  19. @SubZero5 Something was missing to run the installation script, but I can't see what it is.
  20. There was some change: https://www.alphagnu.com/topic/618-imagemagick-install-script-for-almalinux-9x-and-cwp/
  21. There was some change in the availability of ImageMagick, so the PHP 8.4 and 8.5 installation script needed to be corrected. #!/bin/bash # Detect PHP FPM version PHPFPM="/opt/alt/php-fpm84" if [ ! -e "${PHPFPM}/usr/bin/php-config" ]; then PHPFPM="/opt/alt/php-fpm85" fi PHPBIN="${PHPFPM}/usr/bin/php" PHPCONFIG="${PHPFPM}/usr/bin/php-config" PHPINIDIR="${PHPFPM}/usr/php/php.d" if [ ! -x "${PHPCONFIG}" ]; then echo "Skipping Imagick: php-config not found (${PHPCONFIG})" exit 0 fi echo "Installing prerequisites..." dnf -y install ImageMagick ImageMagick-devel ImageMagick-perl pkgconfig cd /usr/local/src rm -rf imagick-* echo "Downloading imagick-3.8.1..." wget https://pecl.php.net/get/imagick -O imagick.tgz tar -xf imagick.tgz cd imagick-* echo "phpize..." ${PHPFPM}/usr/bin/phpize echo "Configuring..." ./configure --with-php-config=${PHPCONFIG} echo "Compiling..." make -j"$(nproc)" && make install EXTDIR="$(${PHPCONFIG} --extension-dir)" if [ -e "${EXTDIR}/imagick.so" ]; then echo "Creating imagick.ini" echo "extension=imagick.so" > "${PHPINIDIR}/imagick.ini" echo "Imagick installation OK." else echo "ERROR: imagick.so missing: ${EXTDIR}/imagick.so" fi The place of the script is: /usr/local/cwpsrv/htdocs/resources/conf/el9/php-fpm_selector/external_modules/8.4
  22. Not fully. I will review these as well, because they should be in my own systems, but sometimes it gets delayed.
  23. E.g: Pre run module for Imap (PHP-FPM 8.4, 8.5) and the compiler takes care of the rest. The Pre run modules place is: /usr/local/cwpsrv/htdocs/resources/conf/el9/php-fpm_selector/pre_run/8.4/imap7.sh #/bin/bash dnf install uw-imap-devel -yEnd External module for MailParse (PHP-FPM 8.4, 8.5) #!/bin/bash set -euo pipefail # --- Detect PHP-FPM version (8.4 or 8.5) --- if [ -x /opt/alt/php-fpm84/usr/bin/php-config ]; then PHPFPM="/opt/alt/php-fpm84" elif [ -x /opt/alt/php-fpm85/usr/bin/php-config ]; then PHPFPM="/opt/alt/php-fpm85" else echo "ERROR: No php-fpm84 or php-fpm85 found." exit 1 fi PHPBIN="${PHPFPM}/usr/bin/php" PHPCONFIG="${PHPFPM}/usr/bin/php-config" PHPINIDIR="${PHPFPM}/usr/php/php.d" echo "Detected PHP: ${PHPBIN}" # --- Install dependencies --- dnf -y install re2c file cd /usr/local/src rm -rf mailparse* mailparse.tgz # --- Stable version: mailparse 3.1.6 --- MAILPARSE_VERSION="3.1.6" MAILPARSE_URL="https://pecl.php.net/get/mailparse-${MAILPARSE_VERSION}.tgz" echo "Downloading mailparse ${MAILPARSE_VERSION}..." wget -q "${MAILPARSE_URL}" -O mailparse.tgz tar -xf mailparse.tgz cd "mailparse-${MAILPARSE_VERSION}" # --- Build --- echo "Running phpize..." "${PHPFPM}/usr/bin/phpize" echo "Configuring..." ./configure --with-php-config="${PHPCONFIG}" echo "Compiling..." make -j"$(nproc)" make install # --- Check extension installation --- EXTDIR="$(${PHPCONFIG} --extension-dir)" if [ -f "${EXTDIR}/mailparse.so" ]; then echo "Creating mailparse.ini" echo "extension=mailparse.so" > "${PHPINIDIR}/mailparse.ini" echo "mailparse installed successfully." else echo "ERROR: mailparse.so was not found in ${EXTDIR}" exit 1 fi I hope this helped. Look at the full article: https://www.alphagnu.com/topic/614-how-to-add-custom-php-fpm-84-85-support-to-cwp-on-almalinux-9x/

Account

Navigation

Search

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.