Admin panelleri + Prometheus exporters + günlük otomatik backup + Google Drive sync + least-privilege user setup
⭐ Beğendiyseniz yıldız bırakın — bu tip self-hosted stack'ler nadir.
Geliştiriciler için "bir tek-makine veritabanı sunucusu" kurmanın zor tarafı 5 farklı container, admin panelleri, backup ve user-permission mantığını uyumlu kurmak. Bu repo:
- 5 popüler DB'yi (MariaDB · PostgreSQL · MongoDB · Redis · MSSQL) tek
docker compose upile çalıştırır - Her birine web UI (phpMyAdmin / pgAdmin / Mongo Express / RedisInsight + Adminer; MSSQL Adminer'dan yönetilir)
- 4 SQL/NoSQL DB'nin Prometheus exporter'ı kurulu, scrape edilmeye hazır (MSSQL exporter'ı yok)
- Günde bir tam backup (5 DB) + 7 gün retention
- Google Drive'a rclone ile sync (offsite backup)
- Least-privilege app user (DROP DATABASE yasak, DELETE serbest)
- Tek nginx dashboard ile her şey tek pencerede
⚠️ Bu bir "production database cluster" değil. Single-machine, single-replica, dev/staging veya küçük production için. HA/multi-region için Patroni, CloudNativePG, Aurora vb. kullanın.
| Servis | Port | Image | Açıklama |
|---|---|---|---|
| mariadb | 3306 | mariadb:11.4 |
slow query log açık, 3G buffer pool, 1000 max_connections (ayarlar mariadb/config/my.cnf) |
| postgresql | 5432 | postgres:15 |
tuned (shared_buffers=256M, max_connections=200) |
| mongodb | 27017 | mongo:4.4 |
auth açık, 1GB WiredTiger cache |
| redis | 6379 | redis:8-alpine |
requirepass, AOF, allkeys-lru, maxmemory=384mb |
| mssql | 1433 | mcr.microsoft.com/mssql/server:2022 |
SQL Server 2022 Developer; admin kullanıcı sa (root değil), yönetim Adminer'dan |
| phpmyadmin | 8081 | phpmyadmin:latest |
MariaDB UI |
| pgadmin | 8082 | dpage/pgadmin4:latest |
PostgreSQL UI |
| mongo-express | 8083 | mongo-express:latest |
MongoDB UI |
| redis-insight | 8084 | redis/redisinsight:latest |
Redis UI |
| adminer | 8085 | adminer:latest |
Universal DB UI (MSSQL dahil — pdo_dblib) |
| nginx-dashboard | 80 | nginx:alpine |
Tüm panellere link landing page |
| mysql-exporter | 9104 | prom/mysqld-exporter:latest |
Prometheus metric'i |
| postgres-exporter | 9187 | prometheuscommunity/postgres-exporter |
Prometheus metric'i |
| mongodb-exporter | 9216 | percona/mongodb_exporter:0.40 |
Prometheus metric'i |
| redis-exporter | 9121 | oliver006/redis_exporter:latest |
Prometheus metric'i |
🪄 Cassandra opsiyonel olarak
cassandra/altında ayrı compose'da. Ana 5 DB'ye dahil değil.
git clone https://github.com/halilibrahimd27/databases-stack.git
cd databases-stackcp .env.example .env
# Güçlü bir parola üret
echo "DB_PASSWORD=$(openssl rand -base64 32 | tr -d '+/=')" >> .env
# .env'i editörde aç ve kalan zorunlu alanları doldurdocker compose up -d
docker compose pscurl http://localhost/health # nginx dashboard
docker compose logs --tail=30 mariadbDB_ROOT_PASSWORD="$(grep DB_PASSWORD .env | cut -d= -f2)" \
APP_PASSWORD="$(openssl rand -base64 24)" \
./setup_db_users.sh allchmod +x backup.sh
crontab crontab # crontab dosyasını cron'a yükle (günlük 02:00 tam yedek)# rclone'u kur ve gdrive remote'unu yapılandır
curl https://rclone.org/install.sh | sudo bash
rclone config
# → New remote → name: gdrive → Storage: drive → ...
# Test
./sync_remote.sh test
./sync_remote.sh # ilk sync| URL | Servis | Auth |
|---|---|---|
http://<HOST> |
Nginx Dashboard (landing) | nginx basic auth (root / ${DB_PASSWORD}) |
http://<HOST>:8081 |
phpMyAdmin | MariaDB user (root / ${DB_PASSWORD}) |
http://<HOST>:8082 |
pgAdmin | admin@admin.com / ${DB_PASSWORD} |
http://<HOST>:8083 |
Mongo Express | root / ${DB_PASSWORD} |
http://<HOST>:8084 |
RedisInsight | UI'da connection ekle |
http://<HOST>:8085 |
Adminer | DB tipi seç + creds |
http://<HOST>:8085/?mssql=mssql&username=sa |
MSSQL (Adminer üzerinden) | sa / ${DB_PASSWORD} |
MSSQL'in ayrı web paneli yoktur — Adminer'dan (
pdo_dblib) veya harici bir istemciden (SSMS / Azure Data Studio)<HOST>:1433, kullanıcısaile bağlanın. MSSQL'in yerleşik admin'isa'dır (diğerlerindekiroot'un karşılığı; yeniden adlandırılamaz).
⚠️ Production'da hiçbiri public açmayın. Reverse proxy + VPN/IP whitelist arkasına alın.
backup.sh 1000+ satırlık production-grade script. Özellikler:
- ✅ Lock mekanizması — concurrent run engeller
- ✅ Tüm DB'ler (sadece
defaultdbdeğil) - ✅ Per-DB single backup opsiyonu
- ✅ Backup integrity verification (gzip/tar test)
- ✅ Disk space check (5GB altında abort)
- ✅ Container health check
- ✅ Retention (default 7 gün)
- ✅ Restore komutları her DB için
- ✅ Detaylı log + colored output
./backup.sh all # 5 DB'yi yedekle (MariaDB/PG/Mongo/Redis/MSSQL)
./backup.sh mariadb # sadece MariaDB
./backup.sh mssql # sadece MSSQL (tüm user DB'leri, native .bak)
./backup.sh mariadb-single mydb # tek bir MariaDB DB'si
./backup.sh stats # istatistik raporu
./backup.sh list # son yedekleri listele
./backup.sh clean 7 # 7 günden eski yedekleri sil
./backup.sh restore-postgresql /path/to/backup.sql.gz
./backup.sh restore-mssql /path/to/mssql_full_...tar.gz
⚠️ Neden 15 dakikada bir değil? Yedekler DB container'ının içindedocker exec(mariadb-dump / mongodump) ile alınır; dump'ın bellek tüketimi DB container'ının kendi cgroup'una yazılır. 15 dakikada bir tam yedek almak MariaDB'yi tekrar tekrarCONSTRAINT_MEMCGOOM ile öldürdü (container 172 kez restart etti). Günde bir tam yedek + offsite sync bu baskıyı ortadan kaldırır. Sık, tutarlı anlık kopya gerekiyorsa dump yerine binlog/PITR ya da volume snapshot gibi container dışı bir yöntem tercih edin.
crontab dosyasını yükle:
crontab crontabBu ekler:
- Her gün 02:00 → full backup (tüm DB'ler)
- Her gün 02:30 → Google Drive sync (yedek bittikten sonra)
- Her gün 03:00 →
backup.sh cleanile 7 günden eski local yedekleri sil - Her gün 08:00 → istatistik raporu
sync_remote.sh — rclone ile Google Drive'a otomatik yedek.
./sync_remote.sh test # bağlantı testi
./sync_remote.sh # şimdi sync
./sync_remote.sh status # local + remote stats
./sync_remote.sh cleanup # eski uzak yedekleri silÖnkoşul: GOOGLE_DRIVE_SETUP.md okuyun (rclone kurulum, Google Drive auth).
setup_db_users.sh — uygulamanın bağlanacağı kısıtlı kullanıcı oluşturur
(MariaDB · PostgreSQL · MongoDB · Redis). MSSQL kapsam dışı — gerekiyorsa
kısıtlı bir SQL login'ini elle oluşturun (GRANT/db_datareader/db_datawriter).
| ✅ İzin verilen | ❌ Yasak |
|---|---|
| SELECT, INSERT, UPDATE, DELETE | DROP DATABASE |
| CREATE TABLE, CREATE INDEX | DROP TABLE |
| ALTER TABLE | TRUNCATE |
| Stored procedures, functions | SUPERUSER, GRANT |
DEL (Redis) |
FLUSHALL, FLUSHDB |
APP_PASSWORD='$(openssl rand -base64 24)' ./setup_db_users.sh all
# Sadece tek DB
./setup_db_users.sh mariadb
./setup_db_users.sh remove # kullanıcıyı kaldırExporter'lar zaten kurulu — Prometheus'u stack'in dışında bir yere kurup şu target'ları scrape edin:
# prometheus.yml
scrape_configs:
- job_name: 'mariadb'
static_configs:
- targets: ['<HOST>:9104']
- job_name: 'postgresql'
static_configs:
- targets: ['<HOST>:9187']
- job_name: 'mongodb'
static_configs:
- targets: ['<HOST>:9216']
- job_name: 'redis'
static_configs:
- targets: ['<HOST>:9121']Grafana dashboard ID önerileri:
- ✅ Tüm secret'lar
.envüzerinden,${VAR}interpolasyonu (hardcoded yok) - ✅ Container'lar resource limit'li (memory hard cap)
- ✅ Health check'li (auto-restart kötü state'te)
- ✅ App user least-privilege
⚠️ DB portları (3306/5432/27017/6379) default'ta host'a expose. Production'da:# docker-compose.yml override mariadb: ports: [] # sadece compose network içinden
⚠️ Admin panel'leri auth'lu ama VPN/whitelist olmadan public açmayın⚠️ Nginx dashboard basic-auth kullanır — production'da OAuth proxy/SSO
# 1. Strong password
openssl rand -base64 32 > /tmp/dbpass
sed -i "s/^DB_PASSWORD=.*/DB_PASSWORD=$(cat /tmp/dbpass)/" .env
shred -u /tmp/dbpass
# 2. DB portlarını host'a açma (override.yml ile)
cat > docker-compose.override.yml <<'EOF'
services:
mariadb: { ports: [] }
postgresql: { ports: [] }
mongodb: { ports: [] }
redis: { ports: [] }
EOF
# 3. Reverse proxy + TLS
# Caddy / nginx + Let's Encrypt arkasından dashboard'a açınContainer'ların hard memory limit toplamı (varsayılan .env değerleriyle):
| Servis | Limit |
|---|---|
| MariaDB | 8G |
| PostgreSQL | 1G |
| MongoDB | 2G |
| Redis | 600M |
| MSSQL | 4G |
| Admin panelleri (5) + nginx | ~1.5G |
| Prometheus exporter'ları (4) | ~256M |
| Toplam (tavan) | ~17.5 GB |
Bunlar container başına tavan değerlerdir; sürekli (steady-state) RSS tüketimi
genelde daha düşüktür. Asıl büyük tüketiciler MariaDB'nin 3G innodb_buffer_pool'u,
MSSQL (min ~2G ister) ve MongoDB'nin 1G WiredTiger cache'idir. Tüm limitler .env
üzerinden ayarlanabilir (MSSQL kullanmıyorsanız servisi kaldırıp ~4G geri kazanın).
💽 Dönen disk (RAID/HDD) notu: Linux boştaki RAM'i page cache olarak kullanır ve DB dosyaları buradan okunur. Dönen disk üzerinde çalıştırıyorsanız limit toplamının üstüne page cache için bol boşluk bırakın — pratikte kutunun limitler + page cache + OS ile birlikte ~22-24 GB civarında oturmasını planlayın (rahat bir taban için 32 GB RAM'li host önerilir). Yedekler zaten
nice -n 19 ionice -c3ile düşük I/O önceliğinde çalışır (bkz.backup.sh); böylece yedek dizisi doyduğunda canlı DB trafiği öncelikli kalır.
databases-stack/
├── docker-compose.yml # Ana stack (MariaDB+PG+Mongo+Redis+MSSQL+UIs+exporters)
├── backup.sh # Backup script (5 DB backup + restore)
├── sync_remote.sh # Google Drive sync (rclone)
├── setup_db_users.sh # Least-privilege app user setup (MariaDB/PG/Mongo/Redis)
├── sc.sh # İlk kurulum yardımcısı (opsiyonel)
├── crontab # Cron jobs (günlük backup + sync)
├── .env.example # Ortam değişkenleri şablonu
├── .gitattributes # LF satır sonu zorlaması (CRLF shebang bozmasın)
├── .gitignore
├── GOOGLE_DRIVE_SETUP.md # Rclone setup detayı
├── mariadb/config/my.cnf # Custom MariaDB config
├── nginx/
│ ├── nginx.conf # Reverse proxy + auth
│ └── html/index.html # Dashboard landing
└── cassandra/ # Opsiyonel: Cassandra alt-stack
├── docker-compose.yml
├── backup.sh
├── setup_users.sh
└── ...
docker compose ps
docker compose logs <SERVICE> --tail=50
docker exec <CONTAINER> printenv | grep -i pass.env dosyasında DB_PASSWORD= doldurulmamış. Düzelt + docker compose down && up -d.
Kilit artık flock ile yönetiliyor: kilit yalnızca çalışan sürece bağlıdır ve süreç ölünce çekirdek tarafından otomatik bırakılır — bayat kilit diye bir şey kalmadı. Bu mesajı görüyorsanız gerçekten başka bir çalışma vardır:
pgrep -af 'backup.sh|sync_remote.sh' # gerçekten çalışan var mı?Lock dosyasını (/tmp/db_backup.lock) elle silmeyin — flock ile ne gerekli
ne de güvenlidir (boş dosya bile canlı bir kilidi temsil edebilir).
rclone config reconnect gdrive:
./sync_remote.sh testMongo Express bazen ilk start'ta sorun çıkarır:
docker compose restart mongodb
sleep 30
docker compose restart mongo-expresspgAdmin container'ını ilk açtığında PostgreSQL henüz hazır olmayabilir. Server config'i UI'da elle ekleyin:
- Host:
postgresql - Port:
5432 - Username:
root - Password:
${DB_PASSWORD}
MIT — LICENSE dosyasına bakın.