Multiple version of php.

Remington

Aspiring Daemon

Reaction score: 194
Messages: 562

Another option is to compile PHP sources from php.net and put them in basejail created by ezjail. All jails will have access to different php versions without having to install in each jail.
 

wattie

Member

Reaction score: 2
Messages: 20

I am interested if the following will work:

FreeBSD 12 + OpenSSL 1.0.2 installed through ports
PHP 7.3 installed using the base OpenSSL (so it can be configured to use TLS 1.3)
PHP 5.6 installed using the OpenSSL from ports (so it can be... compiled) :)

Anybody tried this?
 

CyberCr33p

Well-Known Member

Reaction score: 38
Messages: 364

You can create a shell script to add the users accounts in the jail ( copy /etc/master.passwd and /etc/group to /home/jail/php56/etc directory ).

Then you can have another script inside jail and execute it using:

jexec php56 /root/scripts/syncJail.sh

Here is the script:

Code:
#!/usr/local/bin/bash

pwd_mkdb -p /etc/master.passwd

rm -fr /var/run/fastcgi/*

for username in `( grep "/home/www" /etc/passwd | awk '{split($0,a,":"); print a[1]}' )`
do
        mkdir /var/run/fastcgi/${username}
        chown ${username}:www /var/run/fastcgi/${username}
done

/usr/local/etc/rc.d/php-fpm restart >/dev/null 2>&1

And here is the /etc/fstab.php56 :

Code:
/home/www /home/jail/php56/home/www nullfs rw,noatime,nosuid 0 0
/tmp /home/jail/php56/tmp nullfs rw,noatime,nosuid 0 0
/tmpfs /home/jail/php56/tmpfs nullfs rw,noatime,nosuid 0 0

And the /etc/jail.conf :

Code:
mount.fstab = "/etc/fstab.${name}";
exec.start = "/bin/sh /etc/rc";
exec.stop = "/bin/sh /etc/rc.shutdown";
exec.clean;
mount.devfs;
path = "/home/jail/${name}";
allow.raw_sockets=1;

php56 {
        host.hostname = "php56";
        ip4.addr = xxx.xxx.xxx.xxx;
}

And in your web-server in vhost section you use the php socket from jail:

Code:
/home/jail/php56/var/run/fastcgi/username/username.socket
 

Nasrudin

Member

Reaction score: 20
Messages: 50

Go back to the beginning, why do you need to run two different versions in the first place? What problem are you trying to solve?

If you run multiple pools at the same time and want a different PHP version for some of them.
...
If I could run PHP 7.2 and 7.3 at the same time, I'd just point the apache or nginx config at the socket and that's it.

Almost exactly this idea.
It might help the case for jails if I knew exactly the difference in resource usage between a jailed daemon (to me this is the duplicate OS on the disk and perhaps a process or two) and a regular PHP-FPM daemon. Right now, it seems to be that multiple PHP versions will ultimately be lighterweight than jails (since you need a duplicate OS per jail and hence per php version). I do realize that there is a potentially awesome (but slight) security benefit to using jails in production, but I'd really like the option to implement multiple versions of PHP in different ways.

Perhaps, SirDice, this the implied search for rationale that you sought with your questions? :)

I do recognize that altering the ports/poudriere systems to support multiple versions of PHP on the same box might be too hard to accomplish; sometimes implementation answers in the FreeBSD space are really based on this kind of idea. So, it would be nice if this were asserted when it is the underlying case ... as this is a rationale I can also accept.

For my issues, there are two key use cases here:

- A development box which just needs to switch PHP versions on the fly for testing.
- A production box serving multiple sites which has legacy sites that cannot switch PHP versions "now".

So I'm still curious (whether it is perceived as a good idea by some or not) as to what is expected to happen if I do something like:

Code:
PHP_BUILDS=php70 php71 php72
.for port in ${PHP_ALT}
.if ${.CURDIR:M*/ports*/*/${port}*}
PREFIX=/usr/local/${port}
PHPBASE=/usr/local/${port}
DISABLE_VULNERABILITIES=yes
.endif
.endfor

Thanks in advance for any insight, including any "that's an absolutely horrible idea" comments. :D
 

Lamia

Aspiring Daemon

Reaction score: 212
Messages: 775

Have you taken a look at the php-virtmanager (something like that) in ports?

How about running each in separate chroot/jail?
 

Nasrudin

Member

Reaction score: 20
Messages: 50

Ok following up on this. I've been able to get this to work mostly with this code:

Makefile:
# PHP Makefile arm twisting follows.
p_PHP_FLAVORS=php71 php72 php73
p_GETFLAVOR=echo $$FLAVOR
p_FLAVOR=${p_GETFLAVOR:sh}

.for port in ${p_PHP_FLAVORS}

.if ${.CURDIR:M*/ports/*/${port}*}
PREFIX=/usr/local/${port}
PHPBASE=/usr/local/${port}
DISABLE_VULNERABILITIES=yes
.info set by CURDIR: ${.CURDIR} -- sets PREFIX: ${PREFIX} and PHPBASE: ${PHPBASE}
.endif

.if ${p_FLAVOR} == ${port}
PREFIX=/usr/local/${port}
PHPBASE=/usr/local/${port}
DISABLE_VULNERABILITIES=yes
.info set by FLAVOR ${p_FLAVOR} -- sets PREFIX: ${PREFIX} and PHPBASE: ${PHPBASE}
.endif

.endfor

I have one issue with devel/pear :

Code:
=======================<phase: stage          >============================
make: "/etc/make.conf" line 30: set by FLAVOR php71 -- sets PREFIX: /usr/local/php71 and PHPBASE: /usr/local/php71
===>  Staging for php71-pear-1.10.6
===>   Generating temporary packing list
env: /usr/local/bin/php: No such file or directory
*** Error code 127

Stop.
make: stopped in /usr/ports/devel/pear

I've no idea where to begin with this one, so it may be a while until I get this ironed out. Stay tuned.
 

Alexander Huemeyer

Member

Reaction score: 6
Messages: 32

I would just downloaded the sources form php.net and install to different locations accourding the php.net install advisories. Just make sure to track the php.net releasenotes for important updates.
 

Remington

Aspiring Daemon

Reaction score: 194
Messages: 562

I would just downloaded the sources form php.net and install to different locations accourding the php.net install advisories. Just make sure to track the php.net releasenotes for important updates.

That's exactly what I did and I have 3 different versions since some php apps will not work with newer php version. My php folders looks like this:

/usr/local/php/5.6
/usr/local/php/7.1
/usr/local/php/7.2

But I put them in /jail/basejail/usr/local/php/... so all of my jails will have access to it without having to compile or copy php files into each jail. Of course I have to mount them to the jails in /etc/jail.conf
 

Nasrudin

Member

Reaction score: 20
Messages: 50

Yeah the problem with downloading sources is that it's outside the FreeBSD ports system. People have spent time patching PHP for FreeBSD and I'd like to not only take advantage of that but to keep taking advantage of that.

Stay tuned...I think I have it working. I will post results here so someone can duplicate my work and see if it works for them.
 

Remington

Aspiring Daemon

Reaction score: 194
Messages: 562

Yeah the problem with downloading sources is that it's outside the FreeBSD ports system. People have spent time patching PHP for FreeBSD and I'd like to not only take advantage of that but to keep taking advantage of that.

Stay tuned...I think I have it working. I will post results here so someone can duplicate my work and see if it works for them.

I didn't have to patch anything. Once I had the setup done then its fairly simple to update.
 

rainer_d

Active Member

Reaction score: 9
Messages: 143

The problem with compiling your own PHP in a special location is that none of the ports that rely on PHP can use it.
So, in addition to PHP outside of pkg(8)-management, you will need to maintain the packages that depend on PHP also outside of pkg(8).
I could probably do that, but it would be a veritable nightmare to maintain IMO, especially in the long run and when you have this construct running on multiple servers.
Maybe you can just package-up all of /usr/local/php* and replace it - but it's still not "clean" enough for my taste.
And usually, if something does not look "clean", it's usually a bad solution to begin with.

Also, each PHP branch has now a sufficiently low lifetime that it's actually a PITA to migrate users to new physical servers each time the then-current version drops out of the ports-tree...
 

Remington

Aspiring Daemon

Reaction score: 194
Messages: 562

The problem with compiling your own PHP in a special location is that none of the ports that rely on PHP can use it.
So, in addition to PHP outside of pkg(8)-management, you will need to maintain the packages that depend on PHP also outside of pkg(8).
I could probably do that, but it would be a veritable nightmare to maintain IMO, especially in the long run and when you have this construct running on multiple servers.
Maybe you can just package-up all of /usr/local/php* and replace it - but it's still not "clean" enough for my taste.
And usually, if something does not look "clean", it's usually a bad solution to begin with.

Also, each PHP branch has now a sufficiently low lifetime that it's actually a PITA to migrate users to new physical servers each time the then-current version drops out of the ports-tree...

True. I have to select one PHP version to be the default version on the server BUT Nginx's website config can be configured to use specific PHP version. I have couple of websites running PHP 5.6, 7.3, 7.4 in the same jail.
 

Nasrudin

Member

Reaction score: 20
Messages: 50

The problem with compiling your own PHP in a special location is that none of the ports that rely on PHP can use it.
So, in addition to PHP outside of pkg(8)-management, you will need to maintain the packages that depend on PHP also outside of pkg(8).
...

I believe I've addressed this by trying to detect ports that rely on PHP. There is only one misbehaving port, devel/pear, and that was addressed by this patch:

Code:
40c40
<     @cd ${WRKSRC} && ${SETENV} DESTDIR=${STAGEDIR} ${PREFIX}/bin/php -q ./go-pear
---
>     @cd ${WRKSRC} && ${SETENV} DESTDIR=${STAGEDIR} ${LOCALBASE}/bin/php -q ./go-pear

So far (we are still testing) this all works. I build from poudriere. Pkg still knows what to do and how to install all of this. You can leave out the .info lines if you wish.

Code:
# PHP Makefile arm twisting follows.
p_PHP_FLAVORS=php71 php72 php73 php74
p_GETFLAVOR=echo $$FLAVOR
p_FLAVOR=${p_GETFLAVOR:sh}

.for port in ${p_PHP_FLAVORS}

# Easy part. If your current directory begins with what's in PHP_ALT, you need these variables
.if ${.CURDIR:M*/ports/*/${port}*}
PREFIX=/usr/local/${port}
PHPBASE=/usr/local/${port}
DISABLE_VULNERABILITIES=yes
.info set by CURDIR: ${.CURDIR} -- sets PREFIX: ${PREFIX} and PHPBASE: ${PHPBASE}
.endif

# Harder part, if we detect the flavor is set up via shell environment, you need these variables
.if ${p_FLAVOR} == ${port}
PREFIX=/usr/local/${port}
PHPBASE=/usr/local/${port}
DISABLE_VULNERABILITIES=yes
.info set by FLAVOR ${p_FLAVOR} -- sets PREFIX: ${PREFIX} and PHPBASE: ${PHPBASE}
.endif

.endfor

Any feedback or nits to pick are warmly appreciated. If someone who knows more of what they are doing can somehow get this behavior into the ports system under a knob (no I am not holding my breath lol) that would be awesome.
 

rainer_d

Active Member

Reaction score: 9
Messages: 143

Hi,

where do you place that code?

Maybe you an submit a PR, so ports-maintainers can comment?


Thanks for you efforts!
 

ecazamir

Active Member

Reaction score: 34
Messages: 219

I'll share my thoughts on this matter, even though this subject is old.
Installing multiple PHP versions on a single machine IS possible, with acceptable level of dependency mess/conflicts, at least as long as PEAR is not involved, and standard PHP extensions are installed.
As mentioned on one of the previous messages, two compile-time defines are critical, PHPBASE and PREFIX. I'm using portupgrade to build the packages locally, therfore I use the following block on /usr/local/etc/pkgtools.conf, I'm sure similar options can be set for other package managers

INI:
  MAKE_ARGS = {
    '*/php70*' => 'PHPBASE=/opt/php70 PREFIX=/opt/php70',
    '*/php71*' => 'PHPBASE=/opt/php71 PREFIX=/opt/php71',
    '*/php72*' => 'PHPBASE=/opt/php72 PREFIX=/opt/php72',
    '*/php73*' => 'PHPBASE=/opt/php73 PREFIX=/opt/php73',
    'www/wordpress' => 'PHPBASE=/opt/php73',
    'databases/phpmyadmin' => 'PHPBASE=/opt/php73 WITHOUT_PHP_DEPENDS=yes',
  }

On exceptional circumstances, I had to override LOCALBASE as well during portupgrade, because the build system sometimes is trying to locate some dependencies under ${PHPBASE} instead of the default ${LOCALBASE}, /usr/local.

Allright, once all PHP versions required on the site are installed, then I start one PHP-FPM service for each PHP version. Each FPM instance I configure is using one pool per virtual host, for privilege separation and one dedicated TCP socket. There is a minor package conflict here, because the default service scripts use the same name, but I fix this by minimally changing the rc scripts placed under ${PHPBASE}/etc/rc.d/php-fpm, you can see the differences I applied for ver. 7.3:
Diff:
server:/usr/local/etc % diff -ruN /opt/php73/etc/rc.d/php-fpm /opt/php73/etc/rc.d/php73-fpm
--- /opt/php73/etc/rc.d/php-fpm    2019-11-25 22:34:18.984162000 +0200
+++ /opt/php73/etc/rc.d/php73-fpm    2018-12-19 22:14:52.193957000 +0200
@@ -3,41 +3,41 @@
 # $FreeBSD: head/lang/php73/files/php-fpm.in 444558 2017-06-28 09:40:58Z tz $
 #

-# PROVIDE: php-fpm
+# PROVIDE: php73-fpm
 # REQUIRE: LOGIN
 # KEYWORD: shutdown

 #
 # Add the following line to /etc/rc.conf to enable php-fpm:
-# php_fpm_enable="YES"
+# php73_fpm_enable="YES"
 #

 . /etc/rc.subr

-name="php_fpm"
-rcvar=php_fpm_enable
+name="php73_fpm"
+rcvar=php73_fpm_enable

-start_precmd="php_fpm_prestart"
-restart_precmd="php_fpm_checkconfig"
-reload_precmd="php_fpm_checkconfig"
-configtest_cmd="php_fpm_checkconfig"
+start_precmd="php73_fpm_prestart"
+restart_precmd="php73_fpm_checkconfig"
+reload_precmd="php73_fpm_checkconfig"
+configtest_cmd="php73_fpm_checkconfig"

 load_rc_config "$name"

-: ${php_fpm_enable="NO"}
-: ${php_fpm_umask=""}
+: ${php73_fpm_enable="NO"}
+: ${php73_fpm_umask=""}

 extra_commands="reload configtest logrotate"

 command="/opt/php73/sbin/php-fpm"
-pidfile="/var/run/php-fpm.pid"
+pidfile="/var/run/php73-fpm.pid"
 sig_stop="QUIT"
 sig_reload="USR2"
-logrotate_cmd="php_fpm_logrotate"
+logrotate_cmd="php73_fpm_logrotate"

 required_files="/opt/php73/etc/php-fpm.conf"

-php_fpm_logrotate() {
+php73_fpm_logrotate() {
         if [ -z "$rc_pid" ]; then
                 _run_rc_notrunning
                 return 1
@@ -46,23 +46,23 @@
         kill -USR1 $rc_pid
 }

-php_fpm_checkconfig()
+php73_fpm_checkconfig()
 {
         echo "Performing sanity check on php-fpm configuration:"
         eval ${command} -t
 }

-php_fpm_prestart()
+php73_fpm_prestart()
 {
-    php_fpm_checkconfig
+    php73_fpm_checkconfig
     checkconfig=$?
     if [ $checkconfig -ne 0  ]; then
         return $checkconfig
     fi

-    if [ ! -z "$php_fpm_umask"  ]; then
-        echo "Setting umask to: ${php_fpm_umask}"
-        umask $php_fpm_umask
+    if [ ! -z "$php73_fpm_umask"  ]; then
+        echo "Setting umask to: ${php73_fpm_umask}"
+        umask $php73_fpm_umask
     fi
 }

The next change is made in /etc/rc.conf, to include by default the new startup scripts directories and to preserve the standard service control logic:
Code:
local_startup="/usr/local/etc/rc.d /opt/php71/etc/rc.d /opt/php73/etc/rc.d"

From now on, switching PHP versions is a snap, directly from Apache 2.4 virtualhost config file (pay attention to proxy_fcgi module, make sure to enable it, otherwise this won't work). Read the general guide here https://cwiki.apache.org/confluence/display/httpd/PHP-FPM, then tune your configuration:
From now on, the possibilities are endless, besides running a vost with a specific PHP version, you can even run various parts of the same vhost with different versions, based on Apache 2.4 rules match.
For example, the configuration snippet below will allow you to run: /app1 using php 7.2, /app2 using PHP 7.3, and ther remaining content using PHP 7.4, assuming there are at least 3 pools defined on ports 9720 (PHP 7.2) and 9730 (PHP 7.3) and 7.4 running on port 9740

Apache config:
ProxyPassMatch ^/app1/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9720/path/to/your/php72/app1/$1
ProxyPassMatch ^/app2/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9730/path/to/your/php73/app2/$1
ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9740/path/to/your/other/apps/htdocs/$1
 

Nasrudin

Member

Reaction score: 20
Messages: 50

where do you place that code?

Maybe you an submit a PR, so ports-maintainers can comment?


Thanks for you efforts!

I place said code in the equivalent of make.conf. (For people who use ports builder tools, that can be a number of places, for people who build ports manually that's in /etc/make.conf) I hesitate to submit a PR because a) I don't know exactly where to do that and b) I'm not convinced that I can convince anyone to take this as far as it may need to go to get it to work. ( I have been trying to convince people that convincing people of things is futile, but for some reason this isn't working so well... ;) )

BTW it seems pear works. This build has made it to open testing at my sites, which is good news.
 

rainer_d

Active Member

Reaction score: 9
Messages: 143

There is a PR on bugs.freebsd.org that links back to this thread, so it's kind of circular...
:-/

The current PHP maintainer closed that PR a while ago.

I will try to build it in my poudriere instance. Please update this thread with your efforts.
 

Nasrudin

Member

Reaction score: 20
Messages: 50

Ok so I'll post what I have in that PR, since it's a common reference. I think that's better than opening a new PR as my solution is not strictly a 'problem'. :what:
 

rainer_d

Active Member

Reaction score: 9
Messages: 143

OK, so this actually builds, except for ports that rely on PHP and expect its headers in /usr/local/include (like wordpress or prestashop) - and to build PEAR-ports, one would probably have to change every single one. I'll ignore that for the moment because I don't really need them (horde seems to be one of the main consumers of pear-ports).
Now, I've got to test this and see if I can get this to work in my setup.
 

rainer_d

Active Member

Reaction score: 9
Messages: 143

Ok so I'll post what I have in that PR, since it's a common reference. I think that's better than opening a new PR as my solution is not strictly a 'problem'. :what:



Hi Nasrudin,

it seems that pear is now using pear.mk (from Uses) and your diff does not work anymore.

Do you have suggestions how to fix this (and all other pear ports)?
 

alfikmik

Member

Reaction score: 9
Messages: 54

what about jails with only php + php-fpm on different ports + mount nullfs with php sourcefiles and from master setting php-fpm to according port, so You can choose php version for WWW choosing right php-fpm instance in web server settings for virtualhost
 
Top