Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Environment variables no longer work in Docker Compose #576

Closed
siccovansas opened this issue Mar 11, 2021 · 25 comments
Closed

Environment variables no longer work in Docker Compose #576

siccovansas opened this issue Mar 11, 2021 · 25 comments

Comments

@siccovansas
Copy link

siccovansas commented Mar 11, 2021

After pulling the latest WordPress Docker image today I end up with a default wp-config.php, resulting in 'Error establishing a database connection' when trying to open my WordPress website.

My wp-config.php doesn't contain the values I specify via environment variables in my docker-compose.yml, which are:

  • WORDPRESS_DB_HOST
  • WORDPRESS_DB_NAME_FILE
  • WORDPRESS_DB_USER_FILE
  • WORDPRESS_DB_PASSWORD_FILE
  • WORDPRESS_CONFIG_EXTRA

My logs show this line:
No 'wp-config.php' found in /var/www/html, but 'WORDPRESS_...' variables supplied; copying 'wp-config-docker.php' (WORDPRESS_CONFIG_EXTRA WORDPRESS_DB_HOST WORDPRESS_DB_NAME_FILE WORDPRESS_DB_PASSWORD_FILE WORDPRESS_DB_USER_FILE)

This seems related to the recent merge of Move "wp-config-docker.php" to non-beta (5.7 GA) #572. As per this comment, I entered my Docker container and removed wp-config.php and restarted the container. A new wp-config.php is generated (giving the same message in my logs as shown above), but this is the same as the previous one and doesn't contain the values from my environment variables.

I guess the new issues #573 and #574 are related.

I pull new WordPress docker images on a daily bases, and this problem hasn't occurred before. So I guess it is not caused on my end.

@siccovansas siccovansas changed the title Environment variables no longer work Environment variables no longer work in Docker Compose Mar 11, 2021
@tianon
Copy link
Member

tianon commented Mar 12, 2021

Perhaps you can provide a more specific (minimal) example so we can try to reproduce the issue? 🙏

@tianon
Copy link
Member

tianon commented Mar 12, 2021

If this is in a CI environment, the likely cause is that the WordPress container will no longer wait for MySQL to be "up" / ready before it starts the web server.

@kapoko
Copy link

kapoko commented Mar 13, 2021

Had the same problem. My docker-compose.yml looked like this before, working fine. Which allowed for empty password and a root user.

version: '3'

services:
  database:
    image: mariadb
    ports:
      - 8079:3306
    volumes:
      - ./database:/var/lib/mysql
    restart: always
    environment:
      MYSQL_ALLOW_EMPTY_PASSWORD: "yes"

  wordpress:
    depends_on:
      - database
    image: wordpress:latest
    volumes:
      - ./site/web/app:/var/www/html/wp-content
    ports:
      - 8080:80
    restart: always
    environment:
      WORDPRESS_DB_HOST: database:3306
      WORDPRESS_TABLE_PREFIX: pewp_
      WORDPRESS_DEBUG: 1

But with the new get_env lines:

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

...empty passwords don't work anymore because Wordpress tries to login with 'password_here'.

Would it be a good idea to change to the following to allow for default login? It then wouldn't be necessary to set the user and password in the docker-compose.yml file, which keeps development configuration nice and simple.

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

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

(By the way if you have a running project with a local mysql or mariadb volume which you don't want to destroy, just docker exec it <container id> bash into the container and create a new user with a password, and filling that in docker-compose.yml)

@tianon
Copy link
Member

tianon commented Mar 13, 2021

See #577: we're not likely to bring back the previous insecure default, but we do want to make sure explicitly specifying an empty password works (which I think doesn't right now; I haven't verified that).

As another workaround, you can safely modify your copied wp-config.php (we now only create it initially, we don't update it directly anymore).

That being said, I would strongly recommend creating and using a non-root user with minimal privileges for running WordPress.

@siccovansas
Copy link
Author

Perhaps you can provide a more specific (minimal) example so we can try to reproduce the issue? pray

@tianon thanks for your reply! I'm able to reproduce the problem with the following minimal docker-compose.yml example:

version: '3.1'
services:
  app:
    image: wordpress:5.6.0-php7.4   
    environment:
      WORDPRESS_DB_HOST: mysql
      WORDPRESS_DB_NAME: test
      WORDPRESS_DB_USER: test
      WORDPRESS_DB_PASSWORD: test     
    networks:
      - network                
  mysql:
    image: mysql:8.0
    environment:
      - "MYSQL_DATABASE=test"  
      - "MYSQL_USER=test"
      - "MYSQL_PASSWORD=test"
      - "MYSQL_RANDOM_ROOT_PASSWORD=yes"
    networks:
      - network
networks:
  network:

Everything works fine when you run docker-compose up -d with the file above. The problem arises when you change the WordPress image to wordpress:5.7.0-php7.4 (run docker-compose down and then docker-compose up -d again).

To be more specific, when I use the wordpress:5.6.0-php7.4 image I end up with a wp-config.php that contains the correct database information:

/** The name of the database for WordPress */
define( 'DB_NAME', 'test');

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

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

But when I use the wordpress:5.7.0-php7.4 image I end up with the following which results in a 'Error establishing a database connection' when I try to open WordPress in my browser:

/** The name of the database for WordPress */
define( 'DB_NAME', getenv_docker('WORDPRESS_DB_NAME', 'database_name_here') );

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

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

@kunalnagar
Copy link

kunalnagar commented Mar 14, 2021

@tianon 👋

I have a similar configuration to @siccovansas.

Dockerfile

FROM wordpress:5.7.0-php7.4-apache

SHELL ["/bin/bash", "-c"]

RUN apt-get update && \
  apt-get install vim -y

docker-compose.yml

version: '3.6'
services:

  app:
    container_name: wordpress
    build: .
    ports:
      - 1000:80
    environment:
      WORDPRESS_DB_HOST: mysql
      WORDPRESS_DB_USER: root
      WORDPRESS_DB_PASSWORD: 123
    volumes:
      - ./<plugin>:/var/www/html/wp-content/plugins/<plugin>
    restart: always

  mysql:
    container_name: mariadb
    image: mariadb:10.4.11-bionic
    volumes:
      - ./mysql:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} # These values are coming from a .env file
      - MYSQL_USER=${MYSQL_USER}
      - MYSQL_PASSWORD=${MYSQL_PASSWORD}
      - MYSQL_DATABASE=${MYSQL_DATABASE}
    depends_on:
      - app
    restart: always

  phpmyadmin:
    container_name: phpmyadmin
    image: phpmyadmin/phpmyadmin
    restart: always
    ports:
      - 1080:80
    depends_on:
      - app
      - mysql
    environment:
      PMA_HOST: mysql
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}

Here's what's set in the container's wp-config.php:

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

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

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

/** MySQL hostname */
define( 'DB_HOST', getenv_docker('WORDPRESS_DB_HOST', 'mysql') );

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

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

@kunalnagar
Copy link

☝️

If I use the tag: wordpress:5.6.*-php7.2-apache, everything works, but as soon as I switch to anything 5.7.*, the environment variables don't copy over.

@yosifkit
Copy link
Member

But when I use the wordpress:5.7.0-php7.4 image I end up with the following which results in a 'Error establishing a database connection' when I try to open WordPress in my browser

How long did you want for MySQL to start? With the new changes, the wordpress container will be available almost immediately so the database may not be ready yet.


Here's what's set in the container's wp-config.php:

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

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

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

/** MySQL hostname */
define( 'DB_HOST', getenv_docker('WORDPRESS_DB_HOST', 'mysql') );

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

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

That is exactly how it should currently look. Part of the change is that the environment values are no longer embedded into wp-config.php, but instead they are pulled from the environment (getenv_docker).


Allowing empty passwords again is in #577.

@siccovansas
Copy link
Author

You are right @yosifkit! I didn't wait long enough with the 'failing' example I gave for the database to be ready. So ignore all that :)

The problem seems to be that I'm using Docker Secrets (as mentioned on https://hub.docker.com/_/wordpress/). E.g., in my docker-compose.yml I use WORDPRESS_DB_NAME_FILE instead of WORDPRESS_DB_NAME. But wp_config.php ends up with define( 'DB_NAME', getenv_docker('WORDPRESS_DB_NAME', 'database_name_here') ); which doesn't take into account that it should get the value from WORDPRESS_DB_NAME_FILE.

You can recreate the problem using this docker-compose.yml

version: '3.1'
services:
  app:
    image: wordpress:5.7.0-php7.4
    secrets:
      - db_name
      - db_user
      - db_password
    environment:
      WORDPRESS_DB_HOST: mysql
      WORDPRESS_DB_NAME_FILE: /run/secrets/db_name
      WORDPRESS_DB_USER_FILE: /run/secrets/db_user
      WORDPRESS_DB_PASSWORD_FILE: /run/secrets/db_password
    networks:
      - network
  mysql:
    image: mysql:8.0
    secrets:
      - db_name
      - db_user
      - db_password
    environment:
      - "MYSQL_DATABASE_FILE=/run/secrets/db_name"
      - "MYSQL_USER_FILE=/run/secrets/db_user"
      - "MYSQL_PASSWORD_FILE=/run/secrets/db_password"
      - "MYSQL_RANDOM_ROOT_PASSWORD=yes"
    networks:
      - network
secrets:
  db_name:
    file: ./secrets_db_name.txt
  db_user:
    file: ./secrets_db_user.txt
  db_password:
    file: ./secrets_db_password.txt
networks:
  network:

Create the secrets_db_name.txt, secrets_db_user.txt, and secrets_db_password.txt files, each containing one line with a value (which e.g., could all be test)

@yosifkit
Copy link
Member

getenv_docker definitely uses _FILE variables before falling back to the non-_FILE variable (as the image has in the past via the entrypoint script).

function getenv_docker($env, $default) {
if ($fileEnv = getenv($env . '_FILE')) {
return file_get_contents($fileEnv);
}
else if ($val = getenv($env)) {

But it seems like there is a bug if the secret files have new lines. Using the compose file in the comment just above and adding WORDPRESS_DEBUG I was able to see the possible issue:

Warning: mysqli_real_connect(): (HY000/1045): Access denied for user 'test
'@'172.18.0.3' (using password: YES) in /var/www/html/wp-includes/wp-db.php on line 1653

My three secret files were just created with echo test > secrets_db_password.txt and so they included a new line in them (which we need to allow and trim as the shell script did). A workaround until a fix is added is to ensure the secret files don't have a newline: echo -n test > secrets_db_password.txt

@yosifkit
Copy link
Member

Added fix for newlines in _FILE contents to #577

@siccovansas
Copy link
Author

Removing the newlines from the secret files indeed fixes my problem! Thanks for troubleshooting and adding a fix! Case closed I guess :)

@kunalnagar
Copy link

kunalnagar commented Mar 16, 2021

How long did you want for MySQL to start? With the new changes, the wordpress container will be available almost immediately so the database may not be ready yet.

@yosifkit I waited for quite a bit, here's a quick video demo. It says mysqld ready for connections... but I still get the WordPress Database Error screen.

Wordpress_Docker_Demo.mov

@kunalnagar
Copy link

@yosifkit I also noticed that there's no tables in my database 🤔

image

@siccovansas
Copy link
Author

@kunalnagar I guess you have another issue, but it looks like you're missing WORDPRESS_DB_NAME: custom404pro in your docker-compose.yml

@kunalnagar
Copy link

@siccovansas I think so too. But I've tried adding WORDPRESS_DB_NAME and it still doesn't work for me. Maybe it's the mariadb image that I'm using. I'll try switching around to different mysql images and see what happens.

Could you possibly post your docker-compose.yml file here for reference redacting all secrets of course?

@kunalnagar
Copy link

@yosifkit @siccovansas I left it running for about 15 mins or so and it worked! 🎉

@MrksHfmn
Copy link

Same problem here #578 but without any new lines or line breaks in secrets

@yosifkit
Copy link
Member

yosifkit commented Mar 16, 2021

Do note that there is no need to use this mechanism to create the root superuser, that user gets created by default with the password specified by the MYSQL_ROOT_PASSWORD variable.

https://github.com/docker-library/docs/tree/2b1bfbc81bab0f10d024aa2fd7ac4c999487e6ac/mysql#mysql_user-mysql_password

Do not put root as the value of MYSQL_USER. It will likely fail to finish database initialization.

@rudSarkar
Copy link

Perhaps you can provide a more specific (minimal) example so we can try to reproduce the issue? pray

@tianon thanks for your reply! I'm able to reproduce the problem with the following minimal docker-compose.yml example:

version: '3.1'
services:
  app:
    image: wordpress:5.6.0-php7.4   
    environment:
      WORDPRESS_DB_HOST: mysql
      WORDPRESS_DB_NAME: test
      WORDPRESS_DB_USER: test
      WORDPRESS_DB_PASSWORD: test     
    networks:
      - network                
  mysql:
    image: mysql:8.0
    environment:
      - "MYSQL_DATABASE=test"  
      - "MYSQL_USER=test"
      - "MYSQL_PASSWORD=test"
      - "MYSQL_RANDOM_ROOT_PASSWORD=yes"
    networks:
      - network
networks:
  network:

Everything works fine when you run docker-compose up -d with the file above. The problem arises when you change the WordPress image to wordpress:5.7.0-php7.4 (run docker-compose down and then docker-compose up -d again).

To be more specific, when I use the wordpress:5.6.0-php7.4 image I end up with a wp-config.php that contains the correct database information:

/** The name of the database for WordPress */
define( 'DB_NAME', 'test');

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

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

But when I use the wordpress:5.7.0-php7.4 image I end up with the following which results in a 'Error establishing a database connection' when I try to open WordPress in my browser:

/** The name of the database for WordPress */
define( 'DB_NAME', getenv_docker('WORDPRESS_DB_NAME', 'database_name_here') );

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

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

I used wordpress:5.6.0-php7.4 and it working totally fine.

sdellenb added a commit to sdellenb/wordpress-testing that referenced this issue Oct 23, 2021
None of the overrides worked anymore in the latest docker image because overriding requires a special wp-config.php, which we now use.
See docker-library/wordpress#576

The previous values that need to be preserved are now extracted to a environment file for Docker.

A future commit might also include username, password and the database values, which for now stay hard-coded.
@winkee01
Copy link

winkee01 commented Nov 24, 2021

wordpress failed to read WORDPRESS_DB_HOST environment variable!

environment:
  - WORDPRESS_DB_NAME=wordpress
  - WORDPRESS_TABLE_PREFIX='wp_'
  - WORDPRESS_DB_HOST="db:3306"
  - WORDPRESS_DB_USER="wp_user"
  - WORDPRESS_DB_PASSWORD="wp_passwd"
  - WORDPRESS_DEBUG= "1"

in wp-config.php, the corresponding env variables are not reading the these values.

I have to manually add above values to the variable so that wordpress can connect to the database.

basically, getenv_docker()function in wp-config.php failed to work.

@yosifkit
Copy link
Member

You'd have to give more information (maybe every small step needed to reproduce the problem). We have tried and are unable to replicate the problem (except for not waiting long enough for MySQL to start). You can even click the "play-with-docker" link and see that the getenv_docker is working when using this sample yaml file: docker-library wordpress/stack.yaml.

@winkee01
Copy link

winkee01 commented Nov 25, 2021

@yosifkit
I can reproduce it every time.
For simplicity, I uploaded my source files into a repo: https://github.com/winkee01/docker-nginx-php-fpm.
After you clone it to your local directory.

Follow the below steps:

mkdir run
docker-compose up
docker exec -it nginx-php bash
> usermod -u 82 www-data && groupmod -g 82 www-data && nginx -s reload
> exit
echo "your_ip testwp.ok" >> /etc/hosts

a bit of explanation
We must change the user & group in nginx container because it has to be the same with the user, and its uid & gid also has to be the same. And that's why we need to login to nginx-php container to make the changes.

Now, open URL testwp.ok (I set this as a default domain for testing) in your browser,

you will see this symptom:

JPEG 2021-11-25 at 14 09 39@2x

The reason is
getenv_docker function in wp-config.php failed to read environment variables passed in docker-compose.yml.

You can verify this by entering php-fpm container,

docker exec -it php7.4fpm bash
env | grep WORDPRESS

the variables are correctly shown, but wp-config.php failed to read them.

If you change the variables's value in wp-config.php to the correct, you will load the site successfully.

@tianon
Copy link
Member

tianon commented Nov 29, 2021

@winkee01 in https://github.com/winkee01/docker-nginx-php-fpm/blob/1c1788fe2a77bcd91f7501874bc95988526f1165/php-fpm.conf#L71, you're not setting clear_env = no, and it defaults to yes (which will not let PHP access the environment variables).

See https://github.com/docker-library/php/blob/f17e9741e28808a0f642dd0487af15a3b1154ed2/7.4/bullseye/fpm/Dockerfile#L248 for where we do this in the php image's default configuration.

@hexclann

This comment was marked as off-topic.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants