Note: If you are here just looking for troubleshooting tips on making something running in a Docker container be able to talk to a database – particularly a MySQL database – on the host system, skip down a bit.
I was not prepared to have something like half the web applications I have running on my home lab to pooch it when Debian upgraded PHP from 7.4 to 8.1.
Yes, I was running a lot of them on "bare metal" – that is, they were not inside containers.
While I was able to find either upgraded versions or replacement programs, I realized there had to be another way that would just let me get a bunch of those web applications back up and running quickly.
Most of those sites were already running behind a reverse proxy anyway. So, I asked myself, what if I learned how to run Apache and PHP 7.4 inside Docker, and allowed my "main" bare metal setup to follow Debian’s upgrade path?
Welp, I managed to make it work.
The container, which is based on Debian bullseye-slim, will load any sites configured in the
apache-sites subdirectory, and serve files in the
www subdirectory. It is accessible on port 8180 by default (since everybody uses 8080), and that’s easily changed by editing one line in
It’s meant to be able to be dropped in place so that you mainly have to move a few things around. The idea is that it is (potentially) as little configuration as moving a configuration file, making a symbolic link, and typing
docker-compose up -d --build.
The Docker image also uses a script that loads Apache modules and customizes
php.ini the first time it’s run. You may not need to touch it at all, though it changes some default values that I regularly need changes in my homelab. I tried to make it as clean, commented, and obvious exactly what it does and how in the
docker-compose.yaml, because while it’s all documented somewhere, it’s definitely NOT all documented in the same place.
Likewise, the trickiest part was figuring out how to get it to talk to the (already existing) databases on the host machine. This was easily the most time-consuming portion of the whole task, so if you stumbled onto this looking for this solution, here you go:
Having a Dockerized App Talk To MySQL on the Host
I figured this out for MySQL because, well, that’s what I needed for the web applications I was using. I presume that PgSQL and others have similar issues, YMMV.
The problems come from MySQL having its own permissions separate from the UID/GID permissions of the user. To make this work, you are theoretically weakening your security slightly. Therefore, you must ensure that port 3306 (for MySQL) is not reachable from outside your LAN.
Your firewall must allow access from the IP address or IP address range of the Docker container. You can discover what that IP address is by running
docker inspect [container ID] | grep IPAddresswhile the container is running. Typically, the netmask is
The less secure – but far easier – method is to have the firewall on the server allow access to port 3306, and rely on the router firewall upstream to block access. If you are using UFW, you can achieve this by
sudo ufw allow in to any port 3306.
You will need to ensure that the database user can connect from something other than
localhost. The "connect from anywhere" syntax for MySQL is
'user'@'%', so for example:
CREATE USER 'myuser'@'%' IDENTIFIED BY 'mycomplicatedpassword'; GRANT ALL PRIVILEGES ON mydb.* TO 'myuser'@'%';
Finally, you will probably have to change the address that MySQL binds to as well. The instructions at Stack Overflow at https://stackoverflow.com/questions/16287559/mysql-adding-user-for-remote-access#37341046 worked great.
I learned quite a bit about how all these parts work together putting this together. Even if the finished project is not something that you need, I hope that looking at the parts of it helps someone else better understand Docker and how the parts of it work together, just like it helped me.