SYSTEM INFORMATION | |
---|---|
OS type and version | Linux Ubuntu 24.04 |
Webmin version | 2.202 |
Virtualmin version | 7.30.4 |
Webserver version | Hetzner Dedicated |
Good evening everyone.
As a first article and to contribute to the community, I share the article I uploaded on my personal website nicolaslagios.
After several failed attempts to dockerize virtualmin , finally the solution was to dockerize database and files and at the same time have the UI for dns and emails and everything else virtualmin gives.
Here is the article with the step by step instructions:
So, you want to dockerize Virtualmin? Stop right there! Trying to shove the entire Virtualmin system into a Docker container is a surefire way to fail. Instead, let’s do something smarter—dockerize only the databases. This approach offers a bulletproof setup with isolated database instances, automatic Virtualmin backups, and a disaster recovery plan that actually works.
In this guide, we’ll show you how to run each database in its own MariaDB instance, reducing the risk of total database failure in case of InnoDB corruption or cyberattacks. Bonus: You’ll still have Virtualmin’s UI to manage DNS, email, and everything else.
Why Combine Docker with Virtualmin?
Because, my dear reader, you get the best of both worlds:
- Isolated databases: Each database runs in its own container with its own MariaDB instance.
- Scalability: Easily move containers between servers.
- Security: If one database is hacked, it doesn’t affect others.
- Virtualmin UI stays intact: Clients can still manage their hosting environment while databases live inside Docker.
Step 1: Install Docker, Docker-Compose, and Portainer
First things first, install the required software:
apt update && apt install -y docker.io docker-compose
Then, deploy Portainer for a user-friendly container management experience:
docker run -d -p 9000:9000 --name=portainer --restart=unless-stopped -v /var/run/docker.sock:/var/run/docker.sock portainer/portainer-ce
Access Portainer via http://yourdomain:9000 to easily manage your containers.
Step 2: Prepare the Virtualmin Server for Docker
Navigate to your Virtualmin server’s home directory and create a Docker workspace:
cd /home/SERVER_NAME
mkdir docker && cd docker
mkdir mysql database_backups
Step 3: Create a Docker Compose File
Inside the docker folder, create a docker-compose.yml file:
version: '3.8'
services:
mariadb:
build: .
container_name: SERVER_NAME-db
environment:
MYSQL_ROOT_PASSWORD: "YOUR_ROOT_PASSWORD"
MYSQL_DATABASE: "YOUR_DATABASE_NAME"
MYSQL_USER: "YOUR_DATABASE_USER"
MYSQL_PASSWORD: "YOUR_DATABASE_PASSWORD"
volumes:
- /home/SERVER_NAME/docker/mysql:/var/lib/mysql
restart: unless-stopped
networks:
- SERVER_NAME-db_network
networks:
SERVER_NAME-db_network:
driver: bridge
Step 4: Create a Dockerfile
Inside the docker folder, create a Dockerfile:
FROM mariadb:latest
COPY my.cnf /etc/mysql/mariadb.conf.d/50-server.cnf
Step 5: Configure MariaDB
Create a my.cnf file inside the docker folder:
[client]
default-character-set = utf8mb4
[mysqld]
user = mysql
bind-address = 0.0.0.0
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
max_allowed_packet = 64M
innodb_buffer_pool_size = 2G
innodb_log_file_size = 512M
tmp_table_size = 256M
max_heap_table_size = 256M
table_open_cache = 8000
log_error = /var/log/mysql/error.log
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow-queries.log
long_query_time = 2
Step 6: Deploy the MariaDB Container
Navigate to your Docker directory and launch the container:
cd /home/SERVER_NAME/docker
docker-compose -f docker-compose.yml -p SERVER_NAME-db up -d
Step 7: Connect Your Application to the Dockerized Database
Get the container’s IP by checking Portainer or running:
docker inspect SERVER_NAME-db | grep "IPAddress"
Edit your WordPress wp-config.php or application database config to use the container’s IP:
define('DB_HOST', '172.XX.XX.XX:3306');
Step 8 (Optional): Set Up Automatic Backups
To ensure your database is safe, use Virtualmin’s built-in backup system:
- Visit: YOUR_DOMAIN:10000/virtual-server/list_sched.cgi?xnavigation=1
- Schedule backups to a remote storage.
For an additional backup solution, create a database export script:
nano /home/SERVER_NAME/docker/export_db.sh
Paste the following script:
#!/bin/bash
set -e
BASE_DIR="/home/SERVER_NAME/docker"
BACKUP_DIR="$BASE_DIR/database_backups"
DATE=$(date +"%Y-%m-%d_%H-%M-%S")
RETENTION_DAYS=30
LOG_FILE="$BASE_DIR/cron_log.txt"
mkdir -p "$BACKUP_DIR"
BACKUP_FILE="$BACKUP_DIR/db_backup_$DATE.sql"
CONTAINER_NAME=$(grep -E '^\s*container_name:' "$BASE_DIR/docker-compose.yml" | awk -F': ' '{print $2}' | xargs)
DB_NAME=$(grep -E '^\s*MYSQL_DATABASE:' "$BASE_DIR/docker-compose.yml" | awk -F': ' '{print $2}' | xargs)
DB_USER=$(grep -E '^\s*MYSQL_USER:' "$BASE_DIR/docker-compose.yml" | awk -F': ' '{print $2}' | xargs)
DB_PASSWORD=$(grep -E '^\s*MYSQL_PASSWORD:' "$BASE_DIR/docker-compose.yml" | awk -F': ' '{print $2}' | xargs)
cd "$BASE_DIR" || exit 1
docker exec "$CONTAINER_NAME" mariadb-dump -u "$DB_USER" -p"$DB_PASSWORD" "$DB_NAME" > "$BACKUP_FILE"
tar -czf "$BACKUP_FILE.tar.gz" -C "$BACKUP_DIR" "$(basename "$BACKUP_FILE")"
rm "$BACKUP_FILE"
find "$BACKUP_DIR" -type f -name "*.tar.gz" -mtime +$RETENTION_DAYS -delete
echo "Backup completed: $BACKUP_FILE.tar.gz" >> "$LOG_FILE"
Make it executable:
chmod +x /home/SERVER_NAME/docker/export_db.sh
To automate daily backups, create a cron job in Virtualmin:
- Go to YOUR_DOMAIN:10000/cron/?xnavigation=1
- Add this command:
/home/SERVER_NAME/docker/export_db.sh >> /home/SERVER_NAME/docker/db_backup_log.txt 2>&1
Extra Tip: Want phpMyAdmin?
Download phpMyAdmin, unzip it in your website directory, and modify config.inc.php to set the container’s IP as the database host.
Congratulations, you’ve successfully dockerized Virtualmin’s databases while keeping the UI intact! This setup enhances security, performance, and scalability while ensuring that every database runs in an isolated container. Now, go enjoy your fully dockerized Virtualmin experience!