Install a production LAMP stack on Ubuntu
Build Apache, MariaDB, PHP-FPM, TLS, application identity, database credentials, health checks, and backups as one verified stack.
Deploy a maintainable Linux, Apache, MariaDB, and PHP application baseline without exposing database or sample endpoints.
- Ubuntu Server 24.04 LTS
- PHP 8.3
- 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.
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
- A patched Ubuntu host running Apache, MariaDB and a dedicated PHP-FPM pool for one application.
- A least-privilege database identity, isolated release layout, HTTPS virtual host, bounded firewall and concrete health/backup checks.
- The named HTTPS site reaches the intended FPM pool and local database while default sites, public database exposure and temporary diagnostics are absent.
- Every service validates, restarts and produces attributable logs; a logical backup stream and rollback release are verified.
Architecture
How the parts fit together
Apache terminates TLS and serves only the application's public document root. PHP requests are forwarded through proxy_fcgi to a dedicated Unix-socket FPM pool running under a non-login application identity. MariaDB listens locally and grants one account access to one database. Immutable release directories separate code from writable shared state. UFW exposes only management SSH and HTTP/HTTPS, while health checks, service journals and a tested database dump provide operational evidence.
- Patch and inventory the host before packages or firewall rules change.
- Install signed packages, create explicit identities/directories and provision the local database account.
- Validate the FPM pool and Apache virtual host before enabling TLS and reloading services.
- Exercise HTTPS, PHP, database and backup paths, then retain the previous release and configuration for rollback.
Assumptions
- The target is a supported Ubuntu 24.04 LTS host with console/recovery access and correct time/DNS.
- The hostname resolves to the host before certificate issuance and inbound ports 80/443 are permitted by upstream controls.
- Application secrets are generated and delivered outside shell history; the release has a safe health endpoint and migration plan.
Key concepts
- document root
- The only directory Apache may expose; application secrets and writable private data remain outside it.
- FastCGI
- The protocol Apache uses to pass PHP requests to a separately supervised FPM worker pool.
- least privilege
- Giving the application identity and database account only the paths and schema rights they require.
- release layout
- Versioned immutable code plus separately managed shared state, enabling an atomic application rollback.
Before you copy
Values used in this guide
{{app}}Short application identifier used in service, pool, directory, and configuration names.
Example: billing{{appGroup}}Operating-system group that owns application-readable or shared runtime paths.
Example: billing{{appUser}}Non-login operating-system identity used by the application workers.
Example: billing{{database}}Application database name; use an identifier approved by the database naming policy.
Example: billing{{dbPassword}}Generated database credential supplied through a protected secret channel, never committed to source control.
Example: use-a-secret-manager-generated-value{{dbUser}}Least-privilege database account used by the application.
Example: billing_app{{domain}}Fully qualified public or internal hostname served by this configuration.
Example: billing.example.com{{managementCidr}}Trusted administration network in CIDR notation.
Example: 192.0.2.0/24{{phpVersion}}Exact PHP major and minor branch used by the target runtime.
Example: 8.3Security and production boundaries
- Do not expose MariaDB publicly or grant global privileges to the application account.
- Remove phpinfo and installation test files, restrict the public root, and keep certificate/database secrets outside repository and shell history.
- Keep a second administration session open before enabling the firewall and verify upstream access controls independently.
Stop before continuing if
- Stop if DNS points elsewhere, package provenance is unexpected, Apache exposes the release root, or the firewall would remove recovery access.
- Do not declare success until HTTPS, FPM, database connectivity, logs and a non-empty recoverable backup are all proven.
instruction
Patch and inventory the host
Apply supported security updates, confirm time synchronization, and record listening services before adding the stack.
Why this step matters
Patch and inventory the host is a separate checkpoint because it establishes one auditable part of deploy a maintainable linux, apache, mariadb, and php application baseline without exposing database or sample endpoints. Performing it independently keeps a failed prerequisite, syntax error, or compatibility mismatch from being hidden by later actions.
What to understand
Apply supported security updates, confirm time synchronization, and record listening services before adding the stack. 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 “Patch and inventory the host”. The scope must remain limited to the selected application and supported host.
Syntax explained
apt- Invokes the principal tool or configuration operation for “Patch and inventory the host”; confirm that it resolves to the expected packaged executable or file before using elevated privileges.
&&- Runs the following operation only when the previous command succeeds, preventing a reload or state transition after a failed validation.
sudo apt update && sudo apt upgrade --yes; timedatectl status; sudo ss -lntupThe host is current, synchronized, and its listener baseline is recorded.
Checkpoint: Checkpoint: Patch and inventory the host
Continue whenThe host is current, synchronized, and its listener baseline is 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 apt 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 “Patch and inventory the host” 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.
command -v apt 2>/dev/null || truesystemctl --failed --no-pager 2>/dev/null || truejournalctl -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.
command
Install Apache, MariaDB, PHP-FPM, and required modules
Use Ubuntu packages and PHP-FPM rather than embedding mod_php in Apache.
Why this step matters
Install Apache, MariaDB, PHP-FPM, and required modules is a separate checkpoint because it establishes one auditable part of deploy a maintainable linux, apache, mariadb, and php application baseline without exposing database or sample endpoints. Performing it independently keeps a failed prerequisite, syntax error, or compatibility mismatch from being hidden by later actions.
What to understand
Use Ubuntu packages and PHP-FPM rather than embedding mod_php in Apache. 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 “Install Apache, MariaDB, PHP-FPM, and required modules”. The scope must remain limited to the selected application and supported host.
Syntax explained
apt- Invokes the principal tool or configuration operation for “Install Apache, MariaDB, PHP-FPM, and required modules”; confirm that it resolves to the expected packaged executable or file before using elevated privileges.
sudo apt install --yes apache2 mariadb-server php-fpm php-cli php-mysql php-opcache php-curl php-mbstring php-xml php-zipApache, MariaDB, and the Ubuntu PHP branch install.
Checkpoint: Checkpoint: Install Apache, MariaDB, PHP-FPM, and required modules
Continue whenApache, MariaDB, and the Ubuntu PHP branch install. 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 apt 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 “Install Apache, MariaDB, PHP-FPM, and required modules” 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.
command -v apt 2>/dev/null || truesystemctl --failed --no-pager 2>/dev/null || truejournalctl -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.
command
Create the application identity and release layout
Separate immutable releases, shared writable data, and public document root under an application account.
Why this step matters
Create the application identity and release layout is a separate checkpoint because it establishes one auditable part of deploy a maintainable linux, apache, mariadb, and php application baseline without exposing database or sample endpoints. Performing it independently keeps a failed prerequisite, syntax error, or compatibility mismatch from being hidden by later actions.
What to understand
Separate immutable releases, shared writable data, and public document root under an application account. 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 the application identity and release layout”. The scope must remain limited to the selected application and supported host.
Syntax explained
useradd- Invokes the principal tool or configuration operation for “Create the application identity and release layout”; 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.
Values stay on this page and are never sent or saved.
sudo useradd --system --home-dir /srv/{{app}} --shell /usr/sbin/nologin {{appUser}}; sudo install -d -o {{appUser}} -g {{appGroup}} -m 0750 /srv/{{app}}/{releases,shared}; sudo install -d -o {{appUser}} -g {{appGroup}} -m 0755 /srv/{{app}}/current/publicApplication directories have explicit ownership and no shell login.
Checkpoint: Checkpoint: Create the application identity and release layout
Continue whenApplication directories have explicit ownership and no shell login. 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 useradd 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 the application identity and release layout” 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.
command -v useradd 2>/dev/null || truesystemctl --failed --no-pager 2>/dev/null || truejournalctl -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.
command
Create a least-privilege database principal
Create the database, local-only account, and application privileges with a generated secret supplied interactively or by a protected client option file.
Why this step matters
Create a least-privilege database principal is a separate checkpoint because it establishes one auditable part of deploy a maintainable linux, apache, mariadb, and php application baseline without exposing database or sample endpoints. Performing it independently keeps a failed prerequisite, syntax error, or compatibility mismatch from being hidden by later actions.
What to understand
Create the database, local-only account, and application privileges with a generated secret supplied interactively or by a protected client option file. 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 least-privilege database principal”. The scope must remain limited to the selected application and supported host.
Syntax explained
mariadb- Invokes the principal tool or configuration operation for “Create a least-privilege database principal”; 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.
Values stay on this page and are never sent or saved.
sudo mariadb --protocol=socket -e "CREATE DATABASE \`{{database}}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER '{{dbUser}}'@'localhost' IDENTIFIED BY '{{dbPassword}}'; GRANT ALL PRIVILEGES ON \`{{database}}\`.* TO '{{dbUser}}'@'localhost';"The application account has privileges only on its database.
Checkpoint: Checkpoint: Create a least-privilege database principal
Continue whenThe application account has privileges only on its database. 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 mariadb 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 least-privilege database principal” 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.
command -v mariadb 2>/dev/null || truesystemctl --failed --no-pager 2>/dev/null || truejournalctl -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.
config
Create a dedicated PHP-FPM pool
Run application code under the application identity and expose a private Unix socket to Apache.
Why this step matters
Create a dedicated PHP-FPM pool is a separate checkpoint because it establishes one auditable part of deploy a maintainable linux, apache, mariadb, and php application baseline without exposing database or sample endpoints. Performing it independently keeps a failed prerequisite, syntax error, or compatibility mismatch from being hidden by later actions.
What to understand
Run application code under the application identity and expose a private Unix socket to Apache. 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 dedicated PHP-FPM pool”. The scope must remain limited to the selected application and supported host.
Syntax explained
sudoedit- Invokes the principal tool or configuration operation for “Create a dedicated PHP-FPM pool”; 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/php/{{phpVersion}}/fpm/pool.d/{{app}}.conf- Is the persistent configuration boundary changed by this step. Keep an attributable backup and validate the consumer before reload.
/etc/php/{{phpVersion}}/fpm/pool.d/{{app}}.confValues stay on this page and are never sent or saved.
sudoedit /etc/php/{{phpVersion}}/fpm/pool.d/{{app}}.conf; sudo php-fpm{{phpVersion}} -ttThe pool validates with a unique socket and bounded children.
Checkpoint: Checkpoint: Create a dedicated PHP-FPM pool
Continue whenThe pool validates with a unique socket and bounded children. 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 sudoedit 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 dedicated PHP-FPM pool” 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.
command -v sudoedit 2>/dev/null || truesystemctl --failed --no-pager 2>/dev/null || truejournalctl -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.
config
Configure the Apache virtual host
Set ServerName, document root, least-privilege Directory rules, logs, and a FilesMatch proxy to the application FPM socket.
Why this step matters
Configure the Apache virtual host is a separate checkpoint because it establishes one auditable part of deploy a maintainable linux, apache, mariadb, and php application baseline without exposing database or sample endpoints. Performing it independently keeps a failed prerequisite, syntax error, or compatibility mismatch from being hidden by later actions.
What to understand
Set ServerName, document root, least-privilege Directory rules, logs, and a FilesMatch proxy to the application FPM socket. 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 “Configure the Apache virtual host”. The scope must remain limited to the selected application and supported host.
Syntax explained
a2enmod- Invokes the principal tool or configuration operation for “Configure the Apache virtual host”; 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/apache2/sites-available/{{domain}}.conf- Is the persistent configuration boundary changed by this step. Keep an attributable backup and validate the consumer before reload.
/etc/apache2/sites-available/{{domain}}.confValues stay on this page and are never sent or saved.
sudo a2enmod proxy_fcgi setenvif rewrite headers ssl; sudoedit /etc/apache2/sites-available/{{domain}}.conf; sudo a2ensite {{domain}}; sudo a2dissite 000-defaultOnly the named site is enabled and PHP requests target its pool.
Checkpoint: Checkpoint: Configure the Apache virtual host
Continue whenOnly the named site is enabled and PHP requests target its pool. 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 a2enmod 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 “Configure the Apache virtual host” 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.
command -v a2enmod 2>/dev/null || truesystemctl --failed --no-pager 2>/dev/null || truejournalctl -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.
command
Restrict network access and issue TLS
Expose SSH from the management network plus HTTP/HTTPS, then issue a certificate only after DNS is correct.
Why this step matters
Restrict network access and issue TLS is a separate checkpoint because it establishes one auditable part of deploy a maintainable linux, apache, mariadb, and php application baseline without exposing database or sample endpoints. Performing it independently keeps a failed prerequisite, syntax error, or compatibility mismatch from being hidden by later actions.
What to understand
Expose SSH from the management network plus HTTP/HTTPS, then issue a certificate only after DNS is correct. 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 “Restrict network access and issue TLS”. The scope must remain limited to the selected application and supported host.
Syntax explained
ufw- Invokes the principal tool or configuration operation for “Restrict network access and issue TLS”; 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.
Values stay on this page and are never sent or saved.
sudo ufw allow from {{managementCidr}} to any port 22 proto tcp; sudo ufw allow 'Apache Full'; sudo ufw --force enable; sudo certbot --apache -d {{domain}} --redirectFirewall rules are explicit and the site has a valid HTTPS certificate.
Checkpoint: Checkpoint: Restrict network access and issue TLS
Continue whenFirewall rules are explicit and the site has a valid HTTPS certificate. 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 ufw 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 “Restrict network access and issue TLS” 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.
command -v ufw 2>/dev/null || truesystemctl --failed --no-pager 2>/dev/null || truejournalctl -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.
verification
Validate and restart the complete stack
Test FPM, Apache, and database connectivity before a controlled restart; remove any temporary phpinfo file.
Why this step matters
Validate and restart the complete stack is a separate checkpoint because it establishes one auditable part of deploy a maintainable linux, apache, mariadb, and php application baseline without exposing database or sample endpoints. Performing it independently keeps a failed prerequisite, syntax error, or compatibility mismatch from being hidden by later actions.
What to understand
Test FPM, Apache, and database connectivity before a controlled restart; remove any temporary phpinfo file. 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 “Validate and restart the complete stack”. The scope must remain limited to the selected application and supported host.
Syntax explained
php-fpm- Invokes the principal tool or configuration operation for “Validate and restart the complete stack”; 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.
Values stay on this page and are never sent or saved.
sudo php-fpm{{phpVersion}} -tt; sudo apachectl configtest; sudo mariadb-admin ping; sudo systemctl restart mariadb php{{phpVersion}}-fpm apache2; rm -f /srv/{{app}}/current/public/phpinfo.phpAll services restart and no phpinfo endpoint remains.
Checkpoint: Checkpoint: Validate and restart the complete stack
Continue whenAll services restart and no phpinfo endpoint remains. 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 php-fpm 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 “Validate and restart the complete stack” 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.
command -v php-fpm 2>/dev/null || truesystemctl --failed --no-pager 2>/dev/null || truejournalctl -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
curl --fail --silent --show-error https://{{domain}}/health && openssl s_client -connect {{domain}}:443 -servername {{domain}} </dev/null 2>/dev/null | openssl x509 -noout -datesThe application health endpoint succeeds and certificate dates are valid.MYSQL_PWD='{{dbPassword}}' mariadb -h localhost -u {{dbUser}} {{database}} -e 'SELECT CURRENT_USER(), DATABASE();'; sudo mariadb-dump --single-transaction {{database}} | gzip -c | test -s /dev/stdinThe application connects locally and a logical backup stream is non-empty.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.
systemctl status 'php*-fpm' --no-pagerfind /run -maxdepth 3 -type s -name '*php*fpm*' -lsjournalctl -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.
php --inisystemctl list-units --type=service '*php*fpm*' --no-pagergrep -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.
systemctl --failed --no-pagerjournalctl -p warning --since '-10 min' --no-pagercurl --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.
Recovery
Rollback
Restore the prior Apache site, FPM pool, database grant, and application release independently.
- Switch the current application release symlink back and reload Apache/FPM after syntax tests.
- Restore the database from the pre-change backup only if schema rollback requires it.
- Re-enable the prior site and firewall rules from the saved baseline; do not expose MariaDB publicly.
Evidence