I've a question how exactly docker-compose handles environment variables.
services:
wp:
image: wordpress:latest
container_name: "wp"
restart: unless-stopped
links:
- wpdb
environment:
- TZ=Europe/Berlin
- WORDPRESS_DB_HOST=wpdb:3306
- WORDPRESS_DB_USER=wordpress
- WORDPRESS_DB_PASSWORD=password
- WORDPRESS_DB_NAME=wp
volumes:
- ./data:/var/www/html
labels:
- "traefik.enable=true"
- "traefik.backend=wp"
- "traefik.frontend.rule=Host:MASKED"
- "traefik.port=80"
- "traefik.docker.network=web"
networks:
- internal
- web
wpdb:
image: mariadb:latest
restart: unless-stopped
container_name: "wpdb"
environment:
- MYSQL_ROOT_PASSWORD=1234
- MYSQL_USER=wordpress
- MYSQL_PASSWORD=password
- MYSQL_DATABASE=wp
networks:
- internal
labels:
- "traefik.enable=false"
volumes:
- ./sql:/var/lib/mysql
volumes:
data:
sql:
networks:
web:
external: true
internal:
The compose file works great. The containers will be created and work perfectly.
But when I change the defaults at: WORDPRESS_DB_PASSWORD=password and MYSQL_PASSWORD=password.
The Wordpress container throws access denied for user. I also tried to kill the container and volumes.
Hopefully someone has a hint for me.
You should be doing a docker-compose down -v which would delete the named volumes declared in the volumes section. The only downside is that you would be losing all the data created by the service for the first time.
Here is how I could reproduce it -
Used your compose file as reference and on first time used the default password mentioned by you. The services come up fine, I install it and do a Ctrl+C to bring down the service. So all the MYSQL data is written into sql named volume.
When you do a Ctrl+C OR docker-compose down it only removes the containers and networks defined in the service. Not the volumes. Read more about it here
Now when you change password and bring the service back up it still uses the old volumes which has your old password.
So use a docker-compose down -v to remove the volumes too and give it a try.
Here are the steps how I reproduced it
Ctrl+C to stop all the services and then update the docker-compose.yml to update the password and do a docker-compose up again to get access denied error.
Do a docker-compose down -v to clean all the volume too and then do a docker-compose up
On doing a docker-compose down -v you will be losing all the data created by the prior service. Use it cautiously.
Related
Firstly, I'd like to say that I'm not a server admin. I'm a web programmer tasked with setting up a development server and I have no idea what I'm doing. I may not be doing things according to best practice or the way you might do them. Unfortunately, with Traefik, there are 3 ways to do everything and so 2/3 of the answers that I've come across aren't compatible with my implementation and I can't figure out how to make them work. Furthermore, this isn't my only (or even primary) job duty.
Here's the setup:
Single-server docker environment on a Linode server with Ubuntu 20.04
I have one stack with Traefik, Traefik Hub, Portainer, and WhoAmI configured and working (mostly) correctly. I don't have the DNS challenge working right with Let's Encrypt, but I don't really care about that at this point. I don't really need a wildcard certificate.
I created a mariadb container. We're mostly a WordPress shop and I'd like to have one container for all the databases we work with rather than configuring a database on an environment-by-environment basis.
I created an external bridge network, named "maverick-net" and all of the stacks are connected to it.
I have a self-hosted GitHub runner listening for changes to the "dev" branch of the project. The runner pulls down the latest repo, writes GitHub secrets to a local .env file, runs composer install and then docker-compose up -d. (That's the reason behind the obscenely-long bind mount paths.)
I'm trying to make the code for these WordPress projects reusable as much as possible, so there's a lot of .env variables in the different files. At some point I'll probably move those over to docker secrets, but at this point it's a development server and not as critical.
My issue is that I haven't been able to get a WordPress site up and running, and I keep hitting a "Bad Gateway" error. When I curl the URL from inside the traefik container, I get... wait for it... "Bad Gateway."
Clearly there's something I'm missing, but I've been slamming my head against a brick wall for weeks trying different approaches to get this running and I need help. There has to be something I'm not getting about docker networks in general because my wp-cli container never has been able to connect to the database, regardless of whether I start it in the same stack or if i try to connect to it on the maverick-net network.
My traefik stack (side note, I'd really like to split these command entries into static and dynamic config files, but that's a task for another day):
version: "3.9"
secrets:
linode_token:
file: "../secrets/linode_token.secret"
services:
traefik:
container_name: traefik
image: "traefik:latest"
command:
- --log.level=DEBUG
- --log.filePath=./traefik.log
- --accessLog=true
- --accessLog.filePath=./access.log
- --accessLog.bufferingSize=100
- --accessLog.filters.statusCodes=400-499
- --api
- --api.dashboard=true
- --api.insecure=false
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- --providers.docker
- --providers.docker.watch=true
- --providers.docker.exposedbydefault=false
- --certificatesresolvers.leresolver.acme.dnsChallenge=true
- --certificatesresolvers.leresolver.acme.dnsChallenge.provider=linodev4
- --certificatesresolvers.leresolver.acme.httpchallenge=true
- --certificatesresolvers.leresolver.acme.httpchallenge.entrypoint=web
- --certificatesresolvers.leresolver.acme.email=xxxxxxxxxxx#xxxxxxxxx.xxx
- --certificatesresolvers.leresolver.acme.storage=./acme.json
#- --certificatesresolvers.leresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory
- --certificatesresolvers.leresolver.acme.caserver=https://acme-v02.api.letsencrypt.org/directory
- --experimental.hub=true
- --hub.tls.insecure=true
- --metrics.prometheus.addrouterslabels=true
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ~/certs-data/acme.json:/data/letsencrypt/acme.json
- ./static.yml:/static.yml:ro
- ./configs:/configs
- ~/certs-data/:/data/letsencrypt/
secrets:
- "linode_token"
environment:
TZ: America/Chicago
LINODE_TOKEN_FILE: "/run/secrets/linode_token"
labels:
- "traefik.enable=true"
- "traefik.docker.network=maverick-net"
- "traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)"
- "traefik.http.routers.http-catchall.entrypoints=web"
- "traefik.http.routers.http-catchall.middlewares=redirect-to-https"
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
- "traefik.http.routers.traefik.tls.certresolver=leresolver"
- "traefik.http.routers.traefik.rule=Host(`XXXXX.XXXXXXXXXX.XXX`)"
- "traefik.http.routers.traefik.entrypoints=websecure"
- "traefik.http.routers.traefik.service=api#internal"
- "traefik.http.routers.traefik.middlewares=traefik-auth"
- "traefik.http.middlewares.traefik-auth.basicauth.users=XXXX:$$apr1$$XXXXX$$XXXXXXXXXXXXXXX"
- "traefik.http.routers.api.entrypoints=websecure"
networks:
- maverick-net
hub-agent:
image: ghcr.io/traefik/hub-agent-traefik:experimental
pull_policy: always
container_name: hub-agent
restart: on-failure
command:
- run
- --hub.token=XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXX
- --auth-server.advertise-url=http://hub-agent
- --traefik.host=traefik
- --traefik.tls.insecure=true
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
depends_on:
- traefik
networks:
- maverick-net
portainer:
image: portainer/portainer-ce:latest
command: -H unix:///var/run/docker.sock
container_name: portainer
restart: always
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- portainer_data:/data
labels:
# Frontend
- "traefik.enable=true"
- "traefik.http.routers.frontend.rule=Host(`XXXXX.XXXXXXXXXX.XXX`)"
- "traefik.http.routers.frontend.entrypoints=websecure"
- "traefik.http.services.frontend.loadbalancer.server.port=9000"
- "traefik.http.routers.frontend.service=frontend"
- "traefik.http.routers.frontend.tls.certresolver=leresolver"
networks:
- maverick-net
whoami:
image: "traefik/whoami"
container_name: "whoami"
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoami.rule=Host(`XXXXX.XXXXXXXXXX.XXX`)"
- "traefik.http.routers.whoami.entrypoints=websecure"
- "traefik.http.routers.whoami.tls.certresolver=leresolver"
networks:
- maverick-net
volumes:
portainer_data:
networks:
maverick-net:
external: true
My mariadb stack:
version: "3"
networks:
# enable connection with Traefik
maverick-net:
external: true
services:
mariadb:
container_name: mariadb
image: mariadb:10.7
restart: always
volumes:
- "/home/xxxxxxxxxx/docker/mariadb/data:/var/lib/mysql"
expose:
- "3306"
env_file: .env
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PWD}
MYSQL_USER: ${ADMIN_DB_USER}
MYSQL_PASSWORD: ${ADMIN_DB_PWD}
networks:
- maverick-net
And finally my WordPress stack:
version: '3.8'
networks:
maverick-net:
external: true
# volumes:
# db_data:
services:
# mariadb:
# container_name: ${WORDPRESS_DB_NAME}-db
# image: mariadb:10.7
# restart: always
# volumes:
# - "db_data:/var/lib/mysql"
# env_file: .env
# environment:
# MYSQL_ROOT_PASSWORD: ${MARIADB_ROOT_PASSWORD}
# MYSQL_USER: ${ADMIN_DB_USER}
# MYSQL_PASSWORD: ${ADMIN_DB_PWD}
wordpress:
container_name: ${WORDPRESS_DB_NAME}-wp
image: wordpress:6.0.2-fpm
volumes:
- type: bind
source: ${PROJECT_ROOT}/${WORDPRESS_DB_NAME}/${PROJECT_NAME}/${PROJECT_NAME}/wp
target: /var/www/html
restart: always
env_file: .env
environment:
WORDPRESS_DB_HOST: mariadb
MARIADB_ROOT_PASSWORD: ${MARIADB_ROOT_PASSWORD}
WORDPRESS_DATABASE_USER: ${WORDPRESS_DB_USER}
WORDPRESS_DATABASE_PASSWORD: ${WORDPRESS_DB_PASSWORD}
WORDPRESS_DATABASE_NAME: ${WORDPRESS_DB_NAME}
labels:
# The labels are useful for Traefik only
- "traefik.enable=true"
- "traefik.docker.network=maverick-net"
# Get the routes from https
- "traefik.http.routers.${WORDPRESS_DB_NAME}.rule=Host(`${DEV_URL}`)"
- "traefik.http.routers.${WORDPRESS_DB_NAME}.entrypoints=websecure"
- "traefik.http.routers.${WORDPRESS_DB_NAME}.tls.certresolver=leresolver"
networks:
- maverick-net
wordpress-cli:
container_name: ${WORDPRESS_DB_NAME}-cli
image: wordpress:cli
volumes:
- type: bind
source: ${PROJECT_ROOT}/${WORDPRESS_DB_NAME}/${PROJECT_NAME}/${PROJECT_NAME}/wp
target: /var/www/html
env_file: .env
environment:
WORDPRESS_DB_HOST: mariadb
MARIADB_ROOT_PASSWORD: ${MARIADB_ROOT_PASSWORD}
WORDPRESS_DATABASE_USER: ${WORDPRESS_DB_USER}
WORDPRESS_DATABASE_PASSWORD: ${WORDPRESS_DB_PASSWORD}
WORDPRESS_DATABASE_NAME: ${WORDPRESS_DB_NAME}
networks:
- maverick-net
depends_on:
- wordpress
As far as I know, you can connect to containers in the same network by using their service name.
So for example you are trying to curl to the Wordpress container from the Traefik Container.
curl 'http://wordpress/'
Should work.
In another project I use an nginx container with php-fpm.
I need to send my curl requests to the nginx container, because the php-fpm container does not handle server requests directly:
// does not work
curl 'http://php-debug/index.html'
// result
curl: (7) Failed to connect to php-debug port 80: Connection refused
// https also does not work
curl 'https://php-fpm/index.html'
// result
curl: (7) Failed to connect to php-fpm port 443: Connection refused
// This does work
curl 'http://nginx/index.html'
// result
<HTML...
For some reason https: curl requests fail, but on http I get the correct result so for local development I think it's ok.
If you are interested in a more managed solution, you can check out warden.dev. It contains a template for Wordpress too (which I use succesfully for local development). I have been using this exclusively. If you have questions how to setup WP CLI on this solution, feel free to contact me.
It comes with portainer, traefik, ssl and dns and mailhog.
Configuration is pretty straight forward, I can set up a new project within an hour and connect to the database and containers in my IDE.
https://docs.warden.dev/environments/types.html#wordpress
I am trying to create a basic wordpress/mariadb/wpcli docker container stack. All works as expected, except that the wpcli service fails at startup time with this error turning up in the logs:
"Error: Error establishing a database connection."
To be clear, I can access the wordpress site just fine after allowing enough time for the db and wp containers to spin up. But the wpcli container fails.
Here is my docker-compose.yml:
version: '3.9'
services:
db:
# We use a mariadb image which supports both amd64 & arm64 architecture
image: mariadb:latest
# If you really want to use MySQL, uncomment the following line
#image: mysql:8.0.27
command: '--default-authentication-plugin=mysql_native_password'
volumes:
- db_data:/var/lib/mysql
restart: always
environment:
- MYSQL_ROOT_PASSWORD=somewordpress
- MYSQL_DATABASE=wordpress
- MYSQL_USER=wordpress
- MYSQL_PASSWORD=wordpress
expose:
- 3306
- 33060
wordpress:
image: wordpress:php8.1
ports:
- 80:80
restart: always
depends_on:
- db
environment:
- WORDPRESS_DB_HOST=db
- WORDPRESS_DB_USER=wordpress
- WORDPRESS_DB_PASSWORD=wordpress
- WORDPRESS_DB_NAME=wordpress
volumes:
- wordpress:/var/www/html
wpcli:
image: wordpress:cli-php8.1
# restart: always
depends_on:
- db
- wordpress
environment:
- WORDPRESS_DB_HOST=db
- WORDPRESS_DB_USER=wordpress
- WORDPRESS_DB_PASSWORD=wordpress
- WORDPRESS_DB_NAME=wordpress
volumes:
- wordpress:/var/www/html
volumes:
db_data:
wordpress:
My plan for the short term is to develop new themes for an already existing site, so I have the workaround that I can install wpcli directly in the wp container. But that's a pain, and I am new to docker (definitely not new to linux or wordpress) and I don't really want to take time right now to learn how to roll my own container that has both wordpress and wpcli.
Incidentally, I tried the Bitnami wordpress container which has exactly that, but ran into issues mounting volumes on localhost due to those being non-root containers.
Any ideas about how to get the wpcli container from the official wordpress to work?
Thanks in advance for your help!
Here is my docker-compose.yml file:
version: '3.9'
services:
db:
image: mysql:5.7
restart: always
command: [
'--disable-partition-engine-check',
'--default_authentication_plugin=mysql_native_password',
'--character-set-server=utf8mb4',
'--collation-server=utf8mb4_unicode_ci',
'--max_allowed_packet=100M'
]
volumes:
- ./db_data:/var/lib/mysql
environment:
MYSQL_DATABASE: wordpress
MYSQL_ROOT_PASSWORD: pswd4!
pma:
image: phpmyadmin/phpmyadmin
environment:
PMA_HOST: db
PMA_PORT: 3306
MYSQL_ROOT_PASSWORD: pswd4!
UPLOAD_LIMIT: 1G
ports:
- 8080:80
depends_on:
- db
wp:
image: wordpress:php8.0
ports:
- 80:80
volumes:
- ./config/php.conf.ini:/usr/local/etc/php/conf.d/conf.ini
- ./:/var/www/html
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_NAME: wordpress
WORDPRESS_DB_USER: root
WORDPRESS_DB_PASSWORD: pswd4!
WORDPRESS_DEBUG: 1
depends_on:
- db
links:
- db:mysql
hostname: test.localhost
wpcli:
image: wordpress:cli-php8.0
volumes_from:
- wp
depends_on:
- db
- wp
links:
- db:mysql
entrypoint: wp
command: "--info"
volumes:
db_data:
When I try to use wp-cli in Docker (e.g. docker-compose run --rm wpcli plugin list), it gets an error that it cannot connect to the database:
Error: `Access denied for user 'username_here'#'192.168.32.5' (using password: YES)`
Error establishing a database connection
This either means that the username and password information in your `wp-config.php` file is incorrect or we can’t contact the database server at `mysql`. This could mean your host’s database server is down.
Are you sure you have the correct username and password?
Are you sure you have typed the correct hostname?
Are you sure the database server is running?
If you’re unsure what these terms mean you should probably contact your host. If you still need help you can always visit the WordPress Support Forums. `Access denied for user 'username_here'#'192.168.32.5' (using password: YES)
`
It looks like wp-cli is seeing bad database credentials (username_here instead of root)
Result of executing docker-compose run --rm wpcli config list command:
What could be wrong? I've searched all over the internet, lost several hours and still haven't found the cause of the problem.
You should specify the same set of environment variables as in your wp container for your wpcli container. If not, default variables from a php file in wordpress are used.
Do be careful : volumes_from and link options are deprecated in compose v3. For the link option, docker-compose creates a network automatically (or you can specify one if you prefer) and the embed docker dns automatically attributes aliases to your containers based on their names (or in compose the service name). More info on that here
For volumes, you can find more info here
There is problem with symfony cache and logs in docker containers.
Web server executes from www-data user and group and when I do symfony cache clear from docker container using php that is installed on docker, it executes from root.
So if I remove var/logs/dev.log for example and open url in browser, new log.dev gets created with user and group: www-data:www-data, but after i do cache clear, it gets permissions root:root and url in browser gives error dev.log permission denied.
I am not sure whats the problem, but I guess somehow nginx operates under www-data and when I execute console commands they operate from root user.
I have 4 containers: nginx, php-fpm, mysql, rabbit.
I also use version 3 of docker compose, I thought of solution with group_add but its no longer available in version 3
How do I configure this?
=================
docker-compose is similar to this:
version: "3"
services:
nginx:
image: nginx:1.11
depends_on:
- php-fpm
links:
- php-fpm
environment:
- NGINX_PORT=80
- FASTCGI_HOST=php
- FASTCGI_PORT=9000
- DOCUMENT_ROOT=/usr/local/src/test-project/public
ports:
- 8095:80
volumes:
- .:/usr/local/src/test-project
- ./docker/nginx/templates/default.conf.template:/etc/nginx/conf.d/default.conf.template
- ./docker/nginx/entrypoint.sh:/entrypoint.sh
command: "/bin/bash /entrypoint.sh"
php-fpm:
build: docker/php
depends_on:
- db
extra_hosts:
- "test-project:127.0.0.1"
environment:
DATABASE_URL: pgsql://test-project_users:test-project_users#db:5432/test-project_users
APP_URL: 172.19.0.1:8095/
working_dir: /usr/local/src/test-project
volumes:
- .:/usr/local/src/test-project
db:
image: postgres
restart: always
ports:
- '5599:5432'
environment:
POSTGRES_DB: test-project_users
POSTGRES_USER: test-project_users
POSTGRES_PASSWORD: test-project_users
volumes:
- data:/var/lib/db
The problem is, that you are clearing the cache as root user via command-line. you should run the clear statement with su www-data.
I have all set in my local machine for virtual machine shared folders. I have following code in my Docker compose file for Wordpress service. but not sure how the volumes work here. Can you please explain?
version: '2'
services:
database:
image: mysql:5.6
volumes:
- ./mysql-data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: password
restart: unless-stopped
wordpress:
image: wordpress:4.9.6
ports:
- 49160:80
links:
- database:mysql
volumes:
- ./wordpress:/var/www/html/wp-content
environment:
WORDPRESS_DB_PASSWORD: password
restart: unless-stopped
phpmyadmin:
image: phpmyadmin/phpmyadmin
links:
- database:db
ports:
- 8080:80
Does the above volumes line of code mean, does it need to create a WordPress folder in my docker-compsose.yml file that I am currently running?
Or is it anyhow related to my shared folders in virtual machine?
Basically volumes are instruments for Docker so it can retain data. Docker containers are generally designed to be stateless, but if you need to retain state/information between runs, that's where volumes come in.
You can create an unnamed volume in the following way:
volumes:
- /var/www/html/wp-content
This will retain your wp-content folder in the internal volumes storage without a particular name.
A second way would be to give it a name, making it a named volume:
volumes:
- mywp:/var/www/html/wp-content
And the final type, which is also what you are doing, is called a Volume Bind. This basically binds/mounts the content of a folder on your host machine in the container. So if you change a file in either place, it will be saved on the other.
volumes:
- ./wordpress:/var/www/html/wp-content
In order to use your Volume Bind, you will need to create the folder "wordpress" in the folder where you're running the docker-compose.yaml (usually your root folder). Afterwards, when your installation changes within the container, it will also change on the bind and vice-versa.
EDIT: In your particular case the following should work:
version: '3.2'
services:
database:
image: mysql:5.6
volumes:
- ./mysql-data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: password
restart: unless-stopped
wordpress:
image: wordpress:4.9.6
ports:
- 49160:80
links:
- database:mysql
volumes:
- type: bind
source: ./wordpress
target: /var/www/html/wp-content
environment:
WORDPRESS_DB_PASSWORD: password
restart: unless-stopped
phpmyadmin:
image: phpmyadmin/phpmyadmin
links:
- database:db
ports:
- 8080:80
Adding a volume to your docker-compose.yml file will enable you to 'mount' content from your local file system into the running container.
So, about the following line here:
volumes:
- ./wordpress:/var/www/html/wp-content
This means that whatever's in your local wordpress directory will be placed in the /var/www/html/wp-content directory inside your container. This is useful because it allows you to develop themes and plugins locally and automatically inject them into the running container.
To avoid confusion, I'd recommend renaming wordpress to something else, so it's clear that you're mounting only your WordPress content, and not core files themselves.
I have a similar setup here, in case you need another reference:
https://github.com/alexmacarthur/wp-skateboard