Build and install M7 Crypto on AlmaLinux

This walkthrough installs the optional M7 C Crypto library and M7 PHP Crypto extension for PHP 8.4 NTS on AlmaLinux 10. It takes you from development packages through compilation, correctness and memory tests, installation and PHP-FPM activation. The example build account is m7, with home /home/m7. These are intentional public example paths, not requirements to reproduce an M7 server layout.

For another distribution, your local LLM or administrator can adapt the package names, tool paths, service names and security labels. Preserve the dependency order, matching PHP build tools and test gates. An adapted command sequence is not evidence of platform support until it passes on that platform.

Version status: these examples use the reviewed 0.3.0 development candidates. Final releases and public download verification are pending. The procedure follows earlier AlmaLinux installation experience and current 0.3.0 build/test interfaces; this complete 0.3.0 Linux walkthrough has not yet been executed and accepted. Do not treat older Linux results or the successful macOS candidate checks as its acceptance result.

When you need this optional path

Ordinary Identity SDK use keeps its PHP 8.1+ baseline and supported PHP OpenSSL paths. Install M7 Crypto when selecting a feature that needs it, including the SDK's additional native signature profiles, local HMAC verification or encrypted responses. The current extension initially targets PHP 8.4 NTS, non-debug; this is not an installation path for PHP 8.1–8.3. Broader PHP support is later work.

Once the extension is installed and loaded in the application's PHP process, the SDK detects it when a configured operation needs the native backend. There is no separate backend-selection switch. You still select trusted allowed_algs, supply the appropriate keys/secrets, and explicitly configure encryption recipients and policy. Installing a module does not enable algorithms, change client registration or turn encryption on. Required native operations fail if the module or provider is unavailable; validation is never bypassed.

A possible custom PHP 8.5 port

PHP 8.5 adds a padding parameter to openssl_sign and an OAEP digest parameter to openssl_public_encrypt. These additions may let a custom SDK adaptation replace some M7 Crypto calls with PHP OpenSSL calls. The current SDK does not implement that alternative, and PHP 8.5 alone does not remove its native dependency for these features.

Full parity with M7 Crypto has not been established. A port must verify the exact algorithms and provider support, RSA-PSS/OAEP parameters, ECDSA signature encoding, Edwards/ML-DSA behavior, key formats, errors and rejection tests it needs. Re-run SDK conformance and application interoperability tests. Do not assume that a new PHP version or similarly named operation is interchangeable.

1. Check OpenSSL and install development tools

First check the OS and OpenSSL installation:

cat /etc/os-release
uname -m
openssl version -a
rpm -q openssl openssl-libs openssl-devel

The C library needs OpenSSL 3.0+, including development headers and libraries. This walkthrough runs the complete algorithm suite, including ML-DSA, so use OpenSSL 3.5+ with an available ML-DSA provider. Having an OpenSSL executable alone does not supply its development headers. See the OpenSSL ML-DSA contract.

As an administrator, install the compiler, build tools and test tools:

sudo dnf install gcc make pkgconf-pkg-config openssl-devel autoconf \
  libasan libubsan valgrind nodejs tar gzip policycoreutils-python-utils

Review the transaction. Keep openssl-devel and the installed OpenSSL runtime from compatible packages; do not replace the system crypto stack with an unrelated build to satisfy a test. Sanitizer runtimes and Valgrind are memory test tools. Node.js is used for an independent encryption interoperability test; they are not extension runtime dependencies.

This example uses AlmaLinux's versioned PHP 8.4 package family. Check what the enabled repositories supply before installing it:

dnf info php8.4-cli php8.4-devel php8.4-fpm

For a new PHP 8.4 installation from that package family:

sudo dnf install php8.4-cli php8.4-devel php8.4-fpm

If PHP is already installed, identify its owner first:

command -v php phpize php-config
rpm -qf "$(readlink -f "$(command -v php)")"

Install the matching development package from that same PHP provider and version/release. A phpize executable can exist while its headers or php-config are missing. Generic php-devel, versioned php8.4-devel and third-party parallel PHP packages are not interchangeable. If the packages above are unavailable, stop and resolve the PHP 8.4 package/toolchain selection; do not silently build against another PHP version or switch an existing site's PHP runtime. PHP's phpize guide explains selecting a matching php-config.

2. Use a build account and establish paths

Compile and run tests as the ordinary m7 account. Create it only if it does not already exist, using an administrator account:

if ! id m7 >/dev/null 2>&1; then
  sudo useradd --create-home --home-dir /home/m7 --shell /bin/bash m7
fi
getent passwd m7

Open a Bash login shell as m7 (sudo -iu m7 from an administrator shell). Use this same shell for the following steps. Lines using sudo are privileged installation actions; an administrator can run those lines if the build account does not have sudo permission.

export m7_crypto_version=0.3.0
export m7_crypto_downloads=/home/m7/downloads
export m7_crypto_src=/home/m7/src
export m7_crypto_c="$m7_crypto_src/m7-c-crypto-$m7_crypto_version"
export m7_crypto_php="$m7_crypto_src/m7-php-crypto-$m7_crypto_version"
export m7_crypto_prefix="/opt/m7/crypto/$m7_crypto_version"
export m7_crypto_run=$(date -u +%Y%m%dT%H%M%SZ)
export m7_crypto_logs="$m7_crypto_src/validation/m7-crypto-$m7_crypto_version-$m7_crypto_run"
export m7_php=/usr/bin/php
export m7_phpize=/usr/bin/phpize
export m7_php_config=/usr/bin/php-config
export m7_openssl=/usr/bin/openssl
mkdir -p "$m7_crypto_downloads" "$m7_crypto_src" "$m7_crypto_logs"

Change the four executable paths if your selected PHP/OpenSSL packages install elsewhere. Each execution block below uses a Bash subshell with set -euo pipefail: a failure stops that block, including failures piped to tee. Read its log and fix the cause before proceeding to the next block. After reconnecting, restore these variables; retain the original log-directory value when continuing the same run.

Location Purpose
/home/m7/downloads/ Reviewed archives and integrity sidecars
/home/m7/src/ Unprivileged source builds and validation logs
/opt/m7/crypto/0.3.0/include/ and lib/ Root-owned C header and normal shared library
/opt/m7/crypto/0.3.0/php/ Root-owned PHP module linked to that same C prefix
/etc/php.d/20-m7crypto.ini Extension entry, after confirming the target runtime scans this directory
/var/backups/m7crypto/ Previous extension configuration for rollback

Confirm the toolchain before building:

(
set -euo pipefail
cc --version
pkg-config --modversion libcrypto
pkg-config --cflags --libs libcrypto
pkg-config --atleast-version=3.0 libcrypto
pkg-config --atleast-version=3.5 libcrypto
"$m7_openssl" list -signature-algorithms | tee "$m7_crypto_logs/openssl-algorithms.log"
"$m7_php" -n -r '
if (PHP_MAJOR_VERSION !== 8 || PHP_MINOR_VERSION !== 4 || PHP_ZTS || PHP_DEBUG) {
    fwrite(STDERR, "This walkthrough requires PHP 8.4 NTS, non-debug.\n"); exit(1);
}
echo PHP_VERSION, "\n", OPENSSL_VERSION_TEXT, "\n";'
"$m7_phpize" --version
test "$("$m7_php_config" --phpapi)" = 20240924
test "$("$m7_php_config" --version)" = "$("$m7_php" -n -r 'echo PHP_VERSION;')"
"$m7_php_config" --extension-dir
)

The second pkg-config version check enforces this walkthrough's full-profile test target, not the library's minimum 3.0 build requirement. Confirm ML-DSA appears in the provider output and that phpize reports module API 20240924. If pkg-config selects a custom OpenSSL, set its PKG_CONFIG_PATH deliberately and verify compatibility with PHP's OpenSSL; a version string alone is not proof that the dynamic loader will select the intended library.

3. Verify and extract both source bundles

Place each reviewed .tar.gz, .tar.gz.sha256 and .tar.gz.manifest.json in /home/m7/downloads/. See the C release status and PHP release status for availability. Until final downloads are verified, use only the reviewed candidate files supplied through a trusted channel; the version in these examples is not a promise that a public URL exists.

(
set -euo pipefail
cd "$m7_crypto_downloads"
sha256sum -c "m7-c-crypto-$m7_crypto_version.tar.gz.sha256"
sha256sum -c "m7-php-crypto-$m7_crypto_version.tar.gz.sha256"
tar -tvzf "m7-c-crypto-$m7_crypto_version.tar.gz"
tar -tvzf "m7-php-crypto-$m7_crypto_version.tar.gz"
)

Stop on any mismatch. Review the listings before extraction: each archive must have its single matching versioned root, with no parent traversal, absolute paths, symlinks or unexpected payload. A checksum verifies agreement with the sidecar; publisher trust comes from the channel supplying both.

(
set -euo pipefail
test ! -e "$m7_crypto_c"
test ! -e "$m7_crypto_php"
tar --no-same-owner --no-same-permissions -xzf \
  "$m7_crypto_downloads/m7-c-crypto-$m7_crypto_version.tar.gz" -C "$m7_crypto_src"
tar --no-same-owner --no-same-permissions -xzf \
  "$m7_crypto_downloads/m7-php-crypto-$m7_crypto_version.tar.gz" -C "$m7_crypto_src"
cmp "$m7_crypto_downloads/m7-c-crypto-$m7_crypto_version.tar.gz.manifest.json" "$m7_crypto_c/MANIFEST.json"
cmp "$m7_crypto_downloads/m7-php-crypto-$m7_crypto_version.tar.gz.manifest.json" "$m7_crypto_php/MANIFEST.json"
(cd "$m7_crypto_c" && sha256sum -c CHECKSUMS.sha256)
(cd "$m7_crypto_php" && sha256sum -c CHECKSUMS.sha256)
test "$(cat "$m7_crypto_c/VERSION")" = "$m7_crypto_version"
test "$(cat "$m7_crypto_php/VERSION")" = "$m7_crypto_version"
)

Use fresh directories for a new attempt rather than extracting over an old build. The source bundle also includes scripts/release.py verify --integrity-only for complete inventory/reproducibility checks; it requires Python 3.10+. Neither checksums nor successful extraction establish runtime correctness.

4. Build and test the C library

(
set -euo pipefail
cd "$m7_crypto_c"
make -j2 2>&1 | tee "$m7_crypto_logs/c-build.log"
M7CRYPTO_REQUIRE_ML_DSA=1 make test 2>&1 | tee "$m7_crypto_logs/c-tests.log"
ldd build/libm7crypto.so | tee "$m7_crypto_logs/c-linkage.log"
! grep -q 'not found' "$m7_crypto_logs/c-linkage.log"
)

The normal library is build/libm7crypto.so. The four executables test PSS, signing families, generation/export and encryption; make test also runs the key-generation and encryption provider-failure cases. Require all PASS results and a successful exit. M7CRYPTO_REQUIRE_ML_DSA=1 makes missing ML-DSA support a failure instead of an acceptable skip. Fixtures use disposable test keys.

Check C memory handling

(
set -euo pipefail
cd "$m7_crypto_c"
M7CRYPTO_REQUIRE_ML_DSA=1 \
ASAN_OPTIONS=detect_leaks=1:halt_on_error=1 \
UBSAN_OPTIONS=halt_on_error=1 \
  make sanitize 2>&1 | tee "$m7_crypto_logs/c-sanitizers.log"
)

This builds a separate instrumented library and tests under build/sanitize. AddressSanitizer checks invalid memory access and leaks; UBSan checks undefined behavior. Require successful tests with no sanitizer diagnostics. A missing sanitizer runtime, unsupported instrumentation or skipped run is not a pass. Use a fresh build when changing compilers or flags. Install the normal library, not the instrumented one. Passing these tests checks exercised paths; it does not prove that no defect or leak can occur under every workload.

5. Install the tested C library at its final path

The PHP extension will link against this versioned prefix. Keep it at this location after linking; do not build against a temporary prefix and then move the library. These privileged commands only copy the tested normal output:

(
set -euo pipefail
test ! -e "$m7_crypto_prefix"
sudo install -d -o root -g root -m 0755 \
  "$m7_crypto_prefix/include" "$m7_crypto_prefix/lib" "$m7_crypto_prefix/php"
sudo install -o root -g root -m 0644 "$m7_crypto_c/include/m7crypto.h" "$m7_crypto_prefix/include/m7crypto.h"
sudo install -o root -g root -m 0755 "$m7_crypto_c/build/libm7crypto.so" "$m7_crypto_prefix/lib/libm7crypto.so"
cmp "$m7_crypto_c/build/libm7crypto.so" "$m7_crypto_prefix/lib/libm7crypto.so"
ldd "$m7_crypto_prefix/lib/libm7crypto.so"
)

The fresh-prefix check prevents accidental replacement of an existing version. If it already exists, inspect that installation and its provenance before continuing; do not delete it merely to make the command pass. Keep prior versions for rollback. Applications must not be able to modify installed libraries or their parent directories. C-only consumers can stop after validating their own program against this header/library; the remaining steps install PHP support.

6. Build the matching PHP extension

(
set -euo pipefail
cd "$m7_crypto_php"
"$m7_phpize" 2>&1 | tee "$m7_crypto_logs/phpize.log"
mkdir build-alma
cd build-alma
../configure --with-php-config="$m7_php_config" \
  --with-m7crypto="$m7_crypto_prefix" 2>&1 | tee "$m7_crypto_logs/php-configure.log"
make -j2 2>&1 | tee "$m7_crypto_logs/php-build.log"
)
export m7_crypto_module="$m7_crypto_php/build-alma/modules/m7crypto.so"

phpize prepares the extension build; configure selects the PHP ABI and the installed C header/library; make produces the module. No PHP configuration has been changed yet. The declaration stub is not a runtime PHP implementation.

(
set -euo pipefail
ldd "$m7_crypto_module" | tee "$m7_crypto_logs/php-linkage.log"
! grep -q 'not found' "$m7_crypto_logs/php-linkage.log"
grep -F "$m7_crypto_prefix/lib/libm7crypto.so" "$m7_crypto_logs/php-linkage.log"
"$m7_php" -n -d "extension=$m7_crypto_module" --ri m7crypto
"$m7_php" -n -d "extension=$m7_crypto_module" -r \
  'exit(phpversion("m7crypto") === "0.3.0" ? 0 : 1);'
)

Require extension version 0.3.0, backend external libm7crypto, and the exact versioned C library path. Also inspect libcrypto resolution for compatibility with PHP. A stale C library, missing getter or wrong PHP ABI must be fixed before continuing. -n ignores normal INI files so this check loads only the selected module, even if an older installation is enabled for ordinary PHP commands.

7. Run PHP correctness and interoperability tests

(
set -euo pipefail
cd "$m7_crypto_php/build-alma"
TEST_PHP_EXECUTABLE="$m7_php" M7CRYPTO_TEST_OPENSSL="$m7_openssl" \
M7CRYPTO_TEST_PREFIX="$m7_crypto_prefix" NO_INTERACTION=1 REPORT_EXIT_STATUS=1 \
  make test TESTS="$m7_crypto_php/tests" 2>&1 | tee "$m7_crypto_logs/php-tests.log"
grep -Eq 'Tests passed[[:space:]]*:[[:space:]]*6([[:space:]]|$)' "$m7_crypto_logs/php-tests.log"
! grep -Eq 'Tests (failed|warned|skipped)[[:space:]]*:[[:space:]]*[1-9]' "$m7_crypto_logs/php-tests.log"
PHP_BINARY="$m7_php" M7CRYPTO_TEST_MODULE="$m7_crypto_module" \
  node "$m7_crypto_php/tests/encryption_interop.mjs" 2>&1 | tee "$m7_crypto_logs/php-node-interop.log"
)

Require six PHPT passes, zero failures/warnings/skips, and successful Node interoperability. The PHPT cases cover the API, signing, cleanup, PHP allocation bailout, generation/export and encryption. The bailout case deliberately induces a child-process failure and verifies cleanup; the parent test must still PASS. The Node check independently exercises OAEP and test-only nested-JWT composition. It does not establish that a production Identity SDK integration is configured.

8. Check PHP/native memory cleanup with Valgrind

Use the normal, unsanitized module and C library. Do not combine this run with the C ASan build. USE_ZEND_ALLOC=0 exposes PHP process allocations to Memcheck. The drivers test both explicit close/destruction and request-shutdown cleanup.

(
set -euo pipefail
cd "$m7_crypto_php/build-alma"
run_memory_check() {
  local driver=$1 variable=$2 cycles=$3 result
  if env USE_ZEND_ALLOC=0 M7CRYPTO_TEST_OPENSSL="$m7_openssl" \
    M7CRYPTO_TEST_PREFIX="$m7_crypto_prefix" "$variable=$cycles" \
    valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all \
      --errors-for-leak-kinds=definite,indirect,possible --error-exitcode=1 \
      --child-silent-after-fork=yes --log-file="$m7_crypto_logs/$driver.memcheck.log" \
      "$m7_php" -n -d "extension=$m7_crypto_module" \
      "$m7_crypto_php/tests/$driver.inc.php" \
      > "$m7_crypto_logs/$driver.output.log" 2>&1; then
    result=0
  else
    result=$?
  fi
  printf 'Exit status: %s\n' "$result" | tee "$m7_crypto_logs/$driver.status"
  cat "$m7_crypto_logs/$driver.output.log"
  tail -n 25 "$m7_crypto_logs/$driver.memcheck.log"
  test "$result" -eq 0
  grep -q '^PASS:' "$m7_crypto_logs/$driver.output.log"
}
run_memory_check stress M7CRYPTO_STRESS_ITERATIONS 1000
run_memory_check keygen_stress M7CRYPTO_KEYGEN_ITERATIONS 3
run_memory_check encryption_stress M7CRYPTO_ENCRYPTION_ITERATIONS 1000
)

Signing repeatedly imports, signs, verifies, rejects tampering and frees keys. Generation repeatedly creates and exports keys for all asymmetric profiles; three cycles per profile keeps this expensive check manageable. Encryption runs 1000 OAEP round trips, rejection and cleanup cycles. Increase counts for longer stress testing after the baseline passes.

For each driver, retain its PASS output, exit status 0, and Memcheck report. Require zero memory errors and zero definitely, indirectly or possibly lost bytes. still reachable allocations are a separate category, often from process-lifetime PHP/OpenSSL state; review them rather than reporting every reachable allocation as a leak or hiding findings with blanket suppressions. See Memcheck's leak categories.

A PASS line alone is insufficient: a failure can occur during shutdown after that line. These commands preserve the final process status. A clean run means no counted errors were found in these tested paths, not a universal guarantee of memory safety. Missing tools, a timeout or an incomplete run remain untested.

9. Install the PHP module and apply SELinux labels

After all checks pass, copy the tested module into the same protected version prefix. This keeps both native components together and makes rollback an INI selection rather than overwriting a previous version's binaries.

(
set -euo pipefail
sudo install -o root -g root -m 0755 "$m7_crypto_module" "$m7_crypto_prefix/php/m7crypto.so"
cmp "$m7_crypto_module" "$m7_crypto_prefix/php/m7crypto.so"
"$m7_php" -n -d "extension=$m7_crypto_prefix/php/m7crypto.so" --ri m7crypto
)

Check getenforce and existing local file-context rules. On an enforcing AlmaLinux installation, the versioned lib and php directories hold shared libraries. If no equivalent rule exists, record a persistent label rule and apply it:

getenforce
sudo semanage fcontext -l | grep '/opt/m7/crypto'
# Add once, only when this rule is absent:
sudo semanage fcontext -a -t lib_t '/opt/m7/crypto/[^/]+/(lib|php)(/.*)?'
sudo restorecon -Rv "$m7_crypto_prefix"
ls -lZ "$m7_crypto_prefix/lib/libm7crypto.so" "$m7_crypto_prefix/php/m7crypto.so"
matchpathcon -V "$m7_crypto_prefix/lib/libm7crypto.so" "$m7_crypto_prefix/php/m7crypto.so"

An empty grep result means no matching rule was listed. If the exact rule already exists, inspect/reuse it; use semanage fcontext -m only when intentionally correcting that rule. Do not disable SELinux. For a real service denial, inspect the audit record with sudo ausearch -m AVC,USER_AVC -ts recent and correct the specific label or policy issue. CLI loading alone does not prove service access.

10. Enable the extension and verify the real PHP service

Run "$m7_php" --ini and inspect the target FPM configuration before choosing an INI path. This example uses /etc/php.ini plus /etc/php.d/, as in the standard AlmaLinux layout. Adapt the path if your PHP package uses another scan directory. There must be exactly one effective m7crypto extension entry.

"$m7_php" --ini
grep -nE '^[[:space:]]*extension[[:space:]]*=.*m7crypto' /etc/php.ini /etc/php.d/*.ini

No match is normal for a first installation. If an older entry exists elsewhere, back it up and consolidate the effective configuration before adding another. Use these variables only after confirming the target directory:

export m7_crypto_ini=/etc/php.d/20-m7crypto.ini
export m7_crypto_backup="/var/backups/m7crypto/$m7_crypto_run"
(
set -euo pipefail
sudo install -d -o root -g root -m 0700 "$m7_crypto_backup"
if sudo test -f "$m7_crypto_ini"; then
  sudo cp -a "$m7_crypto_ini" "$m7_crypto_backup/20-m7crypto.ini"
else
  sudo touch "$m7_crypto_backup/no-previous-ini"
fi
printf 'extension=%s/php/m7crypto.so\n' "$m7_crypto_prefix" > "$m7_crypto_logs/20-m7crypto.ini"
sudo install -o root -g root -m 0644 "$m7_crypto_logs/20-m7crypto.ini" "$m7_crypto_ini"
sudo restorecon -v "$m7_crypto_ini"
"$m7_php" --ri m7crypto
)

Verify the existing PHP-FPM service's executable and configuration, then reload it. These commands target the conventional php-fpm service; substitute the actual service and executable for a parallel PHP installation.

(
set -euo pipefail
systemctl show -p ExecStart php-fpm
sudo /usr/sbin/php-fpm -t
sudo /usr/sbin/php-fpm -i | grep -E 'PHP Version|Loaded Configuration|Scan this dir|m7crypto|Extension version|Crypto backend'
sudo systemctl reload php-fpm
systemctl is-active --quiet php-fpm
sudo journalctl -u php-fpm --since '5 minutes ago' --no-pager
)

This assumes the site's FPM service already exists and is running. For a new site, finish its FPM pool/web-server setup before starting the service. Apache usually proxies PHP to FPM on this platform, so it is the FPM workers that need the reload. If your site instead uses mod_php, check the matching Apache/PHP build, run sudo httpd -t, then sudo systemctl reload httpd and verify a real request in that runtime. A shell PHP success is not a web-runtime test.

Save this generated-key smoke check as /home/m7/src/m7crypto-smoke.php:

<?php
declare(strict_types=1);

use M7\Crypto\Key;

if (!extension_loaded('m7crypto') || !class_exists(Key::class, false)
    || phpversion('m7crypto') !== '0.3.0') {
    throw new RuntimeException('Expected m7crypto 0.3.0');
}
$signing = null;
$recipient = null;
try {
    $signing = Key::generate('Ed25519');
    $message = 'installation smoke check';
    $signature = $signing->sign($message, 'Ed25519');
    if ($signing->verify($message, $signature, 'Ed25519') !== true) {
        throw new RuntimeException('Signature check failed');
    }
    $recipient = Key::generate('RSA-OAEP-256', 2048);
    $secret = random_bytes(32);
    $ciphertext = $recipient->encrypt($secret, 'RSA-OAEP-256');
    if (!hash_equals($secret, $recipient->decrypt($ciphertext, 'RSA-OAEP-256'))) {
        throw new RuntimeException('Encryption check failed');
    }
    echo 'PASS: m7crypto signing and encryption; SAPI=', PHP_SAPI, "\n";
} finally {
    $signing?->close();
    $recipient?->close();
}

Run "$m7_php" /home/m7/src/m7crypto-smoke.php without -n or a module override. Then run the same check through a temporary, access-restricted diagnostic route in the actual application worker. The result should report the expected SAPI and PASS; remove that route afterward. Do not expose phpinfo(), generated keys or application credentials. Finally test the application's selected SDK feature with its explicit policy and keys. Primitive success is not token-validation or end-to-end login acceptance.

11. Roll back if activation fails

Keep the previous versioned C/PHP pair until the application passes. Restore the saved INI, or remove the new dedicated entry only for a first installation:

(
set -euo pipefail
if sudo test -f "$m7_crypto_backup/20-m7crypto.ini"; then
  sudo cp -a "$m7_crypto_backup/20-m7crypto.ini" "$m7_crypto_ini"
elif sudo test -f "$m7_crypto_backup/no-previous-ini"; then
  sudo rm -- "$m7_crypto_ini"
else
  printf 'No recorded previous configuration; inspect before changing it.\n' >&2
  exit 1
fi
if sudo test -f "$m7_crypto_ini"; then sudo restorecon -v "$m7_crypto_ini"; fi
sudo /usr/sbin/php-fpm -t
sudo systemctl reload php-fpm
systemctl is-active --quiet php-fpm
)

Use the same actual service choice as activation, and recheck the application. On a first-install rollback, also revert any application change that newly requires native crypto; never turn a failed verification or required encrypted response into success. Do not delete libraries still used by running processes.

What to retain from a successful run

Keep the archive digests, OS/CPU, compiler, PHP/API/NTS/debug and OpenSSL/provider versions, exact installed prefix, build/test logs, sanitizer report, all three Valgrind outputs/statuses and the application-worker result. The final state is a tested installed pair; public artifact release and deployment of SDK features remain separate decisions.

Return to M7 PHP Crypto, general installation, or Identity SDK native-runtime guidance.