1

I created my own dockerfile (ubuntu:xenial) using environment variables. This dockerfile uses php7.0-fpm php7.0-xml php7.0-mbstring php-mysql

The dockerfiles contains:

ENV           MYSQL_HOST=192.168.0.2
ENV           MYSQL_DBNAME=dbname_xyz
ENV           MYSQL_USERNAME=username_xyz
ENV           MYSQL_PASSWORD=password_xyz

...

RUN echo "clear_env = no" >> /etc/php/7.0/fpm/pool.d/www.conf

in the server.php I'm trying to use those variables, but they aren't known obviously

$host       = $_SERVER["MYSQL_HOST"];
$dbname     = $_SERVER["MYSQL_DBNAME"];
$username   = $_SERVER["MYSQL_USERNAME"];
$password   = $_SERVER["MYSQL_PASSWORD"];

$pdo = new \PDO("mysql:host=$host;dbname=$dbname", $username, $password);

Running that shows error:

FastCGI sent in stderr: "PHP message: PHP Notice:  Undefined index: MYSQL_HOST in /var/webdav/server.php on line 4

Executing on: container-shell shows correct value

php -r "echo getenv('MYSQL_HOST');"
env | grep MYSQL

Any suggestions what I've to change?

UPDATE 20211215 after AymDEV's feedback
UPDATE 20211215 after piotrekkr's feedback

Full dockerfile:

FROM          ubuntu:xenial
MAINTAINER    me@whatever.us

# Changing WEBDAV_PASSWORD doesn't work
# MYSQL_x aren't known to server.php
ENV           WEBDAV_USERNAME=admin
ENV           WEBDAV_PASSWORD=admin
ENV           MYSQL_HOST=192.168.0.2
ENV           MYSQL_DBNAME=dbname_xyz
ENV           MYSQL_USERNAME=username_xyz
ENV           MYSQL_PASSWORD=password_xyz

# Defaults
WORKDIR       /var/webdav
VOLUME        /var/webdav/public
VOLUME        /var/webdav/data


# Install zip
RUN           apt-get update && \
              DEBIAN_FRONTEND=noninteractive apt-get install -y zip unzip php-zip

# Install nginx with php7 support
RUN           apt-get update && \
              DEBIAN_FRONTEND=noninteractive apt-get install -y nginx php7.0-fpm php7.0-xml php7.0-mbstring php-mysql && \
              rm -rf /var/lib/apt/lists/*

# Install SabreDAV
RUN           php -r "readfile('http://getcomposer.org/installer');" > composer-setup.php && \
              php composer-setup.php --install-dir=/usr/bin --filename=composer && \
              php -r "unlink('composer-setup.php');" && \
              composer require sabre/dav ~3.2.2 && \
              rm /usr/bin/composer

# Set up entrypoint
COPY          /scripts/install.sh /install.sh

# Configure nginx
COPY          /config/nginx/default /etc/nginx/sites-enabled/default
COPY          /config/nginx/fastcgi_params /etc/nginx/fastcgi_params

# forward request and error logs to docker log collector
RUN           ln -sf /dev/stdout /var/log/nginx/access.log && \
              ln -sf /dev/stderr /var/log/nginx/error.log

# copy server.php for client -- sabredav communication
COPY          /web/server.php /var/webdav/server.php


#make environment variables available to php
RUN echo "clear_env = no" >> /etc/php/7.0/fpm/pool.d/www.conf

#nginx will be process with PID=1
RUN echo "daemon off;" >> /etc/nginx/nginx.conf
CMD           /install.sh && service php7.0-fpm start && nginx

full server.php

<?php

date_default_timezone_set('Europe/Berlin');
$baseUri = '/';
$host       = $_ENV["MYSQL_HOST"];
$dbname     = $_ENV["MYSQL_DBNAME"];
$username   = $_ENV["MYSQL_USERNAME"];
$password   = $_ENV["MYSQL_PASSWORD"];

$pdo = new \PDO("mysql:host=$host;dbname=$dbname", $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

require_once 'vendor/autoload.php';

$authBackend      = new \Sabre\DAV\Auth\Backend\PDO($pdo);
$principalBackend = new \Sabre\DAVACL\PrincipalBackend\PDO($pdo);
$carddavBackend   = new \Sabre\CardDAV\Backend\PDO($pdo);
$caldavBackend    = new \Sabre\CalDAV\Backend\PDO($pdo);

$nodes = [
    new \Sabre\CalDAV\Principal\Collection($principalBackend),
    new \Sabre\CalDAV\CalendarRoot($principalBackend, $caldavBackend),
    new \Sabre\CardDAV\AddressBookRoot($principalBackend, $carddavBackend),
];

$server = new \Sabre\DAV\Server($nodes);
if (isset($baseUri)) $server->setBaseUri($baseUri);

$server->addPlugin(new \Sabre\DAV\Auth\Plugin($authBackend));
$server->addPlugin(new \Sabre\DAV\Browser\Plugin());
$server->addPlugin(new \Sabre\CalDAV\Plugin());
$server->addPlugin(new \Sabre\CardDAV\Plugin());
$server->addPlugin(new \Sabre\DAV\Sync\Plugin());

$server->exec();
Florian
  • 11
  • 3
  • Use `$_ENV` instead ? – AymDev Dec 13 '21 at 11:41
  • @AymDev: Same result – Florian Dec 13 '21 at 12:15
  • Does this answer your question? [No environment variables are available via PHP-fpm+nginx](https://stackoverflow.com/questions/19659675/no-environment-variables-are-available-via-php-fpmnginx) – AymDev Dec 13 '21 at 13:30
  • Indeed it looks very similar to my issue but the solutions don't work. Is it because of doing that in docker? I added: `RUN echo "clear_env = no" >> /etc/php/7.0/fpm/pool.d/www.conf` to the dockerfile, but php is still showing that error. As in the linked issue when I'm executing `php -r "echo getenv('MYSQL_HOST');"` on shell within that container it shows me the correct content. – Florian Dec 15 '21 at 07:19
  • If you go into container console whtat is shown after you type `env | grep MYSQL`? – piotrekkr Dec 15 '21 at 08:41
  • it should be `ENV MYSQL_HOST=192.168.0.2`, missed `=` https://docs.docker.com/engine/reference/builder/#env – piotrekkr Dec 15 '21 at 08:42
  • @piotrekkr: It shows: `MYSQL_PASSWORD=password_xyz MYSQL_DBNAME=dbname_xyz MYSQL_USERNAME=username_xyz MYSQL_HOST=192.168.0.2` – Florian Dec 15 '21 at 09:01
  • @piotrekkr: added the "=", but no difference – Florian Dec 15 '21 at 09:02
  • @piotrekkr wrong, look at the "alternative syntax" part of your link. – AymDev Dec 15 '21 at 09:03
  • @Florian Ok there is alternative syntax for ENV in dockerfile that allows omiting `=` so it was not a case. Can you show output of `var_dump(getenv()); die;` *from index.php*? It is not the same as `php -r '....'`. – piotrekkr Dec 15 '21 at 09:06
  • Also did you rebuild and restart your container after changing `clear_env`? – piotrekkr Dec 15 '21 at 09:12
  • @piotrekkr: Not sure how I have to test your suggestions `var_dump(getenv()); die; from index.php?` and yes of course I rebuild that container every time after a change on dockerfile. Will add the entire dockerfile later today. – Florian Dec 15 '21 at 10:05
  • I mean php file that you try to execute. I suppose it is executed when you make request using curl/browser to some `localhost:PORT` after building and running image. Can you add this at very beginning of file that is executed and give you error? – piotrekkr Dec 15 '21 at 11:26
  • @piotrekkr: Adding `var_dump(getenv('MYSQL_HOST')); die;` at the beginning of my server.php stops the bash from throwing the unknown variable php message, but accessing the webpage instead shows then: `bool(false)`, whatever that means. Adding just `var_dump(getenv()); die;` complains on shell about the missing parameter. – Florian Dec 15 '21 at 15:01

1 Answers1

1

Actually - everything is working as designed. There are several reasons why you are not seeing the ENV variables and the approach you are using is a bit flawed.

TLDR: use docker-compose and split the FPM process into a separate container, with fpm as the entrypoint.

Why it doesn't work

Since this case is a bit complex - I will try to go step by step by the reasons why it's not working for you. Hopefully this will help.

  1. Your PHP scripts are executed within the FPM workers. Each of these workers passes specific data (context) into PHP. That context you can see, for example, inside the $_SERVER variable:

     Array
        (
        [LANGUAGE] =>
        [LC_TIME] =>
        [LC_CTYPE] =>
        [LC_MONETARY] =>
        [TERM] => xterm
        [LC_COLLATE] =>
        [PATH] => /sbin:/usr/sbin:/bin:/usr/bin
        [LC_ADDRESS] =>
        [LANG] =>
        [LC_TELEPHONE] =>
        [LC_MESSAGES] =>
        [LC_NAME] =>
        [LC_MEASUREMENT] =>
        [LC_IDENTIFICATION] =>
        [LC_ALL] =>
        [PWD] => /
        [LC_NUMERIC] =>
        [LC_PAPER] =>
        [USER] => www-data
        [HOME] => /var/www
        [HTTP_ACCEPT] => */*
        [HTTP_USER_AGENT] => curl/7.47.0
        [HTTP_HOST] => localhost
        [REDIRECT_STATUS] => 200
        [SERVER_NAME] => _
        [SERVER_PORT] => 80
        [SERVER_ADDR] => 127.0.0.1
        [REMOTE_PORT] => 35542
        [REMOTE_ADDR] => 127.0.0.1
        [SERVER_SOFTWARE] => nginx/1.10.3
        [GATEWAY_INTERFACE] => CGI/1.1
        [REQUEST_SCHEME] => http
        [SERVER_PROTOCOL] => HTTP/1.1
        [DOCUMENT_ROOT] => /var/www/html
        [DOCUMENT_URI] => /print.php
        [REQUEST_URI] => /print.php
        [SCRIPT_NAME] => /print.php
        [CONTENT_LENGTH] =>
        [CONTENT_TYPE] =>
        [REQUEST_METHOD] => GET
        [QUERY_STRING] =>
        [SCRIPT_FILENAME] => /var/www/html/print.php
        [PATH_INFO] =>
        [FCGI_ROLE] => RESPONDER
        [PHP_SELF] => /print.php
        [REQUEST_TIME_FLOAT] => 1639586759.7522
        [REQUEST_TIME] => 1639586759
        )
    

    If you print out the same variable from the CLI - the result will be quite different (I guess you already observed that):

    Array
    (
        [HOSTNAME] => 580747313ddc
        [TERM] => xterm
        [MYSQL_PASSWORD] => password_xyz
        [LS_COLORS] => rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:
        [WEBDAV_USERNAME] => admin
        [MYSQL_DBNAME] => dbname_xyz
        [PATH] => /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
        [PWD] => /var/www/html
        [WEBDAV_PASSWORD] => admin
        [MYSQL_USERNAME] => username_xyz
        [SHLVL] => 1
        [HOME] => /root
        [MYSQL_HOST] => 192.168.0.2
        [_] => /usr/bin/php
        [OLDPWD] => /etc/nginx
        [PHP_SELF] => print.php
        [SCRIPT_NAME] => print.php
        [SCRIPT_FILENAME] => print.php
        [PATH_TRANSLATED] => print.php
        [DOCUMENT_ROOT] =>
        [REQUEST_TIME_FLOAT] => 1639586851.762
        [REQUEST_TIME] => 1639586851
        [argv] => Array
            (
                [0] => print.php
            )
    
        [argc] => 1
    )
    
  2. The ENV is properly passed into the container and if you execute processes in the container - the ENV is available to them. This is seen in the second example above. But, if you look at the processes running in your container:

root@580747313ddc:/var/www/html# ps -aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0   1872   420 ?        Ss   16:20   0:00 /bin/sh -c service php7.0-fpm start && nginx
root        37  0.0  0.4  45560  9208 ?        S    16:20   0:00 nginx: master process nginx
root        43  0.0  0.1   3628  2908 pts/0    Ss   16:21   0:01 bash
www-data  3154  0.0  0.1  45932  4032 ?        S    16:38   0:00 nginx: worker process
www-data  3155  0.0  0.1  45932  3232 ?        S    16:38   0:00 nginx: worker process
www-data  3156  0.0  0.1  45932  3232 ?        S    16:38   0:00 nginx: worker process
www-data  3157  0.0  0.1  45932  3232 ?        S    16:38   0:00 nginx: worker process
www-data  3158  0.0  0.1  45932  3232 ?        S    16:38   0:00 nginx: worker process
root      3217  0.0  0.5 121364 10324 ?        Ss   16:41   0:00 php-fpm: master process (/etc/php/7.0/fpm/php-fpm.conf)
www-data  3218  0.0  0.4 121708  9920 ?        S    16:41   0:00 php-fpm: pool www
www-data  3219  0.0  0.4 121708  9512 ?        S    16:41   0:00 php-fpm: pool www
root      3233  0.0  0.1   5472  2380 pts/0    R+   16:51   0:00 ps -aux

you can examine the environment of each one of them, see process with PID=1 (the entrypoint of the container):

root@580747313ddc:/var/www/html# cat /proc/1/environ
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binHOSTNAME=580747313ddcWEBDAV_USERNAME=adminWEBDAV_PASSWORD=adminMYSQL_HOST=192.168.0.2MYSQL_DBNAME=dbname_xyzMYSQL_USERNAME=username_xyzMYSQL_PASSWORD=password_xyzHOME=/root

the environment has the ENVs that you created. All good here. But if you look at the FPM process:

root@580747313ddc:/var/www/html# cat /proc/3217/environ
root@580747313ddc:/var/www/html#

it's empty!

This is because you are running the FPM as a service (as in a systemd service), which means that you would have to define these environment variables within the service's configuration file, in this case /lib/systemd/system/php7.0-fpm.service.

It can be done, however - it wouldn't be very clean to do so.

What you can do to fix it

You can work around the problems above by simply using php-fpm as the entrypoint to your container. That way - it will have access to the ENV. This is already being done by the official php-fpm images and we can try to use them. Here's a minimal workable example, using docker-compose:

docker-compose.yml:

version: '3'
services:
  web:
    image: nginx
    container_name: web
    depends_on:
      - php
    links:
      - php
    volumes:
      - ./html:/var/www/html
      - ./conf:/etc/nginx/conf.d/
    ports:
      - "8080:80"
  php:
    image: php:7.4-fpm-alpine
    environment:
      - MYSQL_PASS=pass123
    volumes:
      - ./html:/var/www/html

Now, in the same folder create html/print.php:

<?php print_r($_SERVER);?>

and conf/default.conf:

server {
    listen       80;
    listen  [::]:80;
    server_name  localhost;

    root /var/www/html;
    location ~ \.php$ {

        try_files $uri = 404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param REQUEST_URI $request_uri;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        include        fastcgi_params;
    }

}

with this - simply run docker-compose up -d and then curl localhost:8080/print.php.

This should give you the expected env variable MYSQL_PASS inside your $_SERVER array:

Array
(
    [HOSTNAME] => 84a4d1e174d3
    [PHP_INI_DIR] => /usr/local/etc/php
    [SHLVL] => 1
    [HOME] => /home/www-data
    [PHP_LDFLAGS] => -Wl,-O1 -pie
    [PHP_CFLAGS] => -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
    [PHP_VERSION] => 7.4.26
    [GPG_KEYS] => 42670A7FE4D0441C8E4632349E4FDC074A4EF02D 5A52880781F755608BF815FC910DEB46F53EA312
    [PHP_CPPFLAGS] => -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
    [PHP_ASC_URL] => https://www.php.net/distributions/php-7.4.26.tar.xz.asc
    [MYSQL_PASS] => pass123
    [PHP_URL] => https://www.php.net/distributions/php-7.4.26.tar.xz
    [PATH] => /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
    [WEBDAV_USER] => test
    [PHPIZE_DEPS] => autoconf       dpkg-dev dpkg       file        g++         gcc         libc-dev        make        pkgconf         re2c
    [PWD] => /var/www/html
    [PHP_SHA256] => e305b3aafdc85fa73a81c53d3ce30578bc94d1633ec376add193a1e85e0f0ef8
    [USER] => www-data
    [HTTP_ACCEPT] => */*
    [HTTP_USER_AGENT] => curl/7.77.0
    [HTTP_HOST] => localhost:8080
    [PATH_INFO] =>
    [SCRIPT_FILENAME] => /var/www/html/print.php
    [REDIRECT_STATUS] => 200
    [SERVER_NAME] => localhost
    [SERVER_PORT] => 80
    [SERVER_ADDR] => 172.18.0.3
    [REMOTE_PORT] => 55288
    [REMOTE_ADDR] => 172.18.0.1
    [SERVER_SOFTWARE] => nginx/1.21.4
    [GATEWAY_INTERFACE] => CGI/1.1
    [REQUEST_SCHEME] => http
    [SERVER_PROTOCOL] => HTTP/1.1
    [DOCUMENT_ROOT] => /var/www/html
    [DOCUMENT_URI] => /print.php
    [REQUEST_URI] => /print.php
    [SCRIPT_NAME] => /print.php
    [CONTENT_LENGTH] =>
    [CONTENT_TYPE] =>
    [REQUEST_METHOD] => GET
    [QUERY_STRING] =>
    [FCGI_ROLE] => RESPONDER
    [PHP_SELF] => /print.php
    [REQUEST_TIME_FLOAT] => 1639591114.4143
    [REQUEST_TIME] => 1639591114
    [argv] => Array
        (
        )

    [argc] => 0
)
andrzejwp
  • 922
  • 4
  • 11