PostgreSQL, kurumsal düzeyde güvenilirliği ve zengin özellikleriyle dünya genelinde en çok tercih edilen açık kaynaklı ilişkisel veritabanı yönetim sistemlerinden biri. Basit bir web uygulamasının backend’inden petabayt ölçekli veri ambarlarına kadar her senaryoda karşınıza çıkabilir. Ancak “kuralım, çalışsın” mantığıyla yapılan kurulumlar, ileride performans sorunları, güvenlik açıkları ve yönetilebilirlik kabuslarına dönüşebilir. Bu yazıda PostgreSQL’i sıfırdan doğru şekilde kurup yapılandırmayı, gerçek dünya senaryolarından örneklerle ele alacağız.
Kurulum Öncesi Hazırlık
Sunucunuza PostgreSQL kurmadan önce birkaç şeyi netleştirmeniz gerekiyor. Hangi sürümü kullanacaksınız? Depolama planınız ne? Kaç bağlantı bekliyorsunuz?
PostgreSQL sürüm politikasını bilmek önemli. Her yıl yeni bir major sürüm çıkıyor ve her sürüm beş yıl boyunca destekleniyor. Üretim ortamı için en güncel stable sürümü veya bir önceki LTS niteliğindeki sürümü tercih edin. Dağıtım reposundaki sürüm çoğu zaman geride kalıyor, bu yüzden PostgreSQL’in resmi PGDG (PostgreSQL Global Development Group) deposunu kullanmak çok daha iyi bir karar.
Disk planlaması açısından şunu söyleyelim: PostgreSQL veri dizini (/var/lib/postgresql veya /var/lib/pgsql), WAL (Write-Ahead Log) dosyaları ve backup alanı için ayrı disk bölümleri kullanmak ciddi performans ve kurtarma avantajı sağlar. Küçük bir proje için bu şart olmayabilir ama orta-büyük ölçekte kesinlikle düşünün.
Ubuntu/Debian Üzerine Kurulum
PGDG deposunu ekleyerek başlayalım. Sistem reposundaki sürümü kullanmak yerine her zaman resmi depoyu tercih edin.
# Gerekli bağımlılıkları yükle
sudo apt install -y curl ca-certificates
# PGDG imzalama anahtarını ekle
sudo install -d /usr/share/postgresql-common/pgdg
sudo curl -o /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc
--fail https://www.postgresql.org/media/keys/ACCC4CF8.asc
# Depoyu sources.list.d'ye ekle
sudo sh -c 'echo "deb [signed-by=/usr/share/postgresql-common/pgdg/apt.postgresql.org.asc]
https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main"
> /etc/apt/sources.list.d/pgdg.list'
# Paketi güncelle ve PostgreSQL 16 kur
sudo apt update
sudo apt install -y postgresql-16 postgresql-client-16 postgresql-contrib-16
Kurulum tamamlandıktan sonra servis otomatik başlar. Kontrol edelim:
sudo systemctl status postgresql
sudo systemctl enable postgresql # Sistem açılışında otomatik başlat
# PostgreSQL versiyonunu doğrula
psql --version
sudo -u postgres psql -c "SELECT version();"
RHEL/CentOS/AlmaLinux Üzerine Kurulum
Red Hat tabanlı sistemlerde de yine PGDG reposunu kullanıyoruz. Bu sistemlerde gelen PostgreSQL paketi genellikle çok eski sürüm içeriyor.
# PGDG repo RPM'ini kur (PostgreSQL 16 için)
sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/pgdg-redhat-repo-latest.noarch.rpm
# Sistem PostgreSQL modülünü devre dışı bırak
sudo dnf -qy module disable postgresql
# PostgreSQL 16'yı kur
sudo dnf install -y postgresql16-server postgresql16-contrib
# Veritabanını ilklendir (initdb)
sudo /usr/pgsql-16/bin/postgresql-16-setup initdb
# Servisi başlat ve etkinleştir
sudo systemctl enable --now postgresql-16
RHEL tabanlı sistemlerde initdb adımı kritik. Ubuntu/Debian’da kurulum sırasında otomatik yapılır ama RHEL’de elle çalıştırmanız gerekiyor.
İlk Güvenlik Adımları
PostgreSQL kurulumu tamamlandıktan sonra yapmanız gereken ilk şey postgres superuser hesabının şifresini belirlemek. Varsayılan olarak bu hesap şifresiz gelir ve sadece Unix socket üzerinden erişilebilir durumdadır.
# postgres kullanıcısına geç
sudo -u postgres psql
-- PostgreSQL prompt'unda superuser şifresi belirle
ALTER USER postgres WITH PASSWORD 'G3rcekten_Guclu_Bir_Sifre!';
-- Çıkış
q
Şimdi pg_hba.conf dosyasını yapılandıralım. Bu dosya PostgreSQL’in erişim kontrol listesidir ve yanlış yapılandırıldığında ya kimse bağlanamaz ya da herkes bağlanabilir.
# pg_hba.conf konumunu bul
sudo -u postgres psql -c "SHOW hba_file;"
# Dosyayı düzenle
sudo nano /etc/postgresql/16/main/pg_hba.conf
Tipik bir üretim pg_hba.conf yapılandırması şöyle görünmeli:
# Yerel Unix socket bağlantıları - peer kimlik doğrulama
local all postgres peer
local all all peer
# IPv4 yerel bağlantılar
host all all 127.0.0.1/32 scram-sha-256
# Uygulama sunucusundan gelen bağlantılar (örnek IP bloğu)
host myapp_db myapp_user 10.0.1.0/24 scram-sha-256
# Uzak bağlantıları varsayılan olarak reddet
host all all 0.0.0.0/0 reject
scram-sha-256: Modern ve güvenli kimlik doğrulama yöntemi, MD5 yerine bunu kullanın. peer: Unix kullanıcı adı ile PostgreSQL kullanıcı adını eşleştirir, yerel servisler için idealdir. md5: Eski yöntem, yeni kurulumda kullanmayın. trust: Şifresiz erişim, sadece geliştirme ortamında ve çok dikkatli kullanın.
postgresql.conf ile Temel Performans Ayarları
Varsayılan postgresql.conf son derece muhafazakar ayarlarla gelir. 1990’lardaki sunucu donanımlarını baz alan bu değerleri modern donanıma göre güncellemek şart. Yapılandırma dosyasını açalım:
sudo nano /etc/postgresql/16/main/postgresql.conf
Kritik parametreleri açıklayarak ele alalım:
listen_addresses: Varsayılan olarak sadece localhost’u dinler. Uzak bağlantı gerekiyorsa değiştirin. max_connections: Toplam izin verilen bağlantı sayısı. Her bağlantı yaklaşık 5-10 MB RAM kullanır. shared_buffers: PostgreSQL’in veri önbelleği için kullandığı RAM miktarı. Genellikle toplam RAM’in %25’i önerilen başlangıç noktasıdır. effective_cache_size: Query planner’ın OS cache dahil ne kadar bellek mevcut olduğunu tahmin etmesi için kullanır. Toplam RAM’in %75’i iyi bir değerdir. work_mem: Sıralama ve hash işlemleri için her operasyon başına ayrılan bellek. Dikkatli olun, bu değer bağlantı sayısıyla çarpılır. maintenance_work_mem: VACUUM, CREATE INDEX gibi bakım işlemleri için bellek. Yüksek tutmak bu işlemleri hızlandırır. wal_buffers: WAL yazma tampon boyutu, shared_buffers‘ın %3’ü genellikle yeterli. checkpoint_completion_target: Checkpoint sürecini ne kadar süreye yayacağı. 0.9 değeri I/O spike’larını azaltır. random_page_cost: SSD kullanıyorsanız bunu 1.1 veya 1.5 yapın, HDD için 4.0 varsayılan uygundur.
8 GB RAM’li bir uygulama sunucusu için örnek bir yapılandırma bloğu:
# Bağlantı ayarları
listen_addresses = 'localhost'
max_connections = 100
# Bellek ayarları
shared_buffers = 2GB
effective_cache_size = 6GB
work_mem = 20MB
maintenance_work_mem = 512MB
# WAL ve checkpoint ayarları
wal_buffers = 64MB
checkpoint_completion_target = 0.9
wal_level = replica
max_wal_size = 2GB
min_wal_size = 512MB
# Query planner
random_page_cost = 1.1 # SSD için
effective_io_concurrency = 200 # SSD için
# Loglama
log_min_duration_statement = 1000 # 1 saniyeden uzun sorguları logla
log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h '
log_checkpoints = on
log_connections = on
log_disconnections = on
log_lock_waits = on
Değişiklikleri uygulamak için servisi yeniden başlatın:
sudo systemctl restart postgresql
# Bazı parametreler reload ile de uygulanabilir (kesinti olmadan)
sudo systemctl reload postgresql
# veya
sudo -u postgres psql -c "SELECT pg_reload_conf();"
Veritabanı ve Kullanıcı Oluşturma
Üretimde her uygulama kendi veritabanına ve minimum yetki prensibine göre yapılandırılmış kullanıcısına sahip olmalı. Superuser ile uygulama bağlantısı yapmak büyük bir güvenlik riski.
sudo -u postgres psql << 'EOF'
-- Uygulama kullanıcısı oluştur
CREATE USER myapp_user WITH
PASSWORD 'Uygulama_Sifresi_Buraya'
NOSUPERUSER
NOCREATEDB
NOCREATEROLE
CONNECTION LIMIT 50;
-- Veritabanını oluştur ve sahipliğini ver
CREATE DATABASE myapp_db
OWNER myapp_user
ENCODING 'UTF8'
LC_COLLATE 'tr_TR.UTF-8'
LC_CTYPE 'tr_TR.UTF-8'
TEMPLATE template0;
-- Yetkilendirme
GRANT CONNECT ON DATABASE myapp_db TO myapp_user;
-- myapp_db'ye geç ve schema yetkilerini ver
c myapp_db
GRANT USAGE ON SCHEMA public TO myapp_user;
GRANT CREATE ON SCHEMA public TO myapp_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO myapp_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT USAGE, SELECT ON SEQUENCES TO myapp_user;
EOF
Bağlantıyı test edelim:
# Yerel Unix socket üzerinden test
psql -U myapp_user -d myapp_db -c "conninfo"
# TCP üzerinden test
psql -h 127.0.0.1 -U myapp_user -d myapp_db -c "SELECT current_user, current_database();"
Locale ve Encoding Dikkat Noktaları
Türkçe karakter sorunları genellikle veritabanı oluşturulurken yanlış locale seçilmesinden kaynaklanır. Yukarıdaki örnekte tr_TR.UTF-8 kullandık ama sunucunuzda bu locale’in mevcut olduğundan emin olun:
# Mevcut locale'leri listele
locale -a | grep tr
# tr_TR.UTF-8 yoksa oluştur
sudo locale-gen tr_TR.UTF-8
sudo update-locale
# PostgreSQL tarafında kontrol
sudo -u postgres psql -c "SELECT datname, datcollate, datctype FROM pg_database;"
Eğer İngilizce locale’li bir sunucu kuruyorsanız ve Türkçe karakter sorunuyla karşılaşmak istemiyorsanız en azından en_US.UTF-8 kullanın. SQL_ASCII encoding’den kaçının, bu encoding gerçek bir encoding değil, sadece validasyon devre dışı bırakma mekanizması.
Otomatik VACUUM Yapılandırması
PostgreSQL’in MVCC mimarisi gereği silinen veya güncellenen satırlar fiziksel olarak diskten hemen kaldırılmaz, “dead tuple” olarak kalır. VACUUM bu artıkları temizler ve tablonun şişmesini önler. Varsayılan autovacuum ayarları küçük veritabanları için yeterli olsa da yoğun yazma trafiği olan sistemlerde ayarlama gerekir.
# postgresql.conf'a eklenecek autovacuum ayarları
autovacuum = on
autovacuum_max_workers = 4
autovacuum_naptime = 30s
autovacuum_vacuum_threshold = 50
autovacuum_analyze_threshold = 50
autovacuum_vacuum_scale_factor = 0.02
autovacuum_analyze_scale_factor = 0.01
autovacuum_vacuum_cost_delay = 2ms
Kritik bir tablo için tablo bazlı özel autovacuum ayarı yapabilirsiniz:
sudo -u postgres psql -d myapp_db << 'EOF'
-- Çok sık güncellenen orders tablosu için agresif vacuum ayarı
ALTER TABLE orders SET (
autovacuum_vacuum_scale_factor = 0.01,
autovacuum_analyze_scale_factor = 0.005,
autovacuum_vacuum_cost_delay = 1
);
EOF
Basit Backup Stratejisi Kurma
Herhangi bir üretim veritabanı kurulumunu backup olmadan tamamlandı saymayın. pg_dump ve pg_basebackup ile temel backup altyapısını kuralım:
# Backup dizini oluştur
sudo mkdir -p /backup/postgresql/daily
sudo chown postgres:postgres /backup/postgresql/daily
# Günlük backup scripti oluştur
sudo -u postgres tee /usr/local/bin/pg_daily_backup.sh << 'SCRIPT'
#!/bin/bash
BACKUP_DIR="/backup/postgresql/daily"
DATE=$(date +%Y%m%d_%H%M%S)
RETENTION_DAYS=7
LOG_FILE="/var/log/pg_backup.log"
echo "[$(date)] Backup başlıyor..." >> $LOG_FILE
# Tüm veritabanlarını tek tek yedekle
for DB in $(psql -t -c "SELECT datname FROM pg_database WHERE datistemplate = false AND datname != 'postgres';"); do
DB=$(echo $DB | tr -d ' ')
BACKUP_FILE="${BACKUP_DIR}/${DB}_${DATE}.sql.gz"
pg_dump -Fc "$DB" | gzip > "$BACKUP_FILE"
if [ $? -eq 0 ]; then
echo "[$(date)] $DB backup başarılı: $BACKUP_FILE" >> $LOG_FILE
else
echo "[$(date)] HATA: $DB backup başarısız!" >> $LOG_FILE
fi
done
# Eski backupları temizle
find $BACKUP_DIR -name "*.sql.gz" -mtime +$RETENTION_DAYS -delete
echo "[$(date)] $RETENTION_DAYS günden eski backuplar temizlendi" >> $LOG_FILE
SCRIPT
chmod +x /usr/local/bin/pg_daily_backup.sh
# Crontab'a ekle (her gece 02:00'de)
echo "0 2 * * * postgres /usr/local/bin/pg_daily_backup.sh" | sudo tee /etc/cron.d/pg-backup
Backup’ı test etmek ve restore prosedürünü doğrulamak şart:
# Custom format backup al
sudo -u postgres pg_dump -Fc myapp_db > /backup/myapp_db_test.dump
# Restore test et (önce test veritabanı oluştur)
sudo -u postgres createdb myapp_db_restore_test
sudo -u postgres pg_restore -d myapp_db_restore_test /backup/myapp_db_test.dump
sudo -u postgres psql -d myapp_db_restore_test -c "dt"
sudo -u postgres dropdb myapp_db_restore_test
Temel İzleme Sorguları
Kurulum sonrasında sağlığı takip etmek için işe yarar birkaç sorgu:
sudo -u postgres psql << 'EOF'
-- Aktif bağlantıları gör
SELECT pid, usename, application_name, client_addr, state,
now() - pg_stat_activity.query_start AS duration, query
FROM pg_stat_activity
WHERE state != 'idle'
ORDER BY duration DESC;
-- Veritabanı boyutlarını gör
SELECT datname,
pg_size_pretty(pg_database_size(datname)) AS size
FROM pg_database
ORDER BY pg_database_size(datname) DESC;
-- En büyük tabloları bul
SELECT schemaname, tablename,
pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) AS total_size,
pg_size_pretty(pg_relation_size(schemaname||'.'||tablename)) AS table_size
FROM pg_tables
WHERE schemaname NOT IN ('pg_catalog', 'information_schema')
ORDER BY pg_total_relation_size(schemaname||'.'||tablename) DESC
LIMIT 10;
-- Cache hit oranını kontrol et (>%95 olmalı)
SELECT sum(heap_blks_hit) / (sum(heap_blks_hit) + sum(heap_blks_read)) AS cache_hit_ratio
FROM pg_statio_user_tables;
EOF
Cache hit oranı %95’in altındaysa shared_buffers değerini artırmayı düşünün.
Güvenlik Duvarı Yapılandırması
PostgreSQL varsayılan olarak 5432 portunu kullanır. Güvenlik duvarında bu portu sadece ihtiyaç duyan IP adreslerine açın:
# UFW (Ubuntu) ile
sudo ufw allow from 10.0.1.0/24 to any port 5432
sudo ufw deny 5432
# firewalld (RHEL) ile
sudo firewall-cmd --zone=public --add-rich-rule='rule family="ipv4" source address="10.0.1.0/24" port port="5432" protocol="tcp" accept' --permanent
sudo firewall-cmd --reload
İnternet üzerinden PostgreSQL portuna doğrudan erişim vermekten kaçının. Uzak yönetim için SSH tüneli kullanın:
# SSH tüneli ile güvenli bağlantı
ssh -L 5433:localhost:5432 kullanici@sunucu_ip
# Artık yerel makinenizden localhost:5433 üzerinden bağlanabilirsiniz
psql -h localhost -p 5433 -U myapp_user -d myapp_db
SSL/TLS Yapılandırması
Ağ üzerinden giden PostgreSQL trafiğini şifrelemek üretimde zorunlu kabul edilmeli. PostgreSQL kurulumu sırasında genellikle self-signed sertifika otomatik oluşturulur ama üretim için geçerli bir sertifika kullanın.
# postgresql.conf'ta SSL'i etkinleştir
sudo sed -i "s/#ssl = off/ssl = on/" /etc/postgresql/16/main/postgresql.conf
sudo sed -i "s/#ssl_cert_file/ssl_cert_file/" /etc/postgresql/16/main/postgresql.conf
# pg_hba.conf'ta SSL'i zorunlu kıl (hostssl kullan)
# host yerine hostssl kullanımı SSL bağlantısını zorunlu yapar
Sonuç
PostgreSQL kurulumu ilk bakışta birkaç komutluk iş gibi görünse de sağlam bir altyapı kurmak için dikkat edilmesi gereken onlarca nokta var. Özetlemek gerekirse: her zaman resmi PGDG deposunu kullanın, pg_hba.conf‘u minimum yetki prensibine göre yapılandırın, donanımınıza uygun bellek parametrelerini ayarlayın, scram-sha-256 kimlik doğrulamayı kullanın, autovacuum’u ihmal etmeyin ve backup stratejinizi ilk günden kurun.
Gerçek dünyada en sık karşılaştığım sorunların büyük çoğunluğu ya yanlış pg_hba.conf yapılandırmasından ya da varsayılan bellek ayarlarıyla bırakılmış veritabanlarından kaynaklanıyor. Bu yazıdaki adımları takip ederek kurduğunuz PostgreSQL, hem güvenli hem de performanslı bir başlangıç noktasına sahip olacak.
Sonraki adım olarak replication yapılandırması, connection pooling için PgBouncer kurulumu ve daha detaylı performans tuning konularına bakabilirsiniz. Sorularınız olursa yorumlarda buluşalım.