Load environment variables from env file with Docker and PHP
Asked Answered
L

4

2

How to use dotenv variables set in the Docker file, passed to a Php application?

Recently tried to use a ".env" file with a set of key paired values to use across different configuration files, but noticed that Docker + the Wordpress image is not easy to setup. While quite trivial to set up in node, etc.

See the ".env" file below that sits same dir as the docker-compose.yml:

WORDPRESS_DB_NAME=wp_xxxx
WORDPRESS_DB_USER=xxxxxx
WORDPRESS_DB_PASSWORD=xxxxxx
WORDPRESS_DB_HOST=xxxxxxxx

The official Wordpress image available here ( https://hub.docker.com/_/wordpress ) documents that "The following environment variables are also honoured for configuring your WordPress [...] WORDPRESS_DB_USER, WORDPRESS_DB_PASSWORD, etc".

By default the Configuration parameters in the "wp-config.php" are not replaced by the .env variables, which lead me to extend the original Wordpress image by installing composer. Let's call the file bellow "DockerWordpress.yml":

FROM wordpress:php7.3-apache

RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/bin --filename=composer && chmod +x /usr/bin/composer 
RUN composer require vlucas/phpdotenv

That is used in the main Docker-compose.yml file, as we can see below. Find the service "Wordpress":

version: '3.1'

services:
  web:
    container_name: web
    image: nginx:1.15.11-alpine
    volumes:
      - ./nginx/foobar.conf:/etc/nginx/conf.d/default.conf
      - ../../foobar-blog-ui/public/:/var/www/html/
    ports:
      - 80:80
      - 443:443
    networks:
      - foobar-wordpress-network

  node:
    image: node:8.16.0-slim
    working_dir: /home/node/app
    environment:
      - NODE_ENV=development
    volumes:
      - ../../foobar-blog-ui/:/home/node/app
      - ./node_modules:/home/node/app/node_modules
      - ./npm/.npmrc:/home/node/app/.npmrc
    ports:
     - 8000:8000
     - 9000:9000
    command: bash -c "apt-get update && apt-get install -y rsync vim git libpng-dev libjpeg-dev libxi6 build-essential libgl1-mesa-glx && npm install && exit 0"
    depends_on:
      - wordpress
    networks:
      - foobar-wordpress-network

  wordpress:
    build:
      context: .
      dockerfile: ./Services/DockerWordpress.yml
    container_name: wordpress
    restart: on-failure
    ports:
      - 8888:80
    environment:
      WORDPRESS_DB_HOST: ${WORDPRESS_DB_HOST}
      WORDPRESS_DB_NAME: ${WORDPRESS_DB_NAME}
      WORDPRESS_DB_USER: ${WORDPRESS_DB_USER}
      WORDPRESS_DB_PASSWORD: ${WORDPRESS_DB_PASSWORD}
    volumes:
      - ../../foobar-wordpress-cms/:/var/www/html
      - ./uploads.ini:/usr/local/etc/php/conf.d/uploads.ini
      - ./wordpress/wp-config.php:/var/www/html/wp-config.php
    depends_on:
      - db
    networks:
      - foobar-wordpress-network

  wordpress-cli:
    image: wordpress:cli
    volumes:
      - ../../foobar-wordpress-cms/:/var/www/html
      - ./scripts/docker-entrypoint.sh:/var/www/html/docker-entrypoint.sh
    depends_on:
      - wordpress
      - db
    command: sh -c "sleep 30 && ./docker-entrypoint.sh"
    networks:
      - foobar-wordpress-network

  db:
    image: mariadb:latest
    ports:
      - 3306:3306
    restart: on-failure
    environment:
      MYSQL_DATABASE: ${WORDPRESS_DB_NAME}
      MYSQL_USER: ${WORDPRESS_DB_USER}
      MYSQL_PASSWORD: ${WORDPRESS_DB_PASSWORD}
    #   MYSQL_ROOT_HOST: ${WORDPRESS_DB_HOST}
      MYSQL_ROOT_HOST: '%'
      MYSQL_RANDOM_ROOT_PASSWORD: '1'
    volumes:
      - ./wordpress/database:/docker-entrypoint-initdb.d
      - ./mysql/my.cnf:/etc/mysql/conf.d/my.cnf"
      - ./mysql/data:/var/lib/mysql
    networks:
      - foobar-wordpress-network
    healthcheck:
        test: ["CMD", "mysqladmin", "-u${WORDPRESS_DB_USER}", "-p${WORDPRESS_DB_PASSWORD}", "ping"]
        interval: 60s
        timeout: 60s
        retries: 3

volumes:
  mysql_data:
  node_modules:

networks:
  foobar-wordpress-network:
      driver: bridge

Finally, the "wp-config.php" file that is mounted from an external source into the container volume, as you can see in the previous "docker-compose" file. This is done by following the documentation provided by the defacto plugin to use dotEnv variables ( https://github.com/vlucas/phpdotenv ) in the Php community.

<?php

require_once(__DIR__ . './vendor/autoload.php');
(new \Dotenv\Dotenv(__DIR__ . '/../.init/Docker'))->load();

/**
 * The base configuration for WordPress
 *
 * The wp-config.php creation script uses this file during the
 * installation. You don't have to use the web site, you can
 * copy this file to "wp-config.php" and fill in the values.
 *
 * This file contains the following configurations:
 *
 * * MySQL settings
 * * Secret keys
 * * Database table prefix
 * * ABSPATH
 *
 * @link https://codex.wordpress.org/Editing_wp-config.php
 *
 * @package WordPress
 */

// ** MySQL settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define( 'DB_NAME', '');

/** MySQL database username */
define( 'DB_USER', '');

/** MySQL database password */
define( 'DB_PASSWORD', '');

/** MySQL hostname */
define( 'DB_HOST', '');

/** Database Charset to use in creating database tables. */
define( 'DB_CHARSET', 'utf8');

/** The Database Collate type. Don't change this if in doubt. */
define( 'DB_COLLATE', '');

/**#@+
 * Authentication Unique Keys and Salts.
 *
 * Change these to different unique phrases!
 * You can generate these using the {@link https://api.wordpress.org/secret-key/1.1/salt/ WordPress.org secret-key service}
 * You can change these at any point in time to invalidate all existing cookies. This will force all users to have to log in again.
 *
 * @since 2.6.0
 */
define( 'AUTH_KEY',         'U(p)0EQ$O;meL`Oe@1$t7nI?<$=|NJ)kb+Shya21)-M2HI#/B#e~:@gX+}h@[LNE' );
define( 'SECURE_AUTH_KEY',  'Qpe;9 Ye^zuSozw@}2*f9mK~]7/V1,gf[^v4=}@ N!$<(q2qI<3U]kNK^P4b)n;7' );
define( 'LOGGED_IN_KEY',    'R=yN?s&Ek8ncd;xuvIHU];2fo#piE[MbF6 63@aP:p1TyZmz#94(>XErht{}6<V,' );
define( 'NONCE_KEY',        'Xr~QqP8%cjPA$] ?m*-CrcjgdfA6Vao>8C/AI6-pi_Y<rI]y=6fKSOS6i/%4F~Xl' );
define( 'AUTH_SALT',        '<<7vysQ=uPfNxyl? z=97AyIfm~QNn5%JI7^)bFW&;A`V.5`W2xj+KXJY`_hV66T' );
define( 'SECURE_AUTH_SALT', 'dT-4]:wh_.++<M&L6>&Eywn})wSzy+.`v6eBhl694uF(fc:yp9:?oV! PDbU(ST(' );
define( 'LOGGED_IN_SALT',   '3rPPnmKp|dUR=KX{W-TVYH7a:60P7z}$h3jgggKJgn~9XX`)6XuCtzMLjypztu!m' );
define( 'NONCE_SALT',       'X4aAby}iQOenS$2g7~R@,9+/-mc_lfzq!*RMP+cKOgv0K[{xS73~|k0u:zq>G.My' );

/**#@-*/

/**
 * WordPress Database Table prefix.
 *
 * You can have multiple installations in one database if you give each
 * a unique prefix. Only numbers, letters, and underscores please!
 */
$table_prefix = 'wp_';

/**
 * For developers: WordPress debugging mode.
 *
 * Change this to true to enable the display of notices during development.
 * It is strongly recommended that plugin and theme developers use WP_DEBUG
 * in their development environments.
 *
 * For information on other constants that can be used for debugging,
 * visit the Codex.
 *
 * @link https://codex.wordpress.org/Debugging_in_WordPress
 */
// define( 'WP_DEBUG', true );
// define( 'WP_DEBUG_LOG', true );

/* That's all, stop editing! Happy publishing. */

/** Absolute path to the WordPress directory. */
if ( ! defined( 'ABSPATH' ) ) {
    define( 'ABSPATH', dirname( __FILE__ ) . '/' );
}

/** Sets up WordPress vars and included files. */
require_once( ABSPATH . 'wp-settings.php' );

Since I'm using composer and the phpdotnet plugin, I've also tried:

define( 'DB_NAME', getenv('WORDPRESS_DB_NAME'));
...

In the error log, I can read:

wordpress exited with code 4

The error above code 4 is caused by providing "environment variables", that causes the entrypoint script to try to modify the wp-config.php for us.

Since the code 4 is caused by the environment variables, with or without the inspect docker image returns the following (does not have env variables):

[
    {
        "Id": "sha256:0d91452f5f88a168d9e85e2c4992460e2ef50d66d60c581c3ffc60b78824a416",
        "RepoTags": [
            "docker_wordpress:latest"
        ],
        "RepoDigests": [],
        "Parent": "sha256:73c390be73f955ac64e67751faba8095ed0d31a98a3eb841ea38be6a81d9bd02",
        "Comment": "",
        "Created": "2019-09-09T22:54:10.8766881Z",
        "Container": "20a95e0640aa65d9c1c244cdacf0dae09165c4da3ff19460190dce4cf4a80d8b",
        "ContainerConfig": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "80/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "PHPIZE_DEPS=autoconf \t\tdpkg-dev \t\tfile \t\tg++ \t\tgcc \t\tlibc-dev \t\tmake \t\tpkg-config \t\tre2c",
                "PHP_INI_DIR=/usr/local/etc/php",
                "APACHE_CONFDIR=/etc/apache2",
                "APACHE_ENVVARS=/etc/apache2/envvars",
                "PHP_EXTRA_BUILD_DEPS=apache2-dev",
                "PHP_EXTRA_CONFIGURE_ARGS=--with-apxs2 --disable-cgi",
                "PHP_CFLAGS=-fstack-protector-strong -fpic -fpie -O2",
                "PHP_CPPFLAGS=-fstack-protector-strong -fpic -fpie -O2",
                "PHP_LDFLAGS=-Wl,-O1 -Wl,--hash-style=both -pie",
                "GPG_KEYS=CBAF69F173A0FEA4B537F470D66C9593118BCCB6 F38252826ACD957EF380D39F2F7956BC5DA04B5D",
                "PHP_VERSION=7.3.9",
                "PHP_URL=https://www.php.net/get/php-7.3.9.tar.xz/from/this/mirror",
                "PHP_ASC_URL=https://www.php.net/get/php-7.3.9.tar.xz.asc/from/this/mirror",
                "PHP_SHA256=4007f24a39822bef2805b75c625551d30be9eeed329d52eb0838fa5c1b91c1fd",
                "PHP_MD5=",
                "WORDPRESS_VERSION=5.2.3",
                "WORDPRESS_SHA1=5efd37148788f3b14b295b2a9bf48a1a467aa303"
            ],
            "Cmd": [
                "/bin/sh",
                "-c",
                "composer require vlucas/phpdotenv"
            ],
            "Image": "sha256:73c390be73f955ac64e67751faba8095ed0d31a98a3eb841ea38be6a81d9bd02",
            "Volumes": {
                "/var/www/html": {}
            },
            "WorkingDir": "/var/www/html",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": null,
            "StopSignal": "WINCH"
        },
        "DockerVersion": "19.03.2",
        "Author": "",
        "Config": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "80/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "PHPIZE_DEPS=autoconf \t\tdpkg-dev \t\tfile \t\tg++ \t\tgcc \t\tlibc-dev \t\tmake \t\tpkg-config \t\tre2c",
                "PHP_INI_DIR=/usr/local/etc/php",
                "APACHE_CONFDIR=/etc/apache2",
                "APACHE_ENVVARS=/etc/apache2/envvars",
                "PHP_EXTRA_BUILD_DEPS=apache2-dev",
                "PHP_EXTRA_CONFIGURE_ARGS=--with-apxs2 --disable-cgi",
                "PHP_CFLAGS=-fstack-protector-strong -fpic -fpie -O2",
                "PHP_CPPFLAGS=-fstack-protector-strong -fpic -fpie -O2",
                "PHP_LDFLAGS=-Wl,-O1 -Wl,--hash-style=both -pie",
                "GPG_KEYS=CBAF69F173A0FEA4B537F470D66C9593118BCCB6 F38252826ACD957EF380D39F2F7956BC5DA04B5D",
                "PHP_VERSION=7.3.9",
                "PHP_URL=https://www.php.net/get/php-7.3.9.tar.xz/from/this/mirror",
                "PHP_ASC_URL=https://www.php.net/get/php-7.3.9.tar.xz.asc/from/this/mirror",
                "PHP_SHA256=4007f24a39822bef2805b75c625551d30be9eeed329d52eb0838fa5c1b91c1fd",
                "PHP_MD5=",
                "WORDPRESS_VERSION=5.2.3",
                "WORDPRESS_SHA1=5efd37148788f3b14b295b2a9bf48a1a467aa303"
            ],
            "Cmd": [
                "apache2-foreground"
            ],
            "ArgsEscaped": true,
            "Image": "sha256:73c390be73f955ac64e67751faba8095ed0d31a98a3eb841ea38be6a81d9bd02",
            "Volumes": {
                "/var/www/html": {}
            },
            "WorkingDir": "/var/www/html",
            "Entrypoint": [
                "docker-entrypoint.sh"
            ],
            "OnBuild": null,
            "Labels": null,
            "StopSignal": "WINCH"
        },
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 530754564,
        "VirtualSize": 530754564,
        "GraphDriver": {
            "Data": {
                ...
            },
            "Name": "overlay2"
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                ...
            ]
        },
        "Metadata": {
            "LastTagTime": "2019-09-09T22:54:10.9465719Z"
        }
    }
]

Have in mind that I expect that the documentation is correct and that the setup above, that the environment variables should be honoured.

Lanna answered 9/9, 2019 at 22:29 Comment(0)
L
0

Here're a few notes that helped me found the solution, and hope it helps someone else in the future.

First the issues I found while trying and seeing:

  • the first one that caused the error exposed above as wordpress exited with code 4 is that wp-content.php fails when mounted into the container, so either the intention is to allow the "wordpress" entrypoint sh script to modify the file for us or accept will do something else, as tried above, the plugin phpdotenv and $_ENV or getenv fn (https://www.php.net/manual/en/function.getenv.php)

  • the volume is mounted in the Docker-compose.yml file and overwrites files such as the ones we try to COPY into the container WORKDIR, etc

  • The Docker-compose context doesn't allow copying files outside its scope "The path must be inside the context of the build"

Below you'll find a working version (WIP), that worked for me, as an alternative to the default behaviour that, as stated should be honoured (I believe that refactoring, given the points mentioned above, taking into consideration all, this can be improved, but let's keep this related with passing dotenv to PHP, should be useful for someone else in the future).

++++++++++++ docker-compose.yml ++++++++++++++++

version: '3.1'

services:
  web:
    container_name: web
    image: nginx:1.15.11-alpine
    volumes:
      - ./nginx/foobar.conf:/etc/nginx/conf.d/default.conf
      - ../../foobar-blog-ui/public/:/var/www/html/
    ports:
      - 80:80
      - 443:443
    networks:
      - foobar-wordpress-network

  node:
    image: node:8.16.0-slim
    working_dir: /home/node/app
    environment:
      - NODE_ENV=development
    volumes:
      - ../../foobar-blog-ui/:/home/node/app
      - ./node_modules:/home/node/app/node_modules
      - ./npm/.npmrc:/home/node/app/.npmrc
    ports:
     - 8000:8000
     - 9000:9000
    command: bash -c "apt-get update && apt-get install -y rsync vim git libpng-dev libjpeg-dev libxi6 build-essential libgl1-mesa-glx && npm install && exit 0"
    depends_on:
      - wordpress
    networks:
      - foobar-wordpress-network

  wordpress:
    build:
      context: ../../
      dockerfile: ./.init/Docker/Services/DockerWordpress.yml
    container_name: wordpress
    restart: on-failure
    ports:
      - 8888:80
    depends_on:
      - db
    networks:
      - foobar-wordpress-network

  wordpress-cli:
    image: wordpress:cli
    volumes:
      - ../../foobar-wordpress-cms/:/var/www/html
      - ./scripts/docker-entrypoint.sh:/var/www/html/docker-entrypoint.sh
    depends_on:
      - wordpress
      - db
    command: sh -c "sleep 30 && ./docker-entrypoint.sh"
    networks:
      - foobar-wordpress-network

volumes:
  node_modules:

networks:
  foobar-wordpress-network:
      driver: bridge

++++++++++++ dockerfile ++++++++++++++++

FROM wordpress:php7.3-apache

WORKDIR /var/www/html/

COPY ./.init/Docker/.env .
COPY ./foobar-wordpress-cms .
COPY ./.init/Docker/php/uploads.ini /usr/local/etc/php/conf.d/uploads.ini
COPY ./.init/Docker/wordpress/wp-config.php ./wp-config.php

RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/bin --filename=composer && chmod +x /usr/bin/composer 
RUN composer require vlucas/phpdotenv
RUN ls -la

The following article also helped ( https://vsupalov.com/docker-arg-env-variable-guide/#the-dot-env-file-env ).

Lanna answered 10/9, 2019 at 1:28 Comment(0)
U
4

Environment Variables in Docker

Setup .env in docker-compose.yml

Environmnet File .env

WORDPRESS_DB_NAME=platform-ops-db

docker-compose.yml

version: '2'
services:
  web:
    image: nginx:1.15.11-alpine
    container_name: web
    env_file:
      - ./.env
    environment:
      MYSQL_DATABASE: ${WORDPRESS_DB_NAME}

We can use the WORDPRESS_DB_NAME throughout the application running withing the container web.

To run the Wordpress in a container behind the proxy please check with the repo conf file Wordpress as a container behind the proxy in the repo Repo

Ugh answered 10/9, 2019 at 14:34 Comment(1)
Important: so far, it only works if both .env and docker-compose.yml are in the same folder.Ecumenical
L
0

Here're a few notes that helped me found the solution, and hope it helps someone else in the future.

First the issues I found while trying and seeing:

  • the first one that caused the error exposed above as wordpress exited with code 4 is that wp-content.php fails when mounted into the container, so either the intention is to allow the "wordpress" entrypoint sh script to modify the file for us or accept will do something else, as tried above, the plugin phpdotenv and $_ENV or getenv fn (https://www.php.net/manual/en/function.getenv.php)

  • the volume is mounted in the Docker-compose.yml file and overwrites files such as the ones we try to COPY into the container WORKDIR, etc

  • The Docker-compose context doesn't allow copying files outside its scope "The path must be inside the context of the build"

Below you'll find a working version (WIP), that worked for me, as an alternative to the default behaviour that, as stated should be honoured (I believe that refactoring, given the points mentioned above, taking into consideration all, this can be improved, but let's keep this related with passing dotenv to PHP, should be useful for someone else in the future).

++++++++++++ docker-compose.yml ++++++++++++++++

version: '3.1'

services:
  web:
    container_name: web
    image: nginx:1.15.11-alpine
    volumes:
      - ./nginx/foobar.conf:/etc/nginx/conf.d/default.conf
      - ../../foobar-blog-ui/public/:/var/www/html/
    ports:
      - 80:80
      - 443:443
    networks:
      - foobar-wordpress-network

  node:
    image: node:8.16.0-slim
    working_dir: /home/node/app
    environment:
      - NODE_ENV=development
    volumes:
      - ../../foobar-blog-ui/:/home/node/app
      - ./node_modules:/home/node/app/node_modules
      - ./npm/.npmrc:/home/node/app/.npmrc
    ports:
     - 8000:8000
     - 9000:9000
    command: bash -c "apt-get update && apt-get install -y rsync vim git libpng-dev libjpeg-dev libxi6 build-essential libgl1-mesa-glx && npm install && exit 0"
    depends_on:
      - wordpress
    networks:
      - foobar-wordpress-network

  wordpress:
    build:
      context: ../../
      dockerfile: ./.init/Docker/Services/DockerWordpress.yml
    container_name: wordpress
    restart: on-failure
    ports:
      - 8888:80
    depends_on:
      - db
    networks:
      - foobar-wordpress-network

  wordpress-cli:
    image: wordpress:cli
    volumes:
      - ../../foobar-wordpress-cms/:/var/www/html
      - ./scripts/docker-entrypoint.sh:/var/www/html/docker-entrypoint.sh
    depends_on:
      - wordpress
      - db
    command: sh -c "sleep 30 && ./docker-entrypoint.sh"
    networks:
      - foobar-wordpress-network

volumes:
  node_modules:

networks:
  foobar-wordpress-network:
      driver: bridge

++++++++++++ dockerfile ++++++++++++++++

FROM wordpress:php7.3-apache

WORKDIR /var/www/html/

COPY ./.init/Docker/.env .
COPY ./foobar-wordpress-cms .
COPY ./.init/Docker/php/uploads.ini /usr/local/etc/php/conf.d/uploads.ini
COPY ./.init/Docker/wordpress/wp-config.php ./wp-config.php

RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/bin --filename=composer && chmod +x /usr/bin/composer 
RUN composer require vlucas/phpdotenv
RUN ls -la

The following article also helped ( https://vsupalov.com/docker-arg-env-variable-guide/#the-dot-env-file-env ).

Lanna answered 10/9, 2019 at 1:28 Comment(0)
S
0

Since the code 4 is caused by the environment variables, with or without the inspect docker image returns the following (does not have env variables):

You are mixing two things dotenv vs system environment variable. The dotenv priority is always lowered than the system environment variable and you can not see dotenv variable in docker inspect.

To set env in Docker it should be in Dockerfile ( docker inspect will work) or should be pass to run the command at creation time.

enter image description here

docker exec you_container_name bash -c "printenv" this will print the system environment variable, not dotenv.

enter image description here

Immutability

By default, Dotenv will NOT overwrite existing environment variables that are already set in the environment.

If you want Dotenv to overwrite existing environment variables, use overload instead of load:

$dotenv = Dotenv\Dotenv::create(__DIR__);
$dotenv->overload();

So I will suggest setting in system environment for WordPress if it not picking from dotenv or supposed to pick from system environment variable.

phpdotenv

secure-your-wordpress-config-with-dotenv

Sufficiency answered 10/9, 2019 at 1:29 Comment(0)
O
0

you just need to load the .env file into the container

  wordpress:
    env_file:
      - ./.env
    #environment:
      #WORDPRESS_DB_HOST: ${WORDPRESS_DB_HOST}
      #WORDPRESS_DB_NAME: ${WORDPRESS_DB_NAME}
      #WORDPRESS_DB_USER: ${WORDPRESS_DB_USER}
      #WORDPRESS_DB_PASSWORD: ${WORDPRESS_DB_PASSWORD}

Octan answered 30/5 at 20:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.