OneLinersCommand workbench
Guides
Security / Services & Applications

Harden PHP-FPM with systemd service controls

Measure the current unit, add compatible filesystem and privilege restrictions, validate application paths, and roll out hardening without breaking package upgrades.

50 min8 stepsChanges system stateRevision 2
Save or explore
Save to collectionCreate a collection in the sidebar first.
0 of 8 steps completed
Goal

Reduce the impact of a compromised PHP worker while preserving required application writes and networking.

Supported environments
  • systemd 252+
Prerequisites
  • Supported host and recovery access Use a supported distribution, keep an independent root-capable session, and record the current package repositories before changing the PHP runtime.cat /etc/os-release && uname -m
  • Application compatibility Confirm the application, framework, extensions, and deployment tooling explicitly support the target PHP branch.
  • Configuration backup Archive the active PHP, web-server, and application configuration before packages, pools, or handlers change.
Operating boundary

OneLiners never runs these steps or stores secrets. Review placeholders, versions, current state, and change-control requirements before using a command.

Full guide

What you will build

System
  • A package-safe systemd drop-in that reduces PHP-FPM kernel, device, namespace, filesystem and privilege exposure.
  • A measured writable-path and address-family allowlist derived from real application behavior rather than a copied hardening score.
  • A staged validation, denial-observation and rollback workflow preserving application health and package upgrades.
Observable outcome
  • The FPM unit receives a materially improved exposure assessment without losing required sessions, uploads, caches, logs, DNS, database or upstream access.
  • Every remaining privilege and every write/network exception has an application owner, evidence and review date.

Architecture

How the parts fit together

systemd starts the packaged PHP-FPM service and merges an administrator-owned drop-in without modifying the vendor unit. Process restrictions reduce privilege gain and kernel interfaces; filesystem protections make the host read-only except for enumerated state paths; address-family and device controls remove unused interfaces. A representative workload and journal review reveal compatibility gaps. The original vendor unit and prior drop-in remain recoverable through `systemctl revert`.

Vendor unitDefines the package-supported service lifecycle and remains untouched.
Administrator drop-inAdds reversible hardening controls under /etc/systemd/system.
Application allowlistsEnumerate required writable paths, address families and runtime interfaces.
Canary and journal evidenceProve required behavior and expose denied operations before broad rollout.
  1. Capture unit composition, process behavior and security score before changing policy.
  2. Map legitimate writes and network/device requirements with a representative workload.
  3. Add controls in compatible groups, verify unit syntax and restart only in a protected window.
  4. Exercise all capabilities, inspect denials and either narrow exceptions or revert the drop-in.

Assumptions

  • The host uses a supported systemd release and the exact PHP-FPM service/pool/application identity is known.
  • Console or out-of-band recovery and a maintenance/canary path are available before service restart.
  • Application owners can exercise reads, writes, sessions, uploads, database/DNS/upstream access and background behavior.
  • Writable paths are outside immutable releases and have explicit ownership and capacity controls.

Key concepts

drop-in
An administrator-owned unit fragment merged with the vendor unit, preserving package upgrade visibility and rollback.
ProtectSystem
A systemd filesystem control that can make operating-system paths read-only with explicit write exceptions.
NoNewPrivileges
A process rule preventing children from gaining privileges through setuid, file capabilities or similar mechanisms.
address-family restriction
An allowlist of socket families a service may create, which must retain every required local/network protocol.

Before you copy

Values used in this guide

{{app}}

Short application identifier used in service, pool, directory, and configuration names.

Example: billing
{{appUser}}

Non-login operating-system identity used by the application workers.

Example: billing
{{domain}}

Fully qualified public or internal hostname served by this configuration.

Example: billing.example.com
{{phpVersion}}

Exact PHP major and minor branch used by the target runtime.

Example: 8.3
{{safeFixture}}

Small non-sensitive test file used to exercise an upload or parser path.

Example: /srv/billing/fixtures/upload.txt

Security and production boundaries

  • A lower `systemd-analyze security` score is guidance, not proof; workload checks and narrow exceptions decide whether the policy is safe.
  • Never add broad `/`, `/etc`, `/usr` or entire application roots to ReadWritePaths just to suppress a denial.
  • Preserve denial logs and review extension behavior because native modules execute inside the worker security boundary.

Stop before continuing if

  • Stop if the baseline cannot identify required paths/network behavior, recovery access is absent, or the unit verification reports unknown directives.
  • Immediately revert when health, sessions, uploads, logs, name resolution, database or required upstream calls fail after restart.
01

instruction

Capture the packaged unit and security score

read-only

Record vendor unit contents, drop-ins, dynamic properties, filesystem use, and systemd-analyze security output before adding restrictions.

Why this step matters

Capture the packaged unit and security score is a separate checkpoint because it establishes one auditable part of reduce the impact of a compromised php worker while preserving required application writes and networking. Performing it independently keeps a failed prerequisite, syntax error, or compatibility mismatch from being hidden by later actions.

What to understand

Record vendor unit contents, drop-ins, dynamic properties, filesystem use, and systemd-analyze security output before adding restrictions. Read the complete command or configuration before execution, replace the documented placeholders, and compare the target host with the supported environments listed at the beginning of this tutorial.

Capture the before-state and the exact output in the change record. If this step modifies a file or service, validate the candidate with its native checker before any reload; a successful process exit alone does not prove that the application uses the intended value.

Use a representative staging or canary host first. Repeat the stated checkpoint immediately, because proceeding with ambiguous evidence makes the later end-to-end verification and rollback materially harder.

System changes

  • This step may affect the files, packages, identities, services, or runtime policy named in “Capture the packaged unit and security score”. The scope must remain limited to the selected application and supported host.

Syntax explained

systemctl
Invokes the principal tool or configuration operation for “Capture the packaged unit and security score”; confirm that it resolves to the expected packaged executable or file before using elevated privileges.
{{…}}
Marks an operator-supplied value. Replace every placeholder deliberately; do not paste untrusted text or leave braces in the production command.
Command
Fill variables0/1 ready

Values stay on this page and are never sent or saved.

systemctl cat php{{phpVersion}}-fpm; systemctl show php{{phpVersion}}-fpm > /tmp/php-fpm-unit-before.txt; systemd-analyze security php{{phpVersion}}-fpm.service
Example output / evidence
Unit baseline and exposure score are recorded.

Checkpoint: Checkpoint: Capture the packaged unit and security score

Continue whenUnit baseline and exposure score are recorded. Treat this concrete evidence as the minimum success signal and also confirm that unrelated services and the previous healthy path remain unchanged.

Stop whenStop before the next step when systemctl reports an error, the output differs materially from the example, an unexpected package/service/path is affected, or the required before-state and rollback artifact are missing.

If this step fails

The command for “Capture the packaged unit and security score” fails, produces no useful evidence, or the expected service/configuration state is absent.

Likely causeA placeholder targets the wrong environment, the installed version uses another path or unit name, permissions are insufficient, or an earlier prerequisite was not satisfied.

Safe checks
  • command -v systemctl 2>/dev/null || true
  • systemctl --failed --no-pager 2>/dev/null || true
  • journalctl -p warning -n 50 --no-pager 2>/dev/null || true

ResolutionDo not improvise a privileged workaround. Re-read the environment and variable table, inspect the official source for the installed version, restore the candidate file if necessary, and repeat only this checkpoint.

Security notes

  • Keep secrets out of shell history, process arguments, screenshots, logs, and tutorial placeholders. Elevate only the narrow command that requires it and preserve package signature and TLS verification.

Alternatives

  • When the host layout or software version differs, use the vendor-supported equivalent in a disposable staging environment and document the mapping before touching production.

Stop conditions

  • Stop if the action broadens network exposure, permissions, package sources, writable paths, or service privileges beyond the tutorial's declared architecture.
02

instruction

Map required writable paths

read-only

Use application documentation and a representative test to list sockets, sessions, cache, uploads, logs, and release paths that FPM must modify.

Why this step matters

Map required writable paths is a separate checkpoint because it establishes one auditable part of reduce the impact of a compromised php worker while preserving required application writes and networking. Performing it independently keeps a failed prerequisite, syntax error, or compatibility mismatch from being hidden by later actions.

What to understand

Use application documentation and a representative test to list sockets, sessions, cache, uploads, logs, and release paths that FPM must modify. Read the complete command or configuration before execution, replace the documented placeholders, and compare the target host with the supported environments listed at the beginning of this tutorial.

Capture the before-state and the exact output in the change record. If this step modifies a file or service, validate the candidate with its native checker before any reload; a successful process exit alone does not prove that the application uses the intended value.

Use a representative staging or canary host first. Repeat the stated checkpoint immediately, because proceeding with ambiguous evidence makes the later end-to-end verification and rollback materially harder.

System changes

  • This step may affect the files, packages, identities, services, or runtime policy named in “Map required writable paths”. The scope must remain limited to the selected application and supported host.

Syntax explained

-u
Invokes the principal tool or configuration operation for “Map required writable paths”; confirm that it resolves to the expected packaged executable or file before using elevated privileges.
{{…}}
Marks an operator-supplied value. Replace every placeholder deliberately; do not paste untrusted text or leave braces in the production command.
|
Passes standard output to the next read-only inspection stage; review each stage separately if the combined result is surprising.
Command
Fill variables0/2 ready

Values stay on this page and are never sent or saved.

sudo -u {{appUser}} find /srv/{{app}} -xdev -type d -writable -printf '%m %u:%g %p\n'; sudo lsof -p "$(pgrep -o php-fpm)" 2>/dev/null | head -n 50
Example output / evidence
A minimal writable-path allowlist is documented.

Checkpoint: Checkpoint: Map required writable paths

Continue whenA minimal writable-path allowlist is documented. Treat this concrete evidence as the minimum success signal and also confirm that unrelated services and the previous healthy path remain unchanged.

Stop whenStop before the next step when -u reports an error, the output differs materially from the example, an unexpected package/service/path is affected, or the required before-state and rollback artifact are missing.

If this step fails

The command for “Map required writable paths” fails, produces no useful evidence, or the expected service/configuration state is absent.

Likely causeA placeholder targets the wrong environment, the installed version uses another path or unit name, permissions are insufficient, or an earlier prerequisite was not satisfied.

Safe checks
  • command -v -u 2>/dev/null || true
  • systemctl --failed --no-pager 2>/dev/null || true
  • journalctl -p warning -n 50 --no-pager 2>/dev/null || true

ResolutionDo not improvise a privileged workaround. Re-read the environment and variable table, inspect the official source for the installed version, restore the candidate file if necessary, and repeat only this checkpoint.

Security notes

  • Keep secrets out of shell history, process arguments, screenshots, logs, and tutorial placeholders. Elevate only the narrow command that requires it and preserve package signature and TLS verification.

Alternatives

  • When the host layout or software version differs, use the vendor-supported equivalent in a disposable staging environment and document the mapping before touching production.

Stop conditions

  • Stop if the action broadens network exposure, permissions, package sources, writable paths, or service privileges beyond the tutorial's declared architecture.
03

config

Create a package-safe systemd drop-in

caution

Use systemctl edit instead of modifying the vendor unit so package upgrades remain visible and reversible.

Why this step matters

Create a package-safe systemd drop-in is a separate checkpoint because it establishes one auditable part of reduce the impact of a compromised php worker while preserving required application writes and networking. Performing it independently keeps a failed prerequisite, syntax error, or compatibility mismatch from being hidden by later actions.

What to understand

Use systemctl edit instead of modifying the vendor unit so package upgrades remain visible and reversible. Read the complete command or configuration before execution, replace the documented placeholders, and compare the target host with the supported environments listed at the beginning of this tutorial.

Capture the before-state and the exact output in the change record. If this step modifies a file or service, validate the candidate with its native checker before any reload; a successful process exit alone does not prove that the application uses the intended value.

Use a representative staging or canary host first. Repeat the stated checkpoint immediately, because proceeding with ambiguous evidence makes the later end-to-end verification and rollback materially harder.

System changes

  • This step may affect the files, packages, identities, services, or runtime policy named in “Create a package-safe systemd drop-in”. The scope must remain limited to the selected application and supported host.

Syntax explained

systemctl
Invokes the principal tool or configuration operation for “Create a package-safe systemd drop-in”; confirm that it resolves to the expected packaged executable or file before using elevated privileges.
{{…}}
Marks an operator-supplied value. Replace every placeholder deliberately; do not paste untrusted text or leave braces in the production command.
/etc/systemd/system/php{{phpVersion}}-fpm.service.d/override.conf
Is the persistent configuration boundary changed by this step. Keep an attributable backup and validate the consumer before reload.
File /etc/systemd/system/php{{phpVersion}}-fpm.service.d/override.conf
Configuration
Fill variables0/1 ready

Values stay on this page and are never sent or saved.

sudo systemctl edit php{{phpVersion}}-fpm.service
Example output / evidence
A drop-in exists below /etc/systemd/system.

Checkpoint: Checkpoint: Create a package-safe systemd drop-in

Continue whenA drop-in exists below /etc/systemd/system. Treat this concrete evidence as the minimum success signal and also confirm that unrelated services and the previous healthy path remain unchanged.

Stop whenStop before the next step when systemctl reports an error, the output differs materially from the example, an unexpected package/service/path is affected, or the required before-state and rollback artifact are missing.

If this step fails

The command for “Create a package-safe systemd drop-in” fails, produces no useful evidence, or the expected service/configuration state is absent.

Likely causeA placeholder targets the wrong environment, the installed version uses another path or unit name, permissions are insufficient, or an earlier prerequisite was not satisfied.

Safe checks
  • command -v systemctl 2>/dev/null || true
  • systemctl --failed --no-pager 2>/dev/null || true
  • journalctl -p warning -n 50 --no-pager 2>/dev/null || true

ResolutionDo not improvise a privileged workaround. Re-read the environment and variable table, inspect the official source for the installed version, restore the candidate file if necessary, and repeat only this checkpoint.

Security notes

  • Keep secrets out of shell history, process arguments, screenshots, logs, and tutorial placeholders. Elevate only the narrow command that requires it and preserve package signature and TLS verification.

Alternatives

  • When the host layout or software version differs, use the vendor-supported equivalent in a disposable staging environment and document the mapping before touching production.

Stop conditions

  • Stop if the action broadens network exposure, permissions, package sources, writable paths, or service privileges beyond the tutorial's declared architecture.
04

config

Block unnecessary privilege gains and kernel access

caution

Add NoNewPrivileges, PrivateTmp, ProtectKernelTunables, ProtectKernelModules, ProtectControlGroups, and RestrictSUIDSGID after checking runtime compatibility.

Why this step matters

Block unnecessary privilege gains and kernel access is a separate checkpoint because it establishes one auditable part of reduce the impact of a compromised php worker while preserving required application writes and networking. Performing it independently keeps a failed prerequisite, syntax error, or compatibility mismatch from being hidden by later actions.

What to understand

Add NoNewPrivileges, PrivateTmp, ProtectKernelTunables, ProtectKernelModules, ProtectControlGroups, and RestrictSUIDSGID after checking runtime compatibility. Read the complete command or configuration before execution, replace the documented placeholders, and compare the target host with the supported environments listed at the beginning of this tutorial.

Capture the before-state and the exact output in the change record. If this step modifies a file or service, validate the candidate with its native checker before any reload; a successful process exit alone does not prove that the application uses the intended value.

Use a representative staging or canary host first. Repeat the stated checkpoint immediately, because proceeding with ambiguous evidence makes the later end-to-end verification and rollback materially harder.

System changes

  • This step may affect the files, packages, identities, services, or runtime policy named in “Block unnecessary privilege gains and kernel access”. The scope must remain limited to the selected application and supported host.

Syntax explained

systemctl
Invokes the principal tool or configuration operation for “Block unnecessary privilege gains and kernel access”; confirm that it resolves to the expected packaged executable or file before using elevated privileges.
{{…}}
Marks an operator-supplied value. Replace every placeholder deliberately; do not paste untrusted text or leave braces in the production command.
|
Passes standard output to the next read-only inspection stage; review each stage separately if the combined result is surprising.
configuration file
Is the persistent configuration boundary changed by this step. Keep an attributable backup and validate the consumer before reload.
Configuration
Fill variables0/1 ready

Values stay on this page and are never sent or saved.

systemctl cat php{{phpVersion}}-fpm | grep -E 'NoNewPrivileges|PrivateTmp|ProtectKernel|ProtectControlGroups|RestrictSUIDSGID'
Example output / evidence
Privilege and kernel protections are explicit.

Checkpoint: Checkpoint: Block unnecessary privilege gains and kernel access

Continue whenPrivilege and kernel protections are explicit. Treat this concrete evidence as the minimum success signal and also confirm that unrelated services and the previous healthy path remain unchanged.

Stop whenStop before the next step when systemctl reports an error, the output differs materially from the example, an unexpected package/service/path is affected, or the required before-state and rollback artifact are missing.

If this step fails

The command for “Block unnecessary privilege gains and kernel access” fails, produces no useful evidence, or the expected service/configuration state is absent.

Likely causeA placeholder targets the wrong environment, the installed version uses another path or unit name, permissions are insufficient, or an earlier prerequisite was not satisfied.

Safe checks
  • command -v systemctl 2>/dev/null || true
  • systemctl --failed --no-pager 2>/dev/null || true
  • journalctl -p warning -n 50 --no-pager 2>/dev/null || true

ResolutionDo not improvise a privileged workaround. Re-read the environment and variable table, inspect the official source for the installed version, restore the candidate file if necessary, and repeat only this checkpoint.

Security notes

  • Keep secrets out of shell history, process arguments, screenshots, logs, and tutorial placeholders. Elevate only the narrow command that requires it and preserve package signature and TLS verification.

Alternatives

  • When the host layout or software version differs, use the vendor-supported equivalent in a disposable staging environment and document the mapping before touching production.

Stop conditions

  • Stop if the action broadens network exposure, permissions, package sources, writable paths, or service privileges beyond the tutorial's declared architecture.
05

config

Make the system read-only with narrow write exceptions

caution

Use ProtectSystem=strict, ProtectHome, ReadWritePaths for required application state, and RuntimeDirectory for sockets where compatible.

Why this step matters

Make the system read-only with narrow write exceptions is a separate checkpoint because it establishes one auditable part of reduce the impact of a compromised php worker while preserving required application writes and networking. Performing it independently keeps a failed prerequisite, syntax error, or compatibility mismatch from being hidden by later actions.

What to understand

Use ProtectSystem=strict, ProtectHome, ReadWritePaths for required application state, and RuntimeDirectory for sockets where compatible. Read the complete command or configuration before execution, replace the documented placeholders, and compare the target host with the supported environments listed at the beginning of this tutorial.

Capture the before-state and the exact output in the change record. If this step modifies a file or service, validate the candidate with its native checker before any reload; a successful process exit alone does not prove that the application uses the intended value.

Use a representative staging or canary host first. Repeat the stated checkpoint immediately, because proceeding with ambiguous evidence makes the later end-to-end verification and rollback materially harder.

System changes

  • This step may affect the files, packages, identities, services, or runtime policy named in “Make the system read-only with narrow write exceptions”. The scope must remain limited to the selected application and supported host.

Syntax explained

systemctl
Invokes the principal tool or configuration operation for “Make the system read-only with narrow write exceptions”; confirm that it resolves to the expected packaged executable or file before using elevated privileges.
{{…}}
Marks an operator-supplied value. Replace every placeholder deliberately; do not paste untrusted text or leave braces in the production command.
|
Passes standard output to the next read-only inspection stage; review each stage separately if the combined result is surprising.
configuration file
Is the persistent configuration boundary changed by this step. Keep an attributable backup and validate the consumer before reload.
Configuration
Fill variables0/1 ready

Values stay on this page and are never sent or saved.

systemctl cat php{{phpVersion}}-fpm | grep -E 'ProtectSystem|ProtectHome|ReadWritePaths|RuntimeDirectory'
Example output / evidence
Only documented state paths remain writable.

Checkpoint: Checkpoint: Make the system read-only with narrow write exceptions

Continue whenOnly documented state paths remain writable. Treat this concrete evidence as the minimum success signal and also confirm that unrelated services and the previous healthy path remain unchanged.

Stop whenStop before the next step when systemctl reports an error, the output differs materially from the example, an unexpected package/service/path is affected, or the required before-state and rollback artifact are missing.

If this step fails

The command for “Make the system read-only with narrow write exceptions” fails, produces no useful evidence, or the expected service/configuration state is absent.

Likely causeA placeholder targets the wrong environment, the installed version uses another path or unit name, permissions are insufficient, or an earlier prerequisite was not satisfied.

Safe checks
  • command -v systemctl 2>/dev/null || true
  • systemctl --failed --no-pager 2>/dev/null || true
  • journalctl -p warning -n 50 --no-pager 2>/dev/null || true

ResolutionDo not improvise a privileged workaround. Re-read the environment and variable table, inspect the official source for the installed version, restore the candidate file if necessary, and repeat only this checkpoint.

Security notes

  • Keep secrets out of shell history, process arguments, screenshots, logs, and tutorial placeholders. Elevate only the narrow command that requires it and preserve package signature and TLS verification.

Alternatives

  • When the host layout or software version differs, use the vendor-supported equivalent in a disposable staging environment and document the mapping before touching production.

Stop conditions

  • Stop if the action broadens network exposure, permissions, package sources, writable paths, or service privileges beyond the tutorial's declared architecture.
06

config

Constrain devices, address families, and namespaces

caution

Use PrivateDevices, RestrictAddressFamilies for Unix and required network families, and RestrictNamespaces only after extension and application tests.

Why this step matters

Constrain devices, address families, and namespaces is a separate checkpoint because it establishes one auditable part of reduce the impact of a compromised php worker while preserving required application writes and networking. Performing it independently keeps a failed prerequisite, syntax error, or compatibility mismatch from being hidden by later actions.

What to understand

Use PrivateDevices, RestrictAddressFamilies for Unix and required network families, and RestrictNamespaces only after extension and application tests. Read the complete command or configuration before execution, replace the documented placeholders, and compare the target host with the supported environments listed at the beginning of this tutorial.

Capture the before-state and the exact output in the change record. If this step modifies a file or service, validate the candidate with its native checker before any reload; a successful process exit alone does not prove that the application uses the intended value.

Use a representative staging or canary host first. Repeat the stated checkpoint immediately, because proceeding with ambiguous evidence makes the later end-to-end verification and rollback materially harder.

System changes

  • This step may affect the files, packages, identities, services, or runtime policy named in “Constrain devices, address families, and namespaces”. The scope must remain limited to the selected application and supported host.

Syntax explained

systemctl
Invokes the principal tool or configuration operation for “Constrain devices, address families, and namespaces”; confirm that it resolves to the expected packaged executable or file before using elevated privileges.
{{…}}
Marks an operator-supplied value. Replace every placeholder deliberately; do not paste untrusted text or leave braces in the production command.
|
Passes standard output to the next read-only inspection stage; review each stage separately if the combined result is surprising.
configuration file
Is the persistent configuration boundary changed by this step. Keep an attributable backup and validate the consumer before reload.
Configuration
Fill variables0/1 ready

Values stay on this page and are never sent or saved.

systemctl cat php{{phpVersion}}-fpm | grep -E 'PrivateDevices|RestrictAddressFamilies|RestrictNamespaces'
Example output / evidence
The unit exposes only required kernel interfaces.

Checkpoint: Checkpoint: Constrain devices, address families, and namespaces

Continue whenThe unit exposes only required kernel interfaces. Treat this concrete evidence as the minimum success signal and also confirm that unrelated services and the previous healthy path remain unchanged.

Stop whenStop before the next step when systemctl reports an error, the output differs materially from the example, an unexpected package/service/path is affected, or the required before-state and rollback artifact are missing.

If this step fails

The command for “Constrain devices, address families, and namespaces” fails, produces no useful evidence, or the expected service/configuration state is absent.

Likely causeA placeholder targets the wrong environment, the installed version uses another path or unit name, permissions are insufficient, or an earlier prerequisite was not satisfied.

Safe checks
  • command -v systemctl 2>/dev/null || true
  • systemctl --failed --no-pager 2>/dev/null || true
  • journalctl -p warning -n 50 --no-pager 2>/dev/null || true

ResolutionDo not improvise a privileged workaround. Re-read the environment and variable table, inspect the official source for the installed version, restore the candidate file if necessary, and repeat only this checkpoint.

Security notes

  • Keep secrets out of shell history, process arguments, screenshots, logs, and tutorial placeholders. Elevate only the narrow command that requires it and preserve package signature and TLS verification.

Alternatives

  • When the host layout or software version differs, use the vendor-supported equivalent in a disposable staging environment and document the mapping before touching production.

Stop conditions

  • Stop if the action broadens network exposure, permissions, package sources, writable paths, or service privileges beyond the tutorial's declared architecture.
07

verification

Verify unit syntax and start in a maintenance window

caution

Run systemd-analyze verify, daemon-reload, restart FPM, and inspect denial messages before returning traffic.

Why this step matters

Verify unit syntax and start in a maintenance window is a separate checkpoint because it establishes one auditable part of reduce the impact of a compromised php worker while preserving required application writes and networking. Performing it independently keeps a failed prerequisite, syntax error, or compatibility mismatch from being hidden by later actions.

What to understand

Run systemd-analyze verify, daemon-reload, restart FPM, and inspect denial messages before returning traffic. Read the complete command or configuration before execution, replace the documented placeholders, and compare the target host with the supported environments listed at the beginning of this tutorial.

Capture the before-state and the exact output in the change record. If this step modifies a file or service, validate the candidate with its native checker before any reload; a successful process exit alone does not prove that the application uses the intended value.

Use a representative staging or canary host first. Repeat the stated checkpoint immediately, because proceeding with ambiguous evidence makes the later end-to-end verification and rollback materially harder.

System changes

  • This step may affect the files, packages, identities, services, or runtime policy named in “Verify unit syntax and start in a maintenance window”. The scope must remain limited to the selected application and supported host.

Syntax explained

systemd-analyze
Invokes the principal tool or configuration operation for “Verify unit syntax and start in a maintenance window”; confirm that it resolves to the expected packaged executable or file before using elevated privileges.
{{…}}
Marks an operator-supplied value. Replace every placeholder deliberately; do not paste untrusted text or leave braces in the production command.
Command
Fill variables0/1 ready

Values stay on this page and are never sent or saved.

sudo systemd-analyze verify php{{phpVersion}}-fpm.service; sudo systemctl daemon-reload; sudo systemctl restart php{{phpVersion}}-fpm; sudo journalctl -u php{{phpVersion}}-fpm --since '-5 min' --no-pager
Example output / evidence
The unit starts and logs contain no unexpected permission denial.

Checkpoint: Checkpoint: Verify unit syntax and start in a maintenance window

Continue whenThe unit starts and logs contain no unexpected permission denial. Treat this concrete evidence as the minimum success signal and also confirm that unrelated services and the previous healthy path remain unchanged.

Stop whenStop before the next step when systemd-analyze reports an error, the output differs materially from the example, an unexpected package/service/path is affected, or the required before-state and rollback artifact are missing.

If this step fails

The command for “Verify unit syntax and start in a maintenance window” fails, produces no useful evidence, or the expected service/configuration state is absent.

Likely causeA placeholder targets the wrong environment, the installed version uses another path or unit name, permissions are insufficient, or an earlier prerequisite was not satisfied.

Safe checks
  • command -v systemd-analyze 2>/dev/null || true
  • systemctl --failed --no-pager 2>/dev/null || true
  • journalctl -p warning -n 50 --no-pager 2>/dev/null || true

ResolutionDo not improvise a privileged workaround. Re-read the environment and variable table, inspect the official source for the installed version, restore the candidate file if necessary, and repeat only this checkpoint.

Security notes

  • Keep secrets out of shell history, process arguments, screenshots, logs, and tutorial placeholders. Elevate only the narrow command that requires it and preserve package signature and TLS verification.

Alternatives

  • When the host layout or software version differs, use the vendor-supported equivalent in a disposable staging environment and document the mapping before touching production.

Stop conditions

  • Stop if the action broadens network exposure, permissions, package sources, writable paths, or service privileges beyond the tutorial's declared architecture.
08

verification

Exercise every required capability

read-only

Test reads, configured writes, sessions, uploads, database connections, DNS, outbound calls if required, background jobs, and log delivery.

Why this step matters

Exercise every required capability is a separate checkpoint because it establishes one auditable part of reduce the impact of a compromised php worker while preserving required application writes and networking. Performing it independently keeps a failed prerequisite, syntax error, or compatibility mismatch from being hidden by later actions.

What to understand

Test reads, configured writes, sessions, uploads, database connections, DNS, outbound calls if required, background jobs, and log delivery. Read the complete command or configuration before execution, replace the documented placeholders, and compare the target host with the supported environments listed at the beginning of this tutorial.

Capture the before-state and the exact output in the change record. If this step modifies a file or service, validate the candidate with its native checker before any reload; a successful process exit alone does not prove that the application uses the intended value.

Use a representative staging or canary host first. Repeat the stated checkpoint immediately, because proceeding with ambiguous evidence makes the later end-to-end verification and rollback materially harder.

System changes

  • This step may affect the files, packages, identities, services, or runtime policy named in “Exercise every required capability”. The scope must remain limited to the selected application and supported host.

Syntax explained

curl
Invokes the principal tool or configuration operation for “Exercise every required capability”; confirm that it resolves to the expected packaged executable or file before using elevated privileges.
{{…}}
Marks an operator-supplied value. Replace every placeholder deliberately; do not paste untrusted text or leave braces in the production command.
Command
Fill variables0/2 ready

Values stay on this page and are never sent or saved.

curl --fail --silent https://{{domain}}/internal/dependency-health; curl --fail --silent -F file=@{{safeFixture}} https://{{domain}}/internal/upload-test
Example output / evidence
All allowlisted application capabilities succeed.

Checkpoint: Checkpoint: Exercise every required capability

Continue whenAll allowlisted application capabilities succeed. Treat this concrete evidence as the minimum success signal and also confirm that unrelated services and the previous healthy path remain unchanged.

Stop whenStop before the next step when curl reports an error, the output differs materially from the example, an unexpected package/service/path is affected, or the required before-state and rollback artifact are missing.

If this step fails

The command for “Exercise every required capability” fails, produces no useful evidence, or the expected service/configuration state is absent.

Likely causeA placeholder targets the wrong environment, the installed version uses another path or unit name, permissions are insufficient, or an earlier prerequisite was not satisfied.

Safe checks
  • command -v curl 2>/dev/null || true
  • systemctl --failed --no-pager 2>/dev/null || true
  • journalctl -p warning -n 50 --no-pager 2>/dev/null || true

ResolutionDo not improvise a privileged workaround. Re-read the environment and variable table, inspect the official source for the installed version, restore the candidate file if necessary, and repeat only this checkpoint.

Security notes

  • Keep secrets out of shell history, process arguments, screenshots, logs, and tutorial placeholders. Elevate only the narrow command that requires it and preserve package signature and TLS verification.

Alternatives

  • When the host layout or software version differs, use the vendor-supported equivalent in a disposable staging environment and document the mapping before touching production.

Stop conditions

  • Stop if the action broadens network exposure, permissions, package sources, writable paths, or service privileges beyond the tutorial's declared architecture.

Finish line

Verification checklist

Improved security scoresystemd-analyze security php{{phpVersion}}-fpm.serviceThe exposure score improves and every remaining item has a documented compatibility reason.
Restart and workloadsudo systemctl restart php{{phpVersion}}-fpm && curl --fail --silent https://{{domain}}/healthFPM restarts and the application stays healthy.

Recovery guidance

Common problems and safe checks

The web server returns 502/503 or reports that the FastCGI upstream is unavailable.

Likely causeThe configured socket and the active PHP-FPM pool disagree, the pool failed validation, or Unix socket ownership does not permit the web-server worker to connect.

Safe checks
  • systemctl status 'php*-fpm' --no-pager
  • find /run -maxdepth 3 -type s -name '*php*fpm*' -ls
  • journalctl -u nginx -u apache2 -u php8.3-fpm -p warning -n 80 --no-pager

ResolutionMatch the virtual host to one validated pool socket and explicit owner/group/mode, then reload only after both native configuration tests pass.

CLI reports the intended PHP version but the HTTP application uses another version or INI value.

Likely causeCLI and FPM are separate SAPIs, the virtual host targets another pool, or a later scan-directory file overrides the reviewed setting.

Safe checks
  • php --ini
  • systemctl list-units --type=service '*php*fpm*' --no-pager
  • grep -R -n 'fastcgi_pass\|SetHandler' /etc/nginx /etc/apache2 2>/dev/null

ResolutionTrace the request from hostname through the selected handler and pool to its loaded INI tree; correct that specific boundary rather than changing global CLI alternatives.

Validation passes but a representative request fails after the reload.

Likely causeThe syntax is legal but a path, permission, resource limit, extension, database grant, network dependency, or systemd restriction is incompatible with the real workload.

Safe checks
  • systemctl --failed --no-pager
  • journalctl -p warning --since '-10 min' --no-pager
  • curl --fail --silent --show-error https://example.com/health

ResolutionRemove the host from traffic, compare the before-state, revert the smallest changed layer, and use the preserved logs plus a safe fixture to refine the candidate in staging.

After the procedure

Alternatives and next steps

Consider these alternatives

  • Run the application in a well-maintained rootless container or stronger sandbox when its image, mounts, network and update lifecycle are controlled.
  • Apply a smaller compatible subset of controls and document gaps instead of deploying an untested maximum profile.

Operate it safely

  • Alert on unit/drop-in drift, failed starts and new denial messages; reassess controls after PHP, extension or application upgrades.
  • Split unrelated applications into dedicated pools/services so each can receive a narrower policy.

Recovery

Rollback

Remove or revert the systemd drop-in, daemon-reload, and restart FPM.

  1. Use systemctl revert php{{phpVersion}}-fpm.service or restore the prior drop-in archive.
  2. Run daemon-reload, restart FPM, and repeat health and write-path tests.
  3. Preserve journal denial evidence to design a narrower compatible policy.

Evidence

Sources and review

Verified 2026-07-25Review due 2026-10-23
PHP-FPM installation and configurationofficialPHP core configuration directivesofficialUbuntu Server: install PHPofficial