How to Deploy MariaDB 11.2.2 Using Docker Compose Behind Caddy v2.7.6
MariaDB turns data into structured information in a wide array of applications, ranging from banking to websites. It is an enhanced, drop-in replacement for MySQL.

MariaDB turns data into structured information across a wide array of applications, ranging from banking systems to enterprise websites. It is an enhanced, highly performant, drop-in replacement for MySQL.
Previously, I documented how to deploy MariaDB in a Docker Swarm environment.
Today, I am going to show you how to deploy MariaDB 11.2.2 using Docker Compose behind a Caddy reverse proxy. In this setup, we are not exposing the MariaDB service to the external network. It will be securely isolated and available only to internal services or applications.
MariaDB is used because it is fast, scalable, and robust. Its rich ecosystem of storage engines, plugins, and tools makes it incredibly versatile for a wide variety of use cases.
Let’s start with the actual deployment.
Prerequisites
Please ensure you fulfill the following requirements before proceeding with the deployment:
- A server running the latest Ubuntu release (any Linux distribution works, but Ubuntu is used throughout this guide).
- Docker and Docker Compose installed on the Ubuntu server.
Introduction to MariaDB
MariaDB is one of the most popular database servers in the world. It is a fork of MySQL, created by the original developers of MySQL.
MariaDB is guaranteed to stay open source forever. Notable users include Wikipedia, WordPress.com, and Google.
Developed as open-source software, MariaDB provides a robust SQL interface for accessing data and features modern capabilities, including built-in GIS and JSON support.
You can read more about MariaDB here.
Securing the MariaDB Environment
MariaDB Docker images offer various ways to set the MySQL root password, but some methods are far more secure than others:
- Environment Variables: Specifying
MYSQL_ROOT_PASSWORDdirectly in the compose file. (Least secure) - Mounted Files: Mounting a plain-text password file into the container. (Better, but still exposed on the host)
- Random Generation: Specifying
MYSQL_RANDOM_ROOT_PASSWORDto have MariaDB generate and print a random password to the logs. (Recommended) - Docker Secrets: Securely storing credentials. In Swarm, this uses an encrypted Raft log; in local Docker Compose, it mounts local files into memory securely. (Highly Recommended)
We will use the Docker Secrets method to pass the required password values to our MariaDB container.
Specifying MYSQL_ROOT_PASSWORD in standard environment variables is the least secure option, as variables are exposed to the host system and container inspection, leaving the password at a high risk of exposure. Docker introduced Docker Secrets in version 1.13 to manage sensitive data natively. You can read the overview here.
Setting up containers with secrets in Docker Compose is straightforward and keeps passwords completely out of your source code.
MariaDB Custom Configuration (Optional)
The primary startup configuration is located at /etc/mysql/my.cnf. This file also includes any .cnf files found in the /etc/mysql/conf.d directory.
If you want to use a customized MySQL configuration, you can create an alternative configuration file on the host and mount its directory into the container:
version: "3.7"
services:
mariadb:
image: mariadb:latest
volumes:
- /my/custom:/etc/mysql/conf.d
This will start the
mariadbcontainer using the combined startup settings from/etc/mysql/my.cnfand/etc/mysql/conf.d/config-file.cnf, with the custom settings taking precedence.
Alternatively, many configuration options can be passed directly as flags to mysqld via the command key. For example, to change the default encoding to utf8mb4 and adjust timeout settings:
version: "3.7"
services:
mariadb:
image: mariadb:latest
command: ["mariadb", "--character-set-server=utf8mb4", "--collation-server=utf8mb4_unicode_ci", "--wait_timeout=28800", "--interactive_timeout=28800", "--max_allowed_packet=256M"]
Check the MariaDB Docker Hub page for more configuration options.
Prepare the MariaDB Environment
Let’s start by creating the password files for our MariaDB container using the Docker Secrets method.
Create the required .txt files in your deployment directory:
cd /opt
sudo nano mysql_user.txt
sudo nano mysql_database.txt
sudo nano wp_db_password.txt
sudo nano mysql_root_password.txt
(Enter the respective values into each file, save, and exit).
For disaster recovery and data persistence, we need to map the /var/lib/mysql directory inside the container to the host filesystem.
Create a persistent folder in the /opt directory:
cd /opt
sudo mkdir -p mariadata
Docker Compose Configuration
Now, it’s time to create a docker-compose.yml file that contains both the Caddy Reverse Proxy service and the MariaDB service.
First, create a Docker network named caddy. We will use this to expose internal applications to the outside world safely.
docker network create caddy
We will use an additional bridge network named
inetto connect the MariaDB service securely without exposing it externally.
Create the Compose file:
cd /opt
sudo touch docker-compose.yml
sudo nano docker-compose.yml
Paste the following stack configuration:
version: "3.7"
services:
maria:
image: mariadb:11.2.2
container_name: maria
restart: unless-stopped
depends_on:
caddy:
condition: service_started
volumes:
- ./mariadata:/var/lib/mysql
secrets:
- mysql_user
- mysql_database
- mysql_db_password
- mysql_root_password
environment:
- MYSQL_USER_FILE=/run/secrets/mysql_user
- MYSQL_DATABASE_FILE=/run/secrets/mysql_database
- MYSQL_PASSWORD_FILE=/run/secrets/mysql_db_password
- MYSQL_ROOT_PASSWORD_FILE=/run/secrets/mysql_root_password
command: ["--wait_timeout=28800", "--interactive_timeout=28800", "--max_allowed_packet=256M", "--transaction-isolation=READ-COMMITTED", "--binlog-format=ROW"]
networks:
- inet
healthcheck:
test: ['CMD', '/usr/local/bin/healthcheck.sh', '--innodb_initialized']
start_period: 5s
timeout: 5s
interval: 5s
retries: 5
caddy:
image: rajaseg/caddy
restart: unless-stopped
container_name: caddy
ports:
- target: 80
published: 80
mode: host
- target: 443
published: 443
mode: host
- target: 443
published: 443
mode: host
protocol: udp
- target: 2019
published: 2019
mode: host
networks:
- caddy
- inet
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- ./caddydata:/data
- ./caddyconfig:/config
- ./caddylogs:/var/log/caddy
- ./mariadata:/var/lib/mysql
secrets:
mysql_user:
file: ./mysql_user.txt
mysql_database:
file: ./mysql_database.txt
mysql_root_password:
file: ./mysql_root_password.txt
mysql_db_password:
file: ./mysql_db_password.txt
volumes:
caddydata:
caddyconfig:
caddylogs:
mariadata:
networks:
caddy:
external: true
inet:
driver: bridge
Let’s discuss a few configuration options utilized above:
depends_on: Expresses startup and shutdown dependencies between services. In this scenario,caddyis guaranteed to start beforemaria. Compose waits for dependency services to be ready before starting the dependent service.restart_policy: Configures how containers should behave when they crash or the host reboots.unless-stoppedensures the database always comes back online automatically.
Deploy the Docker Compose Stack
Deploy the stack using the following command:
docker compose up -d
Check the status of the running containers using:
docker ps
Create and Manage Databases
Type docker ps on your server to view the running containers. The output should look similar to the image below.

Note down the CONTAINER ID of the MariaDB container from the output.
Log into the container’s interactive shell using that ID:
docker exec -it <CONTAINER_ID> bash
Once inside, log into the MariaDB admin console:
mariadb -u root -p
Enter the root password you created via the .txt file earlier.
Type SHOW DATABASES; to see all the databases in the server. By default, it will have created the database specified in your mysql_database.txt file (e.g., testdb).
You can manually create new databases for future applications:
CREATE DATABASE app_database_name;
And delete them if necessary:
DROP DATABASE app_database_name;
Watch the video below for a walkthrough of deploying MariaDB in a Docker Swarm Cluster.
I hope you enjoyed this post! Please share your thoughts or feedback in the comments below.
Stay tuned for more application deployments! 🙂
Continue reading

How to Deploy MariaDB 11.0.2 in Docker Swarm Behind Traefik v2.0
MariaDB turns data into structured information in a wide array of applications. Learn how to deploy this enhanced, drop-in replacement for MySQL in a Docker Swarm cluster.

How to Deploy Metabase 0.46.5 in Docker Swarm Behind Caddy v2.6.4
Metabase is the easy, open-source way for everyone in your company to ask questions and learn from data without knowing SQL. Learn how to deploy it in a Docker Swarm cluster.

How to Deploy MongoDB 4.4.22 in Docker Swarm Behind Traefik v2.0
MongoDB is a highly scalable NoSQL database program that uses JSON-like documents. Learn how to deploy it as a highly available service in Docker Swarm.