devilbox icon indicating copy to clipboard operation
devilbox copied to clipboard

(Community Discussion) Run multiply PHP versions at the same time

Open cytopia opened this issue 7 years ago • 60 comments

Community Discussion: multiple PHP versions

Hi everybody,

hope you enjoy the devilbox so far. I was thinking about a new feature, which might be a bit difficult to get it done, could however be something very useful for some of you:

Feature

Be able to run multiple PHP-FPM container at the same time

Benefits

  • test your site simultaneously with different PHP versions
  • useful for migrating from one version to another
  • useful for continuous integration tests against multiple versions

Feedback

Before I am going to wrap my head around this, I wanted to check back with you guys, If it is actually any useful for you. So if this is of any use for you, let me know. Also if you have something similar in mind, just give me a comment here.

cytopia avatar Nov 14 '17 07:11 cytopia

There is a huge benefit to allowing multiple PHP versions. Setting a specific project to a different version of PHP other than the default is extremely useful. I personally don't need to test against multiple versions...but I can certainly see how that might be useful for some developers. The main benefit for me is that I can make sure a specific project is running the same version of PHP that is on the production server. My own server runs the same version of PHP for virtually every project...but that's not always the case for some of my other clients. While most of my projects run either PHP 7.0 or 7.1, I do have some that are still running on PHP 5.6. The ability to run a project on PHP 5.6 without having to spin up a completely different container is incredibly helpful. Definitely would welcome this feature for sure! :D

jeffwhitfield avatar Nov 24 '17 18:11 jeffwhitfield

I think, this would be great. There are many projects running with a different php version, so this would make my work easier. At the moment, i have to upgrade a project from php 5 to 7. The php 5 project is not compatible with php7, so i have to switch the php version everytime when i will test the old one.

I don't know, how you will make this possible, but maybe you can combine it with server version.

mavimedia avatar Nov 25 '17 17:11 mavimedia

Well, one way that might be possible is to setup handlers for each version installed. Pretty much the way most hosting providers do it. That way, if the default is set to PHP 7.0 but you want to use PHP 7.1 to test an application, all you would need to do is add the following to your .htaccess file:

AddHandler application/x-httpd-php71 .php .php5 .php4 .php3

Pretty straight-forward solution. However, I have no idea how this gets configured on a server. I'm assuming that you would install various versions and then just setup the handlers for each.

jeffwhitfield avatar Nov 27 '17 09:11 jeffwhitfield

Hi guys, I thought about something like this, which would be do-able

1. .env (Define the default PHP version):

DEFAULT_PHP_VERSION=php-fpm-5.6
TLD_SUFFIX=dev

2. Startup

This will startup 3 PHP container, httpd and DNS

docker-compose up php54, php56, php70 httpd dns

3. vHosts

The vhosts will be configured normally (default php version) and have duplicated vhosts for each php version with different domain suffices.

  • Project name: test01
  • vHost (default): test01.dev
  • vHost (54): test01.php54.dev
  • vHost (56): test01.php56.dev
  • vHost (70): test01.php70.dev

4. Intranet

The devilbox intranet will be served via the default php version.


What do you think?

cytopia avatar Nov 27 '17 09:11 cytopia

Hi, what about a possibility, to setup the php version in specific project?

mavimedia avatar Nov 27 '17 13:11 mavimedia

@cytopia: I have a comment to the possibility to chose the php version over domain name (3. vHosts). This way is also possible for zendframework or laravel projects. But for projects made with wordpress it is not. The domain name is placed in database, so it would redirect to that. Maybe some other frameworks work the same way.

mavimedia avatar Nov 28 '17 14:11 mavimedia

what about a possibility, to setup the php version in specific project?

This doesn't make any sense. If you have one project which should be server by php54 and one for php56, you will have to start both containers anyway and could also use both versions on both projects or?

cytopia avatar Nov 29 '17 09:11 cytopia

Yes sure, the containers have to be started. When a project runs with php7, it is not nesseary to test it with php5. In most cases a project is build for a specific php version.

mavimedia avatar Nov 29 '17 14:11 mavimedia

If it is easier for you to go this way

    Project name: test01
    vHost (default): test01.dev
    vHost (54): test01.php54.dev
    vHost (56): test01.php56.dev
    vHost (70): test01.php70.dev

i think, this is somethink, we can live with ;)

mavimedia avatar Nov 29 '17 14:11 mavimedia

If this proposal does the job that projects can be tested against multiple php versions in general then I would say lets go with this implementation.

All other improvements are very valid to follow, however getting it done in the most simple way at the beginning is prioritized, so we might find other flaws as early as possible as well.

cytopia avatar Nov 29 '17 14:11 cytopia

Great! Please, be free to tell me, if i can make some tests.

mavimedia avatar Nov 29 '17 18:11 mavimedia

Sounds really great, in case someone is upgrading a project from php version this new feature will give capability to test the entire functionally through php versions.

In the current stack which i'm working, we have projects since php 5.4 to 7.1. Some of those are only cli applications, i suppose that its in mind that each php container will have a shell like root_bash.sh or we could pass some flags.

@cytopia thanks for your work, devilbox it's a really amazing project !

eortega avatar Dec 01 '17 00:12 eortega

Definitely can see the value in what is being discussed. For projects that need testing like this, this would indeed be the right approach.

However, I still think it would be good to be able to use handlers though. The need for different versions of PHP for different projects is a different problem than testing a single project with multiple versions of PHP.

If multiple versions of PHP are available, wouldn’t they all be accessible from different directories anyways? Handlers could be setup with each within the config of each container. If you had multiple projects and needed a different version of PHP that isn’t the default you could simply add a handler to your htaccess file and that would be it. Food for thought.

jeffwhitfield avatar Dec 01 '17 00:12 jeffwhitfield

@jeffwhitfield not quite sure If I fully understood you.

If multiple versions of PHP are available, wouldn’t they all be accessible from different directories anyways?

No, one project in one directory would be accessible with multiple php versions only differentiated by different domains.

project dir php version domain
test /shared/httpd/test/htdocs/ default test.loc
test /shared/httpd/test/htdocs/ 5.5 test.php55.loc
test /shared/httpd/test/htdocs/ 5.6 test.php56.loc
test /shared/httpd/test/htdocs/ 7.0 test.php70.loc
test /shared/httpd/test/htdocs/ 7.1 test.php71.loc
test /shared/httpd/test/htdocs/ 7.2 test.php72.loc
test /shared/httpd/test/htdocs/ 7.3 test.php73.loc

Does this make more sense? Or did you mean something else?

cytopia avatar Dec 02 '17 10:12 cytopia

Let's say you have the following PHP CGI executables setup in the following directories:

/usr/lib/bin/php56-cgi
/usr/lib/bin/php70-cgi
/usr/lib/bin/php71-cgi
/usr/lib/bin/php72-cgi

Granted, the actual paths for each version might be different. Now, let's say the default is set for 7.2 but you have one project that needs to be set with 5.6 for some reason. You could then setup your Apache config like so:

ScriptAlias /php56-cgi /usr/lib/bin/php56-cgi
Action application/x-httpd-php56 /php56-cgi

Then, in the htaccess file for the project, you could simply add the hander:

<FilesMatch "\.php">
SetHandler application/x-httpd-php56
</FilesMatch>

Something like this would allow for simple overrides with any version of PHP. Basically just need to make sure that a default is set while allowing direct access to all other versions through the file system.

jeffwhitfield avatar Dec 03 '17 20:12 jeffwhitfield

@jeffwhitfield unfortunately PHP is not installed on the httpd container. PHP is delivered by its separate PHP-FPM container. So there must be something that will work with Apache and Nginx on remote PHP-FPM container.

cytopia avatar Dec 03 '17 22:12 cytopia

Ah, I see. Still new to Docker so there's bits that I probably don't get. Access to each container would definitely pose a problem. That said, if there was a way for the httpd container to access the PHP-FPM executables then using handlers might be do-able.

jeffwhitfield avatar Dec 04 '17 15:12 jeffwhitfield

There is no need to physically access the PHP-FPM executables. It's done via an IP addresses/hostnam (hosts: php56, php70, php71, ...) to interpret php files from the httpd server.

cytopia avatar Dec 04 '17 16:12 cytopia

@cytopia how is it registered on http site? is it registered in vhost or anywhere else?

mavimedia avatar Dec 04 '17 21:12 mavimedia

General setup

The httpd container (either Nginx or Apache) send all php requests to the php container and receives the rendered code that then can be displayed.

----------       -------------
| httpd  | ----->|  PHP-FPM  |
----------       -------------

Httpd directives (Apache)

    # PHP-FPM Definition
    <FilesMatch \.php$>
        Require all granted
        SetHandler proxy:fcgi://php:9000
    </FilesMatch>

    # enablereuse requires Apache 2.4.11 or later
    <Proxy "fcgi://php:9000/" enablereuse=on max=10>
    </Proxy>

The important line is SetHandler proxy:fcgi://php:9000 Where php is the hostname of the PHP-FPM server and 9000 is the port of the PHP-FPM process on the php host.

Httpd directives (Nginx)

   # PHP-FPM Definition
    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }
    location ~ \.php?$ {
        try_files $uri = 404;
        include fastcgi_params;

        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_split_path_info ^(.+\.php)(.*)$;

        fastcgi_pass php:9000;

        fastcgi_index index.php;
        fastcgi_intercept_errors on;
    }

The important line is fastcgi_pass php:9000; Where php is the hostname of the PHP-FPM server and 9000 is the port of the PHP-FPM process on the php host.

New idea

So basically instead of only having one PHP-FPM server with hostname php, I was thinking of having all PHP-FPM servers with the following hostnames:

  • php56
  • php70
  • php71
  • php72
  • ...

And there is not just one vhost, but as many vhost for one project as there are PHP-FPM container. Example:

  • Project: test
  • TLD_SUFFIX: loc
<VirtualHost *:80>
    ServerName   test.php54.loc
    <FilesMatch \.php$>
        Require all granted
        SetHandler proxy:fcgi://php54:9000
    </FilesMatch>
</VirtualHost>
<VirtualHost *:80>
    ServerName   test.php56.loc
    <FilesMatch \.php$>
        Require all granted
        SetHandler proxy:fcgi://php56:9000
    </FilesMatch>
</VirtualHost>
<VirtualHost *:80>
    ServerName   test.php70.loc
    <FilesMatch \.php$>
        Require all granted
        SetHandler proxy:fcgi://php70:9000
    </FilesMatch>
</VirtualHost>

...

One of them could also be the default vhost such as for PHP-FPM 7.1:

<VirtualHost *:80>
    ServerName   test.loc
    <FilesMatch \.php$>
        Require all granted
        SetHandler proxy:fcgi://php71:9000
    </FilesMatch>
</VirtualHost>

Does this make any sense?

cytopia avatar Dec 05 '17 07:12 cytopia

Why not running php in different ports? Let's assume we use the php version as portnumber like 9056, 9070, 9071 , 9072 etc.

I think it should be possible to say one global setting for all vhosts (your example changed a little bit)

<VirtualHost *:80>
    ServerName   test.loc
    <FilesMatch \.php$>
        Require all granted
        SetHandler proxy:fcgi://php:9071
    </FilesMatch>
</VirtualHost>

and if someone needs a specific php version for a project, he could do it in the project vhost-gen project/.devilbox/apache24.conf like

<VirtualHost *:80>
    ServerName   test.loc
    <FilesMatch \.php$>
        Require all granted
        SetHandler proxy:fcgi://php:9056
    </FilesMatch>
</VirtualHost>

could this be possible?

In this case you could let the php bin as php in the container. Please correct me, if i'm wrong, but in your case, it could be, that you have to name the php bin to php56, php71 etc. ?

What do you think about this?

P.S. I don't think, that a developer needs to test a project against different php versions. And if so, he could copy it in multiple folders and change the php version for that projects.

mavimedia avatar Dec 05 '17 07:12 mavimedia

@mavimedia when using different ports then all PHP versions must be on the same machine php (Note, this is not a binary, but a hostname of a Container running PHP-FPM).

So from what you are recommending, the user could specify a different hostname (instead of different port) via vhost-gen to accomplish exactly this.

cytopia avatar Dec 05 '17 07:12 cytopia

Does this mean, that i can put a vhost-gen conf into the projects folder like the following (the global configuration is e.g. php71)

<VirtualHost *:80>
    ServerName   test.loc
    <FilesMatch \.php$>
        Require all granted
        SetHandler proxy:fcgi://php56:9000
    </FilesMatch>
</VirtualHost>

and it runs test.loc as php56 and additionally test.php56.loc, test.php70.loc, test.php71.loc etc.?

mavimedia avatar Dec 05 '17 08:12 mavimedia

Not at the moment, as there is always only one PHP-FPM container running (hostname: php), but this was the actual plan for running multiple PHP-FPM container. So once this is implemented: Yes.

However, you will still have to start all PHP-FPM container that you want to use.

cytopia avatar Dec 05 '17 08:12 cytopia

Yes sure, that's clear, not now, but in future. Great! 👍

mavimedia avatar Dec 05 '17 08:12 mavimedia

I'm trying to come away from using MAMP Pro and would find it much easier to transition if we could run a different php version per project like this. Would love to see it happen!

johnwbaxter avatar Feb 28 '18 10:02 johnwbaxter

Just to be clear here. From what I have already come up with, it won't be possible to run different PHP versions on a per project base, but to be able to run multiple PHP versions at the same time and to have each of the projects be served by all currently started php versions like so: (If you would start PHP 54, 55 and 56):

  • project1.php54.loc
  • project1.php55.loc
  • project1.php56.loc

This would then be for all projects.

cytopia avatar Feb 28 '18 11:02 cytopia

Yep, what you are doing is exactly what i want. I don't want multiple php versions per project, i just want to be able to specify which php version a project uses. So for example, i can work on 2 different projects at the same time without having to: docker down edit config, docker up; when i switch projects.

What would be great is to be able to use a per project config file to specify the php version to use, rather than part of the project url. Would that be possible?

johnwbaxter avatar Feb 28 '18 12:02 johnwbaxter

First iteration would be to have a default php version specified in .env over which all projects are reachable without *.php[0-9].* part in the domain. Let's get this done first and then see how difficult it is to customize it per project

cytopia avatar Feb 28 '18 12:02 cytopia

That sounds like a great idea. Thanks a million for replying to my requests!

johnwbaxter avatar Feb 28 '18 12:02 johnwbaxter

You're welcome.

cytopia avatar Feb 28 '18 12:02 cytopia

Any thoughts on using composer with different php versions, @cytopia ?

Some projects which use older php versions use different packages etc which may not be usable with never php versions and are therefore giving errors when composer install etc.

molteber avatar Apr 11 '18 06:04 molteber

@molteber so you would require multiple composer versions for each PHP container?

cytopia avatar Apr 11 '18 07:04 cytopia

Just realized that there is a configuration in composer for this kind of problem I was thinking about. Might be a neat hint to add in the documentation regarding multiple php versions running at the same time and using composer.

By just composer config platform.php <php_version_to_use> the problem is solved (composer.json gets updated, but I can live with that)

https://getcomposer.org/doc/06-config.md#platform

molteber avatar Apr 11 '18 07:04 molteber

I built a vagrant box that provided several php fpms and hhvm: https://github.com/Tuurlijk/TYPO3.Packer/blob/master/ansible/configuration/Development/websites.yml#L8

You could switch the upstream in nginx by using the magic regex servername with named variables.

This way you can get:

php53.somesite.dev.local
php56.somesite.dev.local
php70.somesite.dev.local
php72.somesite.dev.local
hhvm.somesite.dev.local

Putting the php part in front makes the naming easier I think. Leaving off the prefix would serve the site with the default php version.

Heard you could do the same for Apache using 'virtual document roots', but never checked that out.

I'm new to docker. Was thinking about sharing the php sockets by using a tmpfs volume. So you can connect directly to the sockets from the httpd service. Here is some info on that: https://medium.com/@shrikeh/setting-up-nginx-and-php-fpm-in-docker-with-unix-sockets-6fdfbdc19f91

Tuurlijk avatar Jul 13 '18 18:07 Tuurlijk

About Customizing php version per project: If you ran all the different php frpm containers (or all that were configured), you could have a variable set in the project/.devilbox/nginx.yml that said PHP_VERSION: 7.2 and that would change the proxy address to go to the php-fpm-7.2 container

science695 avatar Jul 13 '18 19:07 science695

@cytopia I'm attempting to change the apache template to one that generates vhosts for php, php70 and php72, but vhost-gen does not resolve the DOCUMENT_ROOT vars in my ProxyPassMatch statements. Can you take a look?

###
### Basic vHost skeleton
###
vhost: |
  <VirtualHost __DEFAULT_VHOST__:__PORT__>
      ServerName   __VHOST_NAME__

      CustomLog  "__ACCESS_LOG__" combined
      ErrorLog   "__ERROR_LOG__"

  __REDIRECT__
  __SSL__
  __VHOST_DOCROOT__
  __VHOST_RPROXY__
  __PHP_FPM__
  __ALIASES__
  __DENIES__
  __SERVER_STATUS__
      # Custom directives
  __CUSTOM__
  </VirtualHost>
  <VirtualHost __DEFAULT_VHOST__:__PORT__>
      ServerName   php70.__VHOST_NAME__

      CustomLog  "__ACCESS_LOG__" combined
      ErrorLog   "__ERROR_LOG__"

  __REDIRECT__
  __SSL__
  __VHOST_DOCROOT__
  __VHOST_RPROXY__
      # PHP-FPM Definition
      ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://php70:9000__DOCUMENT_ROOT__/$1
  __ALIASES__
  __DENIES__
  __SERVER_STATUS__
      # Custom directives
  __CUSTOM__
  </VirtualHost>
  <VirtualHost __DEFAULT_VHOST__:__PORT__>
      ServerName   php72.__VHOST_NAME__

      CustomLog  "__ACCESS_LOG__" combined
      ErrorLog   "__ERROR_LOG__"

  __REDIRECT__
  __SSL__
  __VHOST_DOCROOT__
  __VHOST_RPROXY__
      # PHP-FPM Definition
      ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://php72:9000__DOCUMENT_ROOT__/$1
  __ALIASES__
  __DENIES__
  __SERVER_STATUS__
      # Custom directives
  __CUSTOM__
  </VirtualHost>

Tuurlijk avatar Jul 14 '18 06:07 Tuurlijk

@cytopia Got it: https://github.com/devilbox/vhost-gen/pull/28

Tuurlijk avatar Jul 14 '18 07:07 Tuurlijk

Downside is that I need to manually adjust the hosts file. But that's only once.

Tuurlijk avatar Jul 14 '18 07:07 Tuurlijk

@Tuurlijk many thanks. Currently looking manually into it as CI seems to be not responding. What do you mean by manually adjust the hosts file once?

cytopia avatar Jul 16 '18 06:07 cytopia

I need to add entries for all php versions to /etc/hosts on the host machine. But I don't think there is a way around that, except for some magic DNS entry, or adding the bind machine to the /etc/resolv.conf. Then bind could be made to handle all dns.

somesite.tld
hhvm.somesite.tld
php70.somesite.tld
php72.somesite.tld

Tuurlijk avatar Jul 16 '18 06:07 Tuurlijk

Auto-DNS will make them available automatically without adding entries to /etc/hosts:

Current documentation: https://devilbox.readthedocs.io/en/latest/configuration-global/auto-dns.html

Upcoming documentation: https://devilbox.readthedocs.io/en/restructure-documentation/intermediate/setup-auto-dns.html

cytopia avatar Jul 16 '18 06:07 cytopia

@Tuurlijk adding a litte fix regarding missing function argument: https://github.com/devilbox/vhost-gen/pull/29

Error did not get caught as CI was somehow not starting

cytopia avatar Jul 17 '18 07:07 cytopia

@cytopia Is this now possible? I'm not able to figure out from the discussion whether or not I can run multiple PHP versions. I'd definitely like to be able to do that!

adrienne avatar Nov 02 '18 09:11 adrienne

@adrienne it will be possible, but not at the moment as there's quite some work ahead to implement this. I've already done some initial work, but will concentrate on open bugs first as I find that more important then adding more features. It should however not take forever to get this implemented :-)

cytopia avatar Nov 02 '18 10:11 cytopia

@adrienne It may be easier to "hack" it for a single setup then it would be to make it available for everyone with configurable setup.

Here are a few steps that you could use to try doing this:

  • copy the php block of the docker-compose.yml file into the overrides file.
    • change php to php2
    • change the ip to a different address
    • change the docker image from using the version variable to the second php version you wish to use
  • Setup a custom webserver conf template for the project you would like to run in the alternate version
  • Change the proxy settings from going to php to php2

These instructions are not tested, but it should give you a baseline to have 1 subdomain running 1 a version different from the rest of the project.

science695 avatar Nov 05 '18 13:11 science695

Some frameworks have database defined base url's and url rewrite tables, using the PHP version in the domain isn't really an option in that situation.

A config file in the project root would be more usable, some hosting companies let you change the PHP version of apache using something like this in .htaccess: AddHandler application/x-httpd-php54 .php

Just adding it here for brainstorm purposes.

daanggc avatar Dec 17 '18 16:12 daanggc

@adrienne It may be easier to "hack" it for a single setup then it would be to make it available for everyone with configurable setup.

Here are a few steps that you could use to try doing this:

  • copy the php block of the docker-compose.yml file into the overrides file.

    • change php to php2
    • change the ip to a different address
    • change the docker image from using the version variable to the second php version you wish to use
  • Setup a custom webserver conf template for the project you would like to run in the alternate version

  • Change the proxy settings from going to php to php2

These instructions are not tested, but it should give you a baseline to have 1 subdomain running 1 a version different from the rest of the project.

I can confirm this instructions are working. This is the files that changed and it's content:

docker-compose.override.yml

version: '2.1'

services:
  php56:
    image: devilbox/php-fpm:5.6-work-0.72
    hostname: php56
    env_file:
      - ./.env
    environment:
      - DEBUG_ENTRYPOINT=${DEBUG_COMPOSE_ENTRYPOINT}
      - DEBUG_COMPOSE_ENTRYPOINT
      - DOCKER_LOGS
      - NEW_UID
      - NEW_GID
      - TIMEZONE
      - ENABLE_MODULES=${PHP_MODULES_ENABLE}
      - DISABLE_MODULES=${PHP_MODULES_DISABLE}
      - ENABLE_MAIL=1
      - FORWARD_PORTS_TO_LOCALHOST=80:httpd:80,443:httpd:443,3306:mysql:3306,5432:pgsql:5432,6379:redis:6379,11211:memcd:11211,27017:mongo:27017
      - MYSQL_BACKUP_USER=root
      - MYSQL_BACKUP_PASS=${MYSQL_ROOT_PASSWORD}
      - MYSQL_BACKUP_HOST=mysql
    dns:
      - 172.16.238.100
    extra_hosts:
      docker.for.lin.host.internal: 172.16.238.1
      docker.for.lin.localhost: 172.16.238.1
    networks:
      app_net:
        ipv4_address: 172.16.238.90
    volumes:
      - ${DEVILBOX_PATH}/.devilbox/www:/var/www/default:ro${MOUNT_OPTIONS}
      - ${HOST_PATH_HTTPD_DATADIR}:/shared/httpd:rw${MOUNT_OPTIONS}
      - ${DEVILBOX_PATH}/log/php-fpm-5.6:/var/log/php:rw${MOUNT_OPTIONS}
      - ${DEVILBOX_PATH}/mail:/var/mail:rw${MOUNT_OPTIONS}
      - ${DEVILBOX_PATH}/backups:/shared/backups:rw${MOUNT_OPTIONS}
      - ${DEVILBOX_PATH}/cfg/php-ini-5.6:/etc/php-custom.d:ro${MOUNT_OPTIONS}
      - ${DEVILBOX_PATH}/cfg/php-fpm-5.6:/etc/php-fpm-custom.d:ro${MOUNT_OPTIONS}
      - ${DEVILBOX_PATH}/mod/php-fpm-5.6:/usr/lib64/php/custom-modules:ro${MOUNT_OPTIONS}
      - ${DEVILBOX_PATH}/cfg/php-startup-5.6:/startup.1.d:rw${MOUNT_OPTIONS}
      - ${DEVILBOX_PATH}/autostart:/startup.2.d:rw${MOUNT_OPTIONS}
      - ${DEVILBOX_PATH}/bash:/etc/bashrc-devilbox.d:rw${MOUNT_OPTIONS}
      - ${DEVILBOX_PATH}/ca:/ca:rw${MOUNT_OPTIONS}
    depends_on:
      - bind

project/.devilbox/nginx.yml

---

###
### Basic vHost skeleton
###
vhost: |
  server {
      listen       __PORT____HTTP_PROTO____DEFAULT_VHOST__;
      server_name  __VHOST_NAME__;

      access_log   "__ACCESS_LOG__" combined;
      error_log    "__ERROR_LOG__" warn;

  __REDIRECT__
  __SSL__
  __VHOST_DOCROOT__
  __VHOST_RPROXY__
  __PHP_FPM__
  __ALIASES__
  __DENIES__
  __SERVER_STATUS__
      # Custom directives
  __CUSTOM__
  }


###
### vHost Type (normal or reverse proxy)
###
vhost_type:
  # Normal vHost (-p)
  docroot: |
    # Define the vhost to serve files
    root         "__DOCUMENT_ROOT__";
    index        __INDEX__;

  # Reverse Proxy (-r)
  rproxy: |
    # Define the vhost to reverse proxy
    location __LOCATION__ {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_pass __PROXY_PROTO__://__PROXY_ADDR__:__PROXY_PORT__;
    }


###
### Optional features to be enabled in vHost
###
features:

  # SSL Configuration
  ssl: |
    ssl_certificate           __SSL_PATH_CRT__;
    ssl_certificate_key       __SSL_PATH_KEY__;
    ssl_protocols             __SSL_PROTOCOLS__;
    ssl_prefer_server_ciphers __SSL_HONOR_CIPHER_ORDER__;
    ssl_ciphers               __SSL_CIPHERS__;

  # Redirect to SSL directive
  redirect: |
    return 301 https://__VHOST_NAME__:__SSL_PORT__$request_uri;

  # PHP-FPM will not be applied to a reverse proxy!
  php_fpm: |
    # PHP-FPM Definition
    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }
    location ~ \.php?$ {
        try_files $uri = 404;
        include fastcgi_params;

        # https://stackoverflow.com/questions/1733306/nginx-errors-readv-and-recv-failed/51457613#51457613
        fastcgi_keep_conn off;

        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_split_path_info ^(.+\.php)(.*)$;

        fastcgi_pass php56:__PHP_PORT__;
        fastcgi_read_timeout __PHP_TIMEOUT__;

        fastcgi_index index.php;
        fastcgi_intercept_errors on;
    }

  alias: |
    # Alias Definition
    location ~ __ALIAS__ {
        root  __PATH__;
    __XDOMAIN_REQ__
    }

  deny: |
    # Deny Definition
    location ~ __REGEX__ {
        deny all;
    }

  server_status: |
    # Status Page
    location ~ __REGEX__ {
        stub_status on;
        access_log off;
    }

  xdomain_request: |
    # Allow cross domain request from these hosts
    if ( $http_origin ~* (__REGEX__) ) {
        add_header "Access-Control-Allow-Origin" "$http_origin";
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
        add_header 'Access-Control-Expose-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
        add_header 'Access-Control-Max-Age' 0;
        return 200;
    }

Then all you need to do is stop the containers with docker-compose kill and re-run with docker-compose up. You will see devilbox_php56_1 container when you do docker-compose ps.

dbrw avatar Jan 25 '19 07:01 dbrw

I have another possible feature that might be nice to roll into this.

I have 2 subdomains and they run different php.ini error warning levels. Would it be possible to run 2 php containers with a different php.ini file for them? Or is there an easier way of making php.ini changes based on apache/nginx virtualhost? Would that be 2 php-fpm pools?

Thanks

science695 avatar Jan 30 '19 20:01 science695

any news about this ?

shmocs avatar Mar 06 '19 21:03 shmocs

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar May 05 '19 22:05 stale[bot]

Here is an example configuration that switches the PHP backend (upstream) based on the host name requested: https://github.com/Tuurlijk/docker-local/blob/master/.docker/web/default.conf

Prefix is the project name in my case. I support the following domains as default:

  • prefix.dev.local
  • prefix.xdebug.local
  • prefix.blackfire.local

You can define as much php machines in your docker-compose.yml as you wish. Map them to the backends in your default.conf.

This way of setup is nice because I can generate a wildcard SSL root cert for *.dev.local, *.xdebug.local and *.blackfire.local. I could add more domains like *.php71.local or *.hhvm.local. I can switch the backend by changing the domain name. I use a single docker-local project set for each new project. I usually work on a project that requires a single PHP version. So if I need ad different version, I rebuild the php containers with that version.

This is however a different way from the way that devilbox is set up. A similar setup with prefixing the domain names is described above. But I need SSL support now, so I switched to using my docker-local setup that aims to be 'thin' and not to support all PHP and database versions pre-baked.

Tuurlijk avatar May 22 '19 08:05 Tuurlijk

Any easier way to get this setup? Or news on it being a feature added in?

I'd love to have multiple sites with different PHP versions, under one Docker setup, rather than create multiple Docker setups.

ghost avatar May 30 '19 09:05 ghost

@adrienne It may be easier to "hack" it for a single setup then it would be to make it available for everyone with configurable setup. Here are a few steps that you could use to try doing this:

  • copy the php block of the docker-compose.yml file into the overrides file.

    • change php to php2
    • change the ip to a different address
    • change the docker image from using the version variable to the second php version you wish to use
  • Setup a custom webserver conf template for the project you would like to run in the alternate version

  • Change the proxy settings from going to php to php2

These instructions are not tested, but it should give you a baseline to have 1 subdomain running 1 a version different from the rest of the project.

I can confirm this instructions are working. This is the files that changed and it's content:

docker-compose.override.yml

version: '2.1'

services:
  php56:
    image: devilbox/php-fpm:5.6-work-0.72
    hostname: php56
    env_file:
      - ./.env
    environment:
      - DEBUG_ENTRYPOINT=${DEBUG_COMPOSE_ENTRYPOINT}
      - DEBUG_COMPOSE_ENTRYPOINT
      - DOCKER_LOGS
      - NEW_UID
      - NEW_GID
      - TIMEZONE
      - ENABLE_MODULES=${PHP_MODULES_ENABLE}
      - DISABLE_MODULES=${PHP_MODULES_DISABLE}
      - ENABLE_MAIL=1
      - FORWARD_PORTS_TO_LOCALHOST=80:httpd:80,443:httpd:443,3306:mysql:3306,5432:pgsql:5432,6379:redis:6379,11211:memcd:11211,27017:mongo:27017
      - MYSQL_BACKUP_USER=root
      - MYSQL_BACKUP_PASS=${MYSQL_ROOT_PASSWORD}
      - MYSQL_BACKUP_HOST=mysql
    dns:
      - 172.16.238.100
    extra_hosts:
      docker.for.lin.host.internal: 172.16.238.1
      docker.for.lin.localhost: 172.16.238.1
    networks:
      app_net:
        ipv4_address: 172.16.238.90
    volumes:
      - ${DEVILBOX_PATH}/.devilbox/www:/var/www/default:ro${MOUNT_OPTIONS}
      - ${HOST_PATH_HTTPD_DATADIR}:/shared/httpd:rw${MOUNT_OPTIONS}
      - ${DEVILBOX_PATH}/log/php-fpm-5.6:/var/log/php:rw${MOUNT_OPTIONS}
      - ${DEVILBOX_PATH}/mail:/var/mail:rw${MOUNT_OPTIONS}
      - ${DEVILBOX_PATH}/backups:/shared/backups:rw${MOUNT_OPTIONS}
      - ${DEVILBOX_PATH}/cfg/php-ini-5.6:/etc/php-custom.d:ro${MOUNT_OPTIONS}
      - ${DEVILBOX_PATH}/cfg/php-fpm-5.6:/etc/php-fpm-custom.d:ro${MOUNT_OPTIONS}
      - ${DEVILBOX_PATH}/mod/php-fpm-5.6:/usr/lib64/php/custom-modules:ro${MOUNT_OPTIONS}
      - ${DEVILBOX_PATH}/cfg/php-startup-5.6:/startup.1.d:rw${MOUNT_OPTIONS}
      - ${DEVILBOX_PATH}/autostart:/startup.2.d:rw${MOUNT_OPTIONS}
      - ${DEVILBOX_PATH}/bash:/etc/bashrc-devilbox.d:rw${MOUNT_OPTIONS}
      - ${DEVILBOX_PATH}/ca:/ca:rw${MOUNT_OPTIONS}
    depends_on:
      - bind

project/.devilbox/nginx.yml

---

###
### Basic vHost skeleton
###
vhost: |
  server {
      listen       __PORT____HTTP_PROTO____DEFAULT_VHOST__;
      server_name  __VHOST_NAME__;

      access_log   "__ACCESS_LOG__" combined;
      error_log    "__ERROR_LOG__" warn;

  __REDIRECT__
  __SSL__
  __VHOST_DOCROOT__
  __VHOST_RPROXY__
  __PHP_FPM__
  __ALIASES__
  __DENIES__
  __SERVER_STATUS__
      # Custom directives
  __CUSTOM__
  }


###
### vHost Type (normal or reverse proxy)
###
vhost_type:
  # Normal vHost (-p)
  docroot: |
    # Define the vhost to serve files
    root         "__DOCUMENT_ROOT__";
    index        __INDEX__;

  # Reverse Proxy (-r)
  rproxy: |
    # Define the vhost to reverse proxy
    location __LOCATION__ {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_pass __PROXY_PROTO__://__PROXY_ADDR__:__PROXY_PORT__;
    }


###
### Optional features to be enabled in vHost
###
features:

  # SSL Configuration
  ssl: |
    ssl_certificate           __SSL_PATH_CRT__;
    ssl_certificate_key       __SSL_PATH_KEY__;
    ssl_protocols             __SSL_PROTOCOLS__;
    ssl_prefer_server_ciphers __SSL_HONOR_CIPHER_ORDER__;
    ssl_ciphers               __SSL_CIPHERS__;

  # Redirect to SSL directive
  redirect: |
    return 301 https://__VHOST_NAME__:__SSL_PORT__$request_uri;

  # PHP-FPM will not be applied to a reverse proxy!
  php_fpm: |
    # PHP-FPM Definition
    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }
    location ~ \.php?$ {
        try_files $uri = 404;
        include fastcgi_params;

        # https://stackoverflow.com/questions/1733306/nginx-errors-readv-and-recv-failed/51457613#51457613
        fastcgi_keep_conn off;

        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_split_path_info ^(.+\.php)(.*)$;

        fastcgi_pass php56:__PHP_PORT__;
        fastcgi_read_timeout __PHP_TIMEOUT__;

        fastcgi_index index.php;
        fastcgi_intercept_errors on;
    }

  alias: |
    # Alias Definition
    location ~ __ALIAS__ {
        root  __PATH__;
    __XDOMAIN_REQ__
    }

  deny: |
    # Deny Definition
    location ~ __REGEX__ {
        deny all;
    }

  server_status: |
    # Status Page
    location ~ __REGEX__ {
        stub_status on;
        access_log off;
    }

  xdomain_request: |
    # Allow cross domain request from these hosts
    if ( $http_origin ~* (__REGEX__) ) {
        add_header "Access-Control-Allow-Origin" "$http_origin";
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
        add_header 'Access-Control-Expose-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
        add_header 'Access-Control-Max-Age' 0;
        return 200;
    }

Then all you need to do is stop the containers with docker-compose kill and re-run with docker-compose up. You will see devilbox_php56_1 container when you do docker-compose ps.

Thanks a lot for sharing theses snippets, it seems to work for me as i needed one of my website to run php5.6 while default version is 7.2

here is what i did to get a php5.6 shell (for composer and php cli compatibility):

  • duplicate 'shell.sh' to 'shell56.sh' and give it execution right
  • change content of 'shell56.sh':
#!/bin/sh
docker-compose exec --user devilbox php56 bash -l

mohamed-ea avatar Aug 17 '19 11:08 mohamed-ea

I currently solve this issue by running multiple Devilbox instances in different IP addresses. Of course without using auto DNS.

panigrc avatar Feb 07 '20 08:02 panigrc

I work in a system that has multiple subsystems that work on different PHP versions. So locally in my dev environment I have 3 subdomains to each one of these subsystems, and some of them call API funcions from the others, so currently I don't see how I could work this out with current devilbox...

So there it is: another use case for this issue.

lucasvignolireis avatar Jun 08 '20 17:06 lucasvignolireis

I currently solve this issue by running multiple Devilbox instances in different IP addresses. Of course without using auto DNS.

That would work! Do you have a link on this? How to run multiple Devilbox instances in different IPs?

lucasvignolireis avatar Jun 09 '20 17:06 lucasvignolireis

this may be helpful, but i couldn't get it to work https://devilbox.discourse.group/t/multiple-versions-of-php/352/5

i may have to switch to laradock for now https://medium.com/@msirius/1-n-php-versions-and-projects-via-laradock-51938b337071

jakedowns avatar Jun 23 '20 16:06 jakedowns

Hi guys, I thought about something like this, which would be do-able

1. .env (Define the default PHP version):

DEFAULT_PHP_VERSION=php-fpm-5.6
TLD_SUFFIX=dev

2. Startup

This will startup 3 PHP container, httpd and DNS

docker-compose up php54, php56, php70 httpd dns

3. vHosts

The vhosts will be configured normally (default php version) and have duplicated vhosts for each php version with different domain suffices.

  • Project name: test01
  • vHost (default): test01.dev
  • vHost (54): test01.php54.dev
  • vHost (56): test01.php56.dev
  • vHost (70): test01.php70.dev

4. Intranet

The devilbox intranet will be served via the default php version.

What do you think?

did we implemented this in 1.9 .. i am still trying to have projects which different php-version running at same time !

RaffyeMemon avatar Dec 15 '20 12:12 RaffyeMemon

did we implemented this in 1.9 .. i am still trying to have projects which different php-version running at same time !

Not yet. For now you can follow the instructions above to get this feature working: https://github.com/cytopia/devilbox/issues/146#issuecomment-457477860

cytopia avatar Dec 15 '20 12:12 cytopia