Apache HTTPd and PHP security

Notes on setting up Apache and PHP to run under user account

Requirements: base installation with PHP using FPM for Apache

How things are connected

The pool configuration file is the file controlling the ‘server’ (proxy) for PHP. The ‘listen’ line in this file is telling where proxy requests should be accepted.
‘user’ and ‘group’ tells under which user account the process should be run. ‘listen.owner’, ‘listen.group’ and ‘listen.mode’ can be set to limit access to the proxy (by other users/sites).

Sample PHP FPM pool configuration
For each version of PHP that should be available, create a pool configuration file (in ‘/etc/php/<version>/fpm/pool.d/’) like:

[8001]
user = $pool
group = $pool

listen = /run/php/php8.2-fpm-$pool.sock

listen.owner = $pool
listen.group = $pool

pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
pm.status_path = /fpm-status

(change the “listen =” line, so it matches the PHP version you wish to use, then change to listen to the same socket in the virtualhost configuration or in the override segment in .htaccess)

In the virtualhost configuration, that same listening socket must be used (the owner of the httpd process must have rights to talk to the proxy, so it could be set up as a per-user or per-group setting depending on how it was set up in the pool configuration).

Sample virtualhost, allows override of PHP version and access to /fpm-status

<VirtualHost *:80>
  <IfModule mpm_itk_module>
    AssignUserId #8001 #8001
  </IfModule>

  ServerName site8001.domain.com
  DocumentRoot /var/www/site8001/html

  <Directory /var/www/site8001/html>
    Options Indexes FollowSymLinks
    AllowOverride All
    Require all granted
  </Directory>
  <LocationMatch "/fpm-status">
    ProxyPass  "unix:/var/run/php/php8.2-fpm-8001.sock|fcgi://localhost/fpm-status"
  </LocationMatch>
  <FilesMatch ".php$">
    SetHandler "proxy:unix:/var/run/php/php8.2-fpm-8001.sock|fcgi://localhost/"
  </FilesMatch>

  ErrorLog /var/www/site8001/logs/error.log
  CustomLog /var/www/site8001/logs/access.log combined
</VirtualHost>

mpm_itk (used above) allows the Apache HTTPd process to be run by another user:

apt install libapache2-mpm-itk
a2enmod mpm_itk

The following were probably done when installing php-fpm

apt install libapache2-mod-fcgid
a2enmod proxy_fcgi

File permissions

When running both Apache httpd and PHP as a specific user, the files on the web site only need to have user read/write(when needed) access if they are owned by the user running the processes.
To make a permanent change to the umask used by PHP, add ‘UMask=0077’ to the ‘Service’ section of each PHP FPM service:

systemctl edit php8.2-fpm.service

Add:

[Service]
UMask=0077

Then reload systemctl daemon and restart the fpm service:

systemctl daemon-reload && systemctl restart php8.2-fpm

Changing system-wide umask
To further tighten file access security, I usually change the default umask for user-owned files from 022 (owner rw and everyone read) to 077 (owner permissions only). This can be done in various places and can be overridden temporarily or permanently by the user if needed. One place to set the umask and do other customizations at login is in /etc/profile.d, where each file is a script (need no execute permissions and should have no script header, so simply a file there with the line “umask 0077” will do the trick.

References
https://serverok.in/apache-virtualhost-separate-user-with-mpm-itk

Running sites on different versions of PHP on the same server

This quick guide explains the steps needed to be able to run different versions of PHP on the same server (different virtual hosts or even different folders within the same site).

Updated after the release of PHP 8.3 in November 2023 (8.3 is now the version installed from Ondrej’s repository)

Prepare

If the ‘add-apt-repository’ command is missing, you need to install the package “software-properties-common” first:

apt install -y software-properties-common

Add the ondrej/php repository to your system:

add-apt-repository ppa:ondrej/php

apt update, upgrade:

apt update
apt upgrade
apt autoremove

Note: after these steps you will have both PHP 8.1 and 8.3 installed, and most likely PHP 8.1 active for Apache. When you follow the hint on removing packages no longer needed (php 8.1 packages), PHP 8.1 Apache will also stop working. This will be remedied in the section below, or by changing Apache to use PHP 8.3 instead:

a2enmod php8.3

Install Apache fastCGI module:

apt install -y libapache2-mod-fcgid

For each version of PHP

As of 1 Jan 2024, PHP versions 8.2 (php8.2) and 8.3 (php8.3) are those with active support and updates. PHP version 8.1 (php8.1) will continue to receive critical updates until 25 Nov 2024. See Supported PHP Versions.

Install required packages

apt install -y php8.2 php8.2-fpm php8.2-cgi php8.2-mysql libapache2-mod-php8.2

Install other wanted modules for the same PHP version, for example these commonly used:

apt install -y php8.2-curl php8.2-gd php8.2-imagick php8.2-intl php8.2-mbstring php8.2-readline
apt install -y php8.2-soap php8.2-xml php8.2-xmlrpc php8.2-zip

Start the php-fpm service:

systemctl start php8.2-fpm

Check that the service is running:

systemctl status php8.2-fpm

For each version, also any custom configuration in php.ini has to be duplicated. In Ubuntu the php.ini files are located in the subfolders of /etc/php/x.x/ (one subfolder for each run environment, “apache2”, “cgi”, “cli”, “fpm”).

With the understanding of the above, here are the needed commands for installing the required and extra packages for PHP 7.4, 8.0, 8.1, 8.2 and 8.3:

#
# 7.4
#
apt install -y php7.4 php7.4-fpm php7.4-cgi php7.4-mysql libapache2-mod-php7.4
apt install -y php7.4-curl php7.4-gd php7.4-imagick php7.4-intl php7.4-mbstring php7.4-readline php7.4-json
apt install -y php7.4-soap php7.4-xml php7.4-xmlrpc php7.4-zip
#
# 8.0
#
apt install -y php8.0 php8.0-fpm php8.0-cgi php8.0-mysql libapache2-mod-php8.0
apt install -y php8.0-curl php8.0-gd php8.0-imagick php8.0-intl php8.0-mbstring php8.0-readline
apt install -y php8.0-soap php8.0-xml php8.0-xmlrpc php8.0-zip
#
# 8.1
#
apt install -y php8.1 php8.1-fpm php8.1-cgi php8.1-mysql libapache2-mod-php8.1
apt install -y php8.1-curl php8.1-gd php8.1-imagick php8.1-intl php8.1-mbstring php8.1-readline
apt install -y php8.1-soap php8.1-xml php8.1-xmlrpc php8.1-zip
#
# 8.2
#
apt install -y php8.2 php8.2-fpm php8.2-cgi php8.2-mysql libapache2-mod-php8.2
apt install -y php8.2-curl php8.2-gd php8.2-imagick php8.2-intl php8.2-mbstring php8.2-readline
apt install -y php8.2-soap php8.2-xml php8.2-xmlrpc php8.2-zip
#
# 8.3
#
apt install -y php8.3 php8.3-fpm php8.3-cgi php8.3-mysql libapache2-mod-php8.3
apt install -y php8.3-curl php8.3-gd php8.3-imagick php8.3-intl php8.3-mbstring php8.3-readline
apt install -y php8.3-soap php8.3-xml php8.3-xmlrpc php8.3-zip

Install only the versions you need/want. My suggestion is to (re)install whatever version that is current for the OS release you are running (as for this time Ubuntu 22.04 LTS = php 8.1), the version by default installed when updating with Ondrej’s repository (for now 8.2), the current release of PHP (8.3) and if really necessary the last ‘legacy’ version (7.4).

Set new default PHP version used by Apache

To set the default PHP version to use when not overridden by SetHandler below, use the commands a2dismod and a2enmod.
Set default to PHP 8.3

a2dismod php8.1
a2enmod php8.3
systemctl restart apache2

Set default to PHP 7.4

a2dismod php8.3
a2enmod php7.4
systemctl restart apache2

Configuring PHP version for virtual host or subfolder

Activate necessary Apache modules and restart Apache:

a2enmod actions fcgid alias proxy_fcgi
systemctl restart apache2

Use FilesMatch directive to set the PHP version:
FilesMatch is valid in both the virtualhost configuration and inside a Directory section.
To set PHP version globally for a virtual host, use it outside a Directory section.

<FilesMatch \.php$>
  SetHandler "proxy:unix:/run/php/php8.2-fpm.sock|fcgi://localhost"
</FilesMatch>

The default PHP version can be set using ‘a2enmod php8.2’ (or any other version)

Check the configuration for errors:

apachectl configtest

If result is “Syntax OK”, restart Apache:

systemctl restart apache2

Overriding PHP version using .htaccess

For this to work, “AllowOverride FileInfo” must be present for the directory (or above) in which the .htaccess file will be used to set the PHP version.
For the default virtual host, the DocumentRoot is set to /var/www/html, so to allow PHP version to be set by .htaccess at that level or below, the following must be present in the vhost configuration:

  <Directory /var/www/html>
    AllowOverride FileInfo
  </Directory>

When this has been set, FilesMatch and SetHandler (as described above) can be used within the .htaccess file. The .htaccess method have higher priority than what is set for the virtualhost, or the subfolder within the DocumentRoot of the virtual host.

Testing

Create a file named ‘i.php’ in the locations with the different PHP versions (can be different virtualhosts or folders)

<?php
phpversion();
?>

Access these locations on the virtualhosts or their directory locations to verify that they are using different PHP versions.

See also Securing Apache HTTPd and PHP sites by running under user accounts

References

Most useful resource for this guide
How To Run Multiple PHP Versions on One Server Using Apache and PHP-FPM on Ubuntu 18.04 (DigitalOcean Community)

Javascript

https://stackoverflow.com/questions/43958335/select-folder-instead-of-single-file-input
https://stackoverflow.com/questions/14425007/get-metadata-of-local-mp3-file-using-html5-filesystem-api
https://stackoverflow.com/questions/3544898/what-does-a-colon-mean-within-an-html-id-attribute
https://stackoverflow.com/questions/441018/replacing-spaces-with-underscores-in-javascript
https://stackoverflow.com/questions/42526032/how-to-find-if-element-with-specific-id-exists-or-not/42526074
https://stackoverflow.com/questions/4250364/how-to-trim-a-file-extension-from-a-string-in-javascript
https://stackoverflow.com/questions/19331606/onclick-add-image-to-div
https://www.google.se/search?q=select+local+file+play+with+html5&oq=select+local+file+play+with+html5
Detect if HTML5 video is playing or paused and show or hide a Div accordingly
https://stackoverflow.com/questions/31307146/javascript-button-stop-all-audio-on-page
https://stackoverflow.com/questions/3623110/get-an-elements-id
https://www.google.com/search?q=javascript+store+data+inside+a+div&ie=utf-8&oe=utf-8&client=firefox-b
https://stackoverflow.com/questions/5785833/how-to-change-link-hrefs-via-javascript
Using files from web applications

HTML & CSS

Responsive IFRAMEs — The Right Way (CSS Only)!
How to Auto-resize an Image to Fit into a DIV Container using CSS

Everything You Need to Know About HTML’s ‘pre’ Element

CSS selector last row from main table
https://stackoverflow.com/questions/16010791/css-selector-last-row-from-main-table

Google search – “html5 canvas layers transparency”
https://www.google.se/search?q=html5+canvas+layers+transparency

Tutorial: How To Style the HTML 5 Audio Player
https://serversideup.net/style-the-html-5-audio-element/

Play local video file with HTML5
https://jsfiddle.net/dsbonev/cCCZ2/

Use Fetch as Google for websites
https://support.google.com/webmasters/answer/6066468?hl=en

hreview-examples
http://microformats.org/wiki/hreview-examples

PDF from every page of website
https://mpdf.github.io/real-life-examples/pdf-from-every-page-of-website.html

Google: php add protection to existing pdf
https://www.google.se/search?q=php+add+protection+to+existing+pdf

Custom colored Bootstrap button
https://codepen.io/anon/pen/RdBqbY
http://blog.koalite.com/bbg/

Styling checkboxes
https://stackoverflow.com/questions/49355676/trying-to-change-color-of-custom-checkbox-label-when-checked-css-only

Text
Background
Border (darken background 10%)
Active (darken background 7.5%)

SSL certificate / VPN

SSL

Let’s Encrypt
https://letsencrypt.org/docs/
https://letsencrypt.org/getting-started/
https://weblog.west-wind.com/posts/2016/Feb/22/Using-Lets-Encrypt-with-IIS-on-Windows
How To Secure Apache with Let’s Encrypt on Ubuntu 20.04
Configuring Let’s Encrypt SSL Cert for Apache on Ubuntu 18.04
Let’s Debug

SSL for free
https://www.sslforfree.com/

RapidSSL
https://www.rapidssl.com/

Certbot
https://certbot.eff.org/

https on subdomain
https://se.godaddy.com/community/Managing-Domains/https-on-subdomain/td-p/30668

SSL Server Test
How to disable outdated versions of SSL/TLS in Apache

VPN

https://support.ivacy.com/kb/how-to-configure-pptp-on-your-linksys-router/