One place for hosting & domains

      How To Use subprocess to Run External Programs in Python 3


      The author selected the COVID-19 Relief Fund to receive a donation as part of the Write for DOnations program.

      Introduction

      Python 3 includes the subprocess module for running external programs and reading their outputs in your Python code.

      You might find subprocess useful if you want to use another program on your computer from within your Python code. For example, you might want to invoke git from within your Python code to retrieve files in your project that are tracked in git version control. Since any program you can access on your computer can be controlled by subprocess, the examples shown here will be applicable to any external program you might want to invoke from your Python code.

      subprocess includes several classes and functions, but in this tutorial we’ll cover one of subprocess’s most useful functions: subprocess.run. We’ll review its different uses and main keyword arguments.

      Prerequisites

      To get the most out of this tutorial, it is recommended to have some familiarity with programming in Python 3. You can review these tutorials for the necessary background information:

      Running an External Program

      You can use the subprocess.run function to run an external program from your Python code. First, though, you need to import the subprocess and sys modules into your program:

      import subprocess
      import sys
      
      result = subprocess.run([sys.executable, "-c", "print('ocean')"])
      

      If you run this, you will receive output like the following:

      Output

      ocean

      Let’s review this example:

      • sys.executable is the absolute path to the Python executable that your program was originally invoked with. For example, sys.executable might be a path like /usr/local/bin/python.
      • subprocess.run is given a list of strings consisting of the components of the command we are trying to run. Since the first string we pass is sys.executable, we are instructing subprocess.run to execute a new Python program.
      • The -c component is a python command line option that allows you to pass a string with an entire Python program to execute. In our case, we pass a program that prints the string ocean.

      You can think of each entry in the list that we pass to subprocess.run as being separated by a space. For example, [sys.executable, "-c", "print('ocean')"] translates roughly to /usr/local/bin/python -c "print('ocean')". Note that subprocess automatically quotes the components of the command before trying to run them on the underlying operating system so that, for example, you can pass a filename that has spaces in it.

      Warning: Never pass untrusted input to subprocess.run. Since subprocess.run has the ability to perform arbitrary commands on your computer, malicious actors can use it to manipulate your computer in unexpected ways.

      Capturing Output From an External Program

      Now that we can invoke an external program using subprocess.run, let’s see how we can capture output from that program. For example, this process could be useful if we wanted to use git ls-files to output all your files currently stored under version control.

      Note: The examples shown in this section require Python 3.7 or higher. In particular, the capture_output and text keyword arguments were added in Python 3.7 when it was released in June 2018.

      Let’s add to our previous example:

      import subprocess
      import sys
      
      result = subprocess.run(
          [sys.executable, "-c", "print('ocean')"], capture_output=True, text=True
      )
      print("stdout:", result.stdout)
      print("stderr:", result.stderr)
      

      If we run this code, we’ll receive output like the following:

      Output

      stdout: ocean stderr:

      This example is largely the same as the one introduced in the first section: we are still running a subprocess to print ocean. Importantly, however, we pass the capture_output=True and text=True keyword arguments to subprocess.run.

      subprocess.run returns a subprocess.CompletedProcess object that is bound to result. The subprocess.CompletedProcess object includes details about the external program’s exit code and its output. capture_output=True ensures that result.stdout and result.stderr are filled in with the corresponding output from the external program. By default, result.stdout and result.stderr are bound as bytes, but the text=True keyword argument instructs Python to instead decode the bytes into strings.

      In the output section, stdout is ocean (plus the trailing newline that print adds implicitly), and we have no stderr.

      Let’s try an example that produces a non-empty value for stderr:

      import subprocess
      import sys
      
      result = subprocess.run(
          [sys.executable, "-c", "raise ValueError('oops')"], capture_output=True, text=True
      )
      print("stdout:", result.stdout)
      print("stderr:", result.stderr)
      

      If we run this code, we receive output like the following:

      Output

      stdout: stderr: Traceback (most recent call last): File "<string>", line 1, in <module> ValueError: oops

      This code runs a Python subprocess that immediately raises a ValueError. When we inspect the final result, we see nothing in stdout and a Traceback of our ValueError in stderr. This is because by default Python writes the Traceback of the unhandled exception to stderr.

      Raising an Exception on a Bad Exit Code

      Sometimes it’s useful to raise an exception if a program we run exits with a bad exit code. Programs that exit with a zero code are considered successful, but programs that exit with a non-zero code are considered to have encountered an error. As an example, this pattern could be useful if we wanted to raise an exception in the event that we run git ls-files in a directory that wasn’t actually a git repository.

      We can use the check=True keyword argument to subprocess.run to have an exception raised if the external program returns a non-zero exit code:

      import subprocess
      import sys
      
      result = subprocess.run([sys.executable, "-c", "raise ValueError('oops')"], check=True)
      

      If we run this code, we receive output like the following:

      Output

      Traceback (most recent call last): File "<string>", line 1, in <module> ValueError: oops Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python3.8/subprocess.py", line 512, in run raise CalledProcessError(retcode, process.args, subprocess.CalledProcessError: Command '['/usr/local/bin/python', '-c', "raise ValueError('oops')"]' returned non-zero exit status 1.

      This output shows that we ran a subprocess that raised an error, which is printed in stderr in our terminal. Then subprocess.run dutifully raised a subprocess.CalledProcessError on our behalf in our main Python program.

      Alternatively, the subprocess module also includes the subprocess.CompletedProcess.check_returncode method, which we can invoke for similar effect:

      import subprocess
      import sys
      
      result = subprocess.run([sys.executable, "-c", "raise ValueError('oops')"])
      result.check_returncode()
      

      If we run this code, we’ll receive:

      Output

      Traceback (most recent call last): File "<string>", line 1, in <module> ValueError: oops Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python3.8/subprocess.py", line 444, in check_returncode raise CalledProcessError(self.returncode, self.args, self.stdout, subprocess.CalledProcessError: Command '['/usr/local/bin/python', '-c', "raise ValueError('oops')"]' returned non-zero exit status 1.

      Since we didn’t pass check=True to subprocess.run, we successfully bound a subprocess.CompletedProcess instance to result even though our program exited with a non-zero code. Calling result.check_returncode(), however, raises a subprocess.CalledProcessError because it detects the completed process exited with a bad code.

      Using timeout to Exit Programs Early

      subprocess.run includes the timeout argument to allow you to stop an external program if it is taking too long to execute:

      import subprocess
      import sys
      
      result = subprocess.run([sys.executable, "-c", "import time; time.sleep(2)"], timeout=1)
      

      If we run this code, we’ll receive output like the following:

      Output

      Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python3.8/subprocess.py", line 491, in run stdout, stderr = process.communicate(input, timeout=timeout) File "/usr/local/lib/python3.8/subprocess.py", line 1024, in communicate stdout, stderr = self._communicate(input, endtime, timeout) File "/usr/local/lib/python3.8/subprocess.py", line 1892, in _communicate self.wait(timeout=self._remaining_time(endtime)) File "/usr/local/lib/python3.8/subprocess.py", line 1079, in wait return self._wait(timeout=timeout) File "/usr/local/lib/python3.8/subprocess.py", line 1796, in _wait raise TimeoutExpired(self.args, timeout) subprocess.TimeoutExpired: Command '['/usr/local/bin/python', '-c', 'import time; time.sleep(2)']' timed out after 0.9997982999999522 seconds

      The subprocess we tried to run used the time.sleep function to sleep for 2 seconds. However, we passed the timeout=1 keyword argument to subprocess.run to time out our subprocess after 1 second. This explains why our call to subprocess.run ultimately raised a subprocess.TimeoutExpired exception.

      Note that the timeout keyword argument to subprocess.run is approximate. Python will make a best effort to kill the subprocess after the timeout number of seconds, but it won’t necessarily be exact.

      Passing Input to Programs

      Sometimes programs expect input to be passed to them via stdin.

      The input keyword argument to subprocess.run allows you to pass data to the stdin of the subprocess. For example:

      import subprocess
      import sys
      
      result = subprocess.run(
          [sys.executable, "-c", "import sys; print(sys.stdin.read())"], input=b"underwater"
      )
      

      We’ll receive output like the following after running this code:

      Output

      underwater

      In this case, we passed the bytes underwater to input. Our target subprocess used sys.stdin to read the passed in stdin (underwater) and printed it out in our output.

      The input keyword argument can be useful if you want to chain multiple subprocess.run calls together passing the output of one program as the input to another.

      Conclusion

      The subprocess module is a powerful part of the Python standard library that lets you run external programs and inspect their outputs easily. In this tutorial, you have learned to use subprocess.run to control external programs, pass input to them, parse their output, and check their return codes.

      The subprocess module exposes additional classes and utilities that we did not cover in this tutorial. Now that you have a baseline, you can use the subprocess module’s documentation to learn more about other available classes and utilities.



      Source link

      How To Run Multiple PHP Versions on One Server Using Apache and PHP-FPM on Ubuntu 20.04


      Not using Ubuntu 20.04?


      Choose a different version or distribution.

      The author selected the COVID-19 Relief Fund to receive a donation as part of the Write for DOnations program.

      Introduction

      The Apache web server uses virtual hosts to manage multiple domains on a single instance. Similarly, PHP-FPM uses a daemon to manage multiple PHP versions on a single instance. Together, you can use Apache and PHP-FPM to host multiple PHP web-applications, each using a different version of PHP, all on the same server, and all at the same time. This is useful because different applications may require different versions of PHP, but some server stacks, like a regularly configured LAMP stack, can only manage one. Combining Apache with PHP-FPM is also a more cost-efficient solution than hosting each application on its own instance.

      PHP-FPM also offers configuration options for stderr and stdout logging, emergency restarts, and adaptive process spawning, which is useful for heavy-loaded sites. In fact, using Apache with PHP-FPM is one of the best stacks for hosting PHP applications, especially when it comes to performance.

      In fact, using Apache with PHP-FPM is one of the best stacks for hosting PHP applications, especially when it comes to performance. PHP-FPM not only allows you run to multiple PHP versions simultaneously, it also provides numerous extra features like adaptive process spawning, which is useful for heavy-loaded sites.

      In this tutorial you will set up two PHP sites on a single instance. Each site will use its own domain, and each domain will deploy its own version of PHP. The first, site1.your_domain, will deploy PHP 7.2. The second, site2.your_domain, will deploy PHP 7.3.

      Prerequisites

      Step 1 — Installing PHP Versions 7.2 and 7.3 with PHP-FPM

      With the prerequisites completed, you will now install PHP versions 7.2 and 7.3, as well as PHP-FPM and several additional extensions. But to accomplish this, you will first need to add the Ondrej PHP repository to your system.

      Execute the apt-get command to install software-properties-common:

      • sudo apt-get install software-properties-common -y

      The software-properties-common package provides apt-add-repository command-line utility which you will use to add the ondrej/php PPA (Personal Package Archive) repository.

      Now add the ondrej/php repository to your system. The ondrej/php PPA will have more up-to-date versions of PHP than the official Ubuntu repositories, and it will also allow you to install multiple versions of PHP in the same system:

      • sudo add-apt-repository ppa:ondrej/php

      Update the repository:

      Next, install php7.2, php7.2-fpm, php7.2-mysql, libapache2-mod-php7.2, and libapache2-mod-fcgid with the following commands:

      • sudo apt-get install php7.2 php7.2-fpm php7.2-mysql libapache2-mod-php7.2 libapache2-mod-fcgid -y
      • php7.2 is a metapackage used to run PHP applications.
      • php7.2-fpm provides the Fast Process Manager interpreter that runs as a daemon and receives Fast/CGI requests.
      • php7.2-mysql connects PHP to the MySQL database.
      • libapache2-mod-php7.2 provides the PHP module for the Apache webserver.
      • libapache2-mod-fcgid contains a mod_fcgid that starts a number of CGI program instances to handle concurrent requests.

      Now repeat the process for PHP version 7.3. Install php7.3, php7.3-fpm, php7.3-mysql, and libapache2-mod-php7.3.

      • sudo apt-get install php7.3 php7.3-fpm php7.3-mysql libapache2-mod-php7.3 -y

      After installing both PHP versions, start the php7.2-fpm service:

      • sudo systemctl start php7.2-fpm

      Next, verify the status of php7.2-fpm service:

      • sudo systemctl status php7.2-fpm

      You’ll see the following output:

      Output

      • ● php7.2-fpm.service - The PHP 7.2 FastCGI Process Manager
      • Loaded: loaded (/lib/systemd/system/php7.2-fpm.service; enabled; vendor preset: enabled)
      • Active: active (running) since Fri 2020-06-05 11:25:07 UTC; 1min 38s ago
      • Docs: man:php-fpm7.2(8)
      • Main PID: 13703 (php-fpm7.2)
      • Status: "Processes active: 0, idle: 2, Requests: 0, slow: 0, Traffic: 0req/sec"
      • Tasks: 3 (limit: 2353)
      • Memory: 6.2M
      • CGroup: /system.slice/php7.2-fpm.service
      • ├─13703 php-fpm: master process (/etc/php/7.2/fpm/php-fpm.conf)
      • ├─13719 php-fpm: pool www
      • └─13720 php-fpm: pool www
      • Jun 05 11:25:07 ubuntu systemd[1]: Starting The PHP 7.2 FastCGI Process Manager...
      • Jun 05 11:25:07 ubuntu systemd[1]: Started The PHP 7.2 FastCGI Process Manager.

      Repeating this process, now start the php7.3-fpm service:

      • sudo systemctl start php7.3-fpm

      Next, verify the status of php7.3-fpm service:

      • sudo systemctl status php7.3-fpm

      You’ll see the following output:

      Output

      • ● php7.3-fpm.service - The PHP 7.3 FastCGI Process Manager
      • Loaded: loaded (/lib/systemd/system/php7.3-fpm.service; enabled; vendor preset: enabled)
      • Active: active (running) since Fri 2020-06-05 11:26:33 UTC; 56s ago
      • Docs: man:php-fpm7.3(8)
      • Process: 23470 ExecStartPost=/usr/lib/php/php-fpm-socket-helper install /run/php/php-fpm.sock /etc/php/7.3/fpm/pool.d/www.conf 73 (code=ex>
      • Main PID: 23452 (php-fpm7.3)
      • Status: "Processes active: 0, idle: 2, Requests: 0, slow: 0, Traffic: 0req/sec"
      • Tasks: 3 (limit: 2353)
      • Memory: 7.1M
      • CGroup: /system.slice/php7.3-fpm.service
      • ├─23452 php-fpm: master process (/etc/php/7.3/fpm/php-fpm.conf)
      • ├─23468 php-fpm: pool www
      • └─23469 php-fpm: pool www
      • Jun 05 11:26:33 ubuntu systemd[1]: Starting The PHP 7.3 FastCGI Process Manager...
      • Jun 05 11:26:33 ubuntu systemd[1]: Started The PHP 7.3 FastCGI Process Manager.

      Lastly, you must enable several modules so that your Apache2 service can work with multiple PHP versions:

      • sudo a2enmod actions fcgid alias proxy_fcgi
      • actions is used for executing CGI scripts based on media type or request method.

      • fcgid is a high performance alternative to mod_cgi that starts a sufficient number of instances of the CGI program to handle concurrent requests.

      • alias provides for the mapping of different parts of the host filesystem in the document tree, and for URL redirection.

      • proxy_fcgi allows Apache to forward requests to PHP-FPM.

      Now restart the Apache service to apply your changes:

      • sudo systemctl restart apache2

      At this point you have installed two PHP versions on your server. Next, you will create a directory structure for each website you want to deploy.

      Step 2 — Creating Directory Structures for Both Websites

      In this section, you will create a document root directory and an index page for each of your two websites.

      First, create document root directories for both site1.your_domain and site2.your_domain:

      • sudo mkdir /var/www/site1.your_domain
      • sudo mkdir /var/www/site2.your_domain

      By default, the Apache webserver runs as a www-data user and www-data group. To ensure that you have the correct ownership and permissions of your website root directories, execute the following commands:

      • sudo chown -R www-data:www-data /var/www/site1.your_domain
      • sudo chown -R www-data:www-data /var/www/site2.your_domain
      • sudo chmod -R 755 /var/www/site1.your_domain
      • sudo chmod -R 755 /var/www/site2.your_domain

      Next you will create an info.php file inside each website root directory. This will display each website’s PHP version information. Begin with site1:

      • sudo nano /var/www/site1.your_domain/info.php

      Add the following line:

      /var/www/site1.your_domain/info.php

      <?php phpinfo(); ?>
      

      Save and close the file. Now copy the info.php file you created to site2:

      • sudo cp /var/www/site1.your_domain/info.php /var/www/site2.your_domain/info.php

      Your web server should now have the document root directories that each site requires to serve data to visitors. Next, you will configure your Apache web server to work with two different PHP versions.

      Step 3 — Configuring Apache for Both Websites

      In this section, you will create two virtual host configuration files. This will enable your two websites to work simultaneously with two different PHP versions.

      In order for Apache to serve this content, it is necessary to create a virtual host file with the correct directives. Instead of modifying the default configuration file located at /etc/apache2/sites-available/000-default.conf, you’ll create two new ones inside the directory /etc/apache2/sites-available/.

      First create a new virtual host configuration file for the website site1.your_domain. Here you will direct Apache to render content using php7.2:

      • sudo nano /etc/apache2/sites-available/site1.your_domain.conf

      Add the following content. Make sure the website directory path, server name, and PHP version match your setup:

      /etc/apache2/sites-available/site1.your_domain.conf

      
      <VirtualHost *:80>
           ServerAdmin admin@site1.your_domain
           ServerName site1.your_domain
           DocumentRoot /var/www/site1.your_domain
           DirectoryIndex info.php
      
           <Directory /var/www/site1.your_domain>
              Options Indexes FollowSymLinks MultiViews
              AllowOverride All
              Order allow,deny
              allow from all
           </Directory>
      
          <FilesMatch .php$>
              # From the Apache version 2.4.10 and above, use the SetHandler to run PHP as a fastCGI process server
               SetHandler "proxy:unix:/run/php/php7.2-fpm.sock|fcgi://localhost"
          </FilesMatch>
      
           ErrorLog ${APACHE_LOG_DIR}/site1.your_domain_error.log
           CustomLog ${APACHE_LOG_DIR}/site1.your_domain_access.log combined
      </VirtualHost>
      

      In this file you updated the DocumentRoot to your new directory and ServerAdmin to an email that the your_domain site administrator can access. You’ve also updated ServerName, which establishes the base domain for this virtual host configuration, and you’ve added a SetHandler directive to run PHP as a fastCGI process server.

      Save and close the file.

      Next, create a new virtual host configuration file for the website site2.your_domain. You will specify this subdomain to deploy php7.3:

      • sudo nano /etc/apache2/sites-available/site2.your_domain.conf

      Add the following content. Again, make sure the website directory path, server name, and PHP version match your unique information:

      /etc/apache2/sites-available/site2.your_domain.conf

      <VirtualHost *:80>
           ServerAdmin admin@site2.your_domain
           ServerName site2.your_domain
           DocumentRoot /var/www/site2.your_domain
           DirectoryIndex info.php
      
           <Directory /var/www/site2.your_domain>
              Options Indexes FollowSymLinks MultiViews
              AllowOverride All
              Order allow,deny
              allow from all
           </Directory>
      
          <FilesMatch .php$>
              # 2.4.10+ can proxy to unix socket
               SetHandler "proxy:unix:/run/php/php7.3-fpm.sock|fcgi://localhost"
          </FilesMatch>
      
           ErrorLog ${APACHE_LOG_DIR}/site2.your_domain_error.log
           CustomLog ${APACHE_LOG_DIR}/site2.your_domain_access.log combined
      </VirtualHost>
      

      Save and close the file when you are finished. Then, check the Apache configuration file for any syntax errors:

      • sudo apachectl configtest

      You’ll see the following output:

      Output

      Next, enable both virtual host configuration files with the following commands:

      • sudo a2ensite site1.your_domain
      • sudo a2ensite site2.your_domain

      Now disable the default site, since you won’t need it.:

      • sudo a2dissite 000-default.conf

      Finally, restart the Apache service to implement your changes:

      • sudo systemctl restart apache2

      Now that you have configured Apache to serve each site, you will test them to make sure the proper PHP versions are running.

      Step 4 — Testing Both Websites

      At this point, you have configured two websites to run two different versions of PHP. Now test the results.

      Open your web browser and visit both sites http://site1.your_domain and http://site2.your_domain. You will see two pages that look like this:

      PHP 7.2 info page
      PHP 7.3 info page

      Note the titles. The first page indicates that site1.your_domain deployed PHP version 7.2. The second indicates that site2.your_domain deployed PHP version 7.3.

      Now that you’ve tested your sites, remove the info.php files. Because they contain sensitive information about your server and are accessible to unauthorized users, they pose a security vulnerability. To remove both files, run the following commands:

      • sudo rm -rf /var/www/site1.your_domain/info.php
      • sudo rm -rf /var/www/site2.your_domain/info.php

      You now have a single Ubuntu 20.04 server handling two websites with two different PHP versions. PHP-FPM, however, is not limited to this one application.

      Conclusion

      You have now combined virtual hosts and PHP-FPM to serve multiple websites and multiple versions of PHP on a single server. The only practical limit on the number of PHP sites and PHP versions that your Apache service can handle is the processing power of your instance.

      From here you might consider exploring PHP-FPM’s more advanced features, like its adaptive spawning process or how it can log sdtout and stderr Alternatively, you could now secure your websites. To accomplish this, you can follow our tutorial on how to secure your sites with free TLS/SSL certificates from Let’s Encrypt.



      Source link

      How To Run Multiple PHP Versions on One Server Using Apache and PHP-FPM on CentOS 8


      Not using CentOS 8?


      Choose a different version or distribution.

      The author selected the COVID-19 Relief Fund to receive a donation as part of the Write for DOnations program.

      Introduction

      The Apache web server uses virtual hosts to manage multiple domains on a single instance. Similarly, PHP-FPM uses a daemon to manage multiple PHP versions on a single instance. Together, you can use Apache and PHP-FPM to host multiple PHP web-applications, each using a different version of PHP, all on the same server, and all at the same time. This is useful because different applications may require different versions of PHP, but some server stacks, like a regularly configured LAMP stack, can only manage one. Combining Apache with PHP-FPM is also a more cost-efficient solution than hosting each application on its own instance.

      PHP-FPM also offers configuration options for stderr and stdout logging, emergency restarts, and adaptive process spawning, which is useful for heavy-loaded sites. In fact, using Apache with PHP-FPM is one of the best stacks for hosting PHP applications, especially when it comes to performance.

      In this tutorial you will set up two PHP sites on a single instance. Each site will use its own domain, and each domain will deploy its own version of PHP. The first, site1.your_domain, will deploy PHP 7.3. The second, site2.your_domain, will deploy PHP 7.4.

      Prerequisites

      Step 1 — Installing PHP Versions 7.3 and 7.4 with PHP-FPM

      With the prerequisites completed, you will now install PHP versions 7.3 and 7.4, as well as PHP-FPM and several additional extensions. In order to install multiple versions of PHP, you will need to install and enable the Remi repository to your system. Which also offers the latest versions of the PHP stack on CentOS 8 system.

      You can add the both repository to your system using the below commands:

      • sudo dnf install http://rpms.remirepo.net/enterprise/remi-release-8.rpm

      The command above will also enable the EPEL repository.

      First let’s discover what versions of PHP 7 are available on Remi:

      You’ll see an output like this:

      Output

      Remi's Modular repository for Enterprise Linux 8 - x86_64 Name Stream Profiles Summary php remi-7.2 common [d], devel, minimal PHP scripting language php remi-7.3 common [d], devel, minimal PHP scripting language php remi-7.4 common [d], devel, minimal PHP scripting language

      Next, disable the default PHP module and enable Remi’s PHP7.3 module using the below command:

      • sudo dnf module reset php
      • sudo dnf module enable php:remi-7.3

      Lets start to installing php73 and php73-php-fpm:

      • sudo dnf install php73 php73-php-fpm -y
      • php73 is a metapackage that can be used to run PHP application.
      • php73-php-fpm provides the Fast Process Manager interpreter that runs as a daemon and receives Fast/CGI requests.

      Now repeat the process for PHP version 7.4. Install php74 and php74-php-fpm.

      • sudo dnf module reset php
      • sudo dnf module enable php:remi-7.4
      • sudo dnf install php74 php74-php-fpm -y

      After installing both PHP versions, start the php73-php-fpm service and enable it to start at boot with the following commands:

      • sudo systemctl start php73-php-fpm
      • sudo systemctl enable php73-php-fpm

      Next, verify the status of php73-php-fpm service with the following commands:

      • sudo systemctl status php73-php-fpm

      You’ll see the following output:

      • ● php73-php-fpm.service - The PHP FastCGI Process Manager
      • Loaded: loaded (/usr/lib/systemd/system/php73-php-fpm.service; enabled; vendor preset: disabled)
      • Active: active (running) since Wed 2020-04-22 05:14:46 UTC; 52s ago
      • Main PID: 14206 (php-fpm)
      • Status: "Processes active: 0, idle: 5, Requests: 0, slow: 0, Traffic: 0req/sec"
      • Tasks: 6 (limit: 5059)
      • Memory: 25.9M
      • CGroup: /system.slice/php73-php-fpm.service
      • ├─14206 php-fpm: master process (/etc/opt/remi/php73/php-fpm.conf)
      • ├─14207 php-fpm: pool www
      • ├─14208 php-fpm: pool www
      • ├─14209 php-fpm: pool www
      • ├─14210 php-fpm: pool www
      • └─14211 php-fpm: pool www
      • Apr 22 05:14:46 centos-s-1vcpu-1gb-nyc3-01 systemd[1]: Starting The PHP FastCGI Process Manager...
      • Apr 22 05:14:46 centos-s-1vcpu-1gb-nyc3-01 systemd[1]: Started The PHP FastCGI Process Manager.

      Repeating this process, now start the php74-php-fpm service and enable it to start at boot with the following commands:

      • sudo systemctl start php74-php-fpm
      • sudo systemctl enable php74-php-fpm

      And then verify the status of php74-php-fpm service with the following commands:

      • sudo systemctl status php74-php-fpm

      You’ll see the following output:

      • ● php74-php-fpm.service - The PHP FastCGI Process Manager
      • Loaded: loaded (/usr/lib/systemd/system/php74-php-fpm.service; enabled; vendor preset: disabled)
      • Active: active (running) since Wed 2020-04-22 05:16:16 UTC; 23s ago
      • Main PID: 14244 (php-fpm)
      • Status: "Processes active: 0, idle: 5, Requests: 0, slow: 0, Traffic: 0req/sec"
      • Tasks: 6 (limit: 5059)
      • Memory: 18.8M
      • CGroup: /system.slice/php74-php-fpm.service
      • ├─14244 php-fpm: master process (/etc/opt/remi/php74/php-fpm.conf)
      • ├─14245 php-fpm: pool www
      • ├─14246 php-fpm: pool www
      • ├─14247 php-fpm: pool www
      • ├─14248 php-fpm: pool www
      • └─14249 php-fpm: pool www
      • Apr 22 05:16:15 centos-s-1vcpu-1gb-nyc3-01 systemd[1]: Starting The PHP FastCGI Process Manager...
      • Apr 22 05:16:16 centos-s-1vcpu-1gb-nyc3-01 systemd[1]: Started The PHP FastCGI Process Manager.

      At this point you have installed two PHP versions on your server. Next, you will create a directory structure for each website you want to deploy.

      Step 2 — Creating Directory Structures for Both Websites

      In this section, you will create a document root directory and an index page for each of your two websites.

      First, create document root directories for both site1.yourdomain and site2.yourdomain:

      • sudo mkdir /var/www/site1.your_domain
      • sudo mkdir /var/www/site2.your_domain

      By default, Apache webserver runs as a apache user and apache group. To ensure that you have the correct ownership and permissions of your website root directories, execute the following commands:

      • sudo chown -R apache:apache /var/www/site1.your_domain
      • sudo chown -R apache:apache /var/www/site2.your_domain
      • sudo chmod -R 755 /var/www/site1.your_domain
      • sudo chmod -R 755 /var/www/site2.your_domain

      The chown command changes the ownership of your two website directories to the apache user and the apache group. The chmod command changes the permissions associated with that user and group, as well as others.

      Next you will create an info.php file inside each website root directory. This will display each website’s PHP version information. Begin with site1:

      • sudo vi /var/www/site1.your_domain/info.php

      Add the following line:

      site1.your_domain/info.php’>/var/www/site1.your_domain/info.php

      <?php phpinfo(); ?>
      

      Save and close the file. Now copy the info.php file you created to site2:

      • sudo cp /var/www/site1.your_domain/info.php /var/www/site2.your_domain/info.php

      Your web server now has the document root directories that each site requires to serve data to visitors. Next, you will configure your Apache web server to work with two different PHP versions.

      Step 3 — Configuring Apache for Both Websites

      In this section, you will create two virtual host configuration files. This will enable your two websites to work simultaneously with two different PHP versions.

      In order for Apache to serve this content, it is necessary to create a virtual host file with the correct directives. You’ll create two new virtual host configuration file inside the directory /etc/httpd/conf.d/.

      First create a new virtual host configuration file for the website site1.your_domain. Here you will direct Apache to render content using php7.3:

      • sudo vi /etc/httpd/conf.d/site1.your_domain.conf

      Add the following content. Make sure the website directory path, server name, and PHP version match your setup:

      /etc/httpd/conf.d/site1.your_domain.conf

      <VirtualHost *:80>
           ServerAdmin admin@site1.your_domain
           ServerName site1.your_domain
           DocumentRoot /var/www/site1.your_domain
           DirectoryIndex info.php
           ErrorLog /var/log/httpd/site1.your_domain-error.log
           CustomLog /var/log/httpd/site1.your_domain-access.log combined
      
        <IfModule !mod_php7.c>
          <FilesMatch .(php|phar)$>
              SetHandler "proxy:unix:/var/opt/remi/php73/run/php-fpm/www.sock|fcgi://localhost"
          </FilesMatch>
        </IfModule>
      
      </VirtualHost>
      

      For DocumentRoot you are specifying the path of your website root directory. For ServerAdmin you are adding an email that the your_domain site administrator can access. For ServerName you are adding the url for your first subdomain. For SetHandler you are specifying the PHP-FPM socket file for php7.3.

      Save and close the file.

      Next, create a new virtual host configuration file for the website site2.your_domain. You will specify this subdomain to deploy php7.4:

      • sudo vi /etc/httpd/conf.d/site2.your_domain.conf

      Add the following content. Again, make sure the website directory path, server name, and PHP version match your unique information:

      /etc/httpd/conf.d/site2.your_domain.conf

      <VirtualHost *:80>
           ServerAdmin admin@site2.your_domain
           ServerName site2.your_domain
           DocumentRoot /var/www/site2.your_domain
           DirectoryIndex info.php
           ErrorLog /var/log/httpd/site2.your_domain-error.log
           CustomLog /var/log/httpd/site2.your_domain-access.log combined
        <IfModule !mod_php7.c>
          <FilesMatch .(php|phar)$>
              SetHandler "proxy:unix:/var/opt/remi/php74/run/php-fpm/www.sock|fcgi://localhost"
          </FilesMatch>
        </IfModule>
      
      </VirtualHost>
      

      Save and close the file when you are finished. Then, check the Apache configuration file for any syntax errors with the following command:

      • sudo apachectl configtest

      You’ll see an output printing Syntax OK:

      Output

      Finally, restart the Apache service to implement your changes:

      • sudo systemctl restart httpd

      Now that you have configured Apache to serve each site, you will test them to make sure the proper PHP versions are running.

      Step 4 — Testing Both Websites

      At this point, you have configured two websites to run two different versions of PHP. Now test the results.

      Open your web browser and visit both sites http://site1.your_domain and http://site2.your_domain. You will see two pages that look like this:

      PHP 7.3 info page
      PHP 7.4 info page

      Note the titles. The first page indicates that site1.yourdomain deployed PHP version 7.3. The second indicates that site2.yourdomain deployed PHP version 7.4.

      Now that you’ve tested your sites, remove the info.php files. Because they contain sensitive information about your server and are accessible to unauthorized users, they pose a security vulnerability. To remove both files, run the following commands:

      • sudo rm -rf /var/www/site1.your_domain/info.php
      • sudo rm -rf /var/www/site2.your_domain/info.php

      You now have a single CentOS 8 server handling two websites with two different PHP versions. PHP-FPM, however, is not limited to this one application.

      Conclusion

      You have now combined virtual hosts and PHP-FPM to serve multiple websites and multiple versions of PHP on a single server. The only practical limit on the number of PHP sites and PHP versions that your Apache service can handle is the processing power of your instance.

      From here you might consider exploring PHP-FPM’s more advanced features, like its adaptive spawning process or how it can log sdtout and stderr. Alternatively, you could now secure your websites with free TLS/SSL certificates from Let’s Encrypt.



      Source link