VeloCMS'i Kendi Sunucunuzda Barındırma
Neden Kendi Sunucunuzda Barındırmalısınız?
Çoğu kişi yönetilen bulut çözümünü tercih ediyor, ki bunda bir sorun yok. Ama verilerinizin nerede duracağı konusunda yasal zorunluluklarınız varsa, GDPR veya HIPAA gibi bir uyumluluk meselesi (ya da şirket içi SOC 2 politikanız) söz konusuysa, büyüdükçe artan maliyetler canınızı sıkıyorsa veya en basitinden 'verim benim sunucumda durmalı' diyorsanız, bu rehberle 30 dakikadan kısa sürede, ayda 6 dolarlık bir VPS üzerinde çalışan bir production ortamı kurabilirsiniz. Kendi sunucunuzda barındırmak demek; şema, depolama, yedekler ve güncelleme döngüsü üzerinde tam kontrol sahibi olmanız demek. Bunun karşılığında operasyonel sorumluluğu üstlenmiş oluyorsunuz. VeloCMS, bu takası gerçekten değerli kılmak için elinden geleni yapıyor.
Sistem Gereksinimleri
VeloCMS göründüğünden çok daha hafif. PocketBase, içine SQLite gömülmüş tek bir Go binary'sinden ibaret ve Next.js container'ı da boşta yaklaşık 150MB RSS kullanıyor. Yani sıradan bir blog kurulumu için öyle ahım şahım bir sunucuya ihtiyacınız yok.
| Profil | Kiracı Sayısı | RAM | Disk | CPU | Notlar |
|---|---|---|---|---|---|
| Küçük blog | 1 | 1 GB | 25 GB | 1 vCPU | Tekil kurulum modu için ideal. |
| SaaS hobi projesi | 50'ye kadar | 2 GB | 50 GB | 1 vCPU | Çoklu kiracı modu, R2 kullanımı şiddetle tavsiye edilir. |
| SaaS production | 50+ | 4 GB+ | 80 GB+ | 2+ vCPU | Yük arttıkça ölçeklenir. R2 kullanımı neredeyse zorunludur. |
Docker Compose ile Hızlı Başlangıç
VeloCMS, iki adet hazır Docker imajıyla geliyor: `velocms/velocms:latest` (Next.js 16 uygulaması) ve `velocms/pocketbase:latest` (VeloCMS şeması önceden yüklenmiş PocketBase 0.36). Çalıştırmak için kaynak koduna ihtiyacınız yok. `public/install/docker-compose.yml` adresindeki Compose şablonu, bu iki servisi mantıklı varsayılan ayarlarla birbirine bağlıyor: paylaşılan volume, dahili DNS ve PocketBase'in hazır olmasını garantileyen sağlık kontrolü sıralaması sayesinde Next.js süreci şema migrasyonuna kalkıştığında her şey yolunda gidiyor.
# 1. Create a working directory
mkdir velocms && cd velocms
# 2. Download the official Compose template + env example
curl -O https://velocms.org/install/docker-compose.yml
curl -O https://velocms.org/install/.env.example
cp .env.example .env
# 3. Edit .env — fill in the required secrets (see Environment Variables table below)
nano .env # or: vim .env / code .env
# 4. Pull images and start in the background
docker compose up -d
# Verify both containers are running and healthy
docker compose psCompose dosyasının tam hali repoda `public/install/docker-compose.yml` altında tutuluyor. 2026'nın 3. çeyrek sürümü itibarıyla standart yapısı şu şekilde:
version: "3.9"
services:
pocketbase:
image: velocms/pocketbase:latest
restart: unless-stopped
volumes:
- pb_data:/pb/pb_data
ports:
- "8090:8090" # Expose only internally in prod; reverse-proxy to 3000
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:8090/api/health"]
interval: 10s
timeout: 5s
retries: 5
velocms:
image: velocms/velocms:latest
restart: unless-stopped
depends_on:
pocketbase:
condition: service_healthy
ports:
- "3000:3000"
env_file: .env
environment:
POCKETBASE_URL: http://pocketbase:8090 # Internal Docker DNS — do not change
volumes:
pb_data:Ortam Değişkenleri Referansı
Tüm yapılandırma ortam değişkenleri üzerinden yapılıyor; herhangi bir ayar dosyası ya da sunucu davranışları için bir arayüz paneli yok. Kurulum paketindeki `.env.example` dosyası bu tablonun birebir aynısı. Zorunlu değişkenler başlangıçta kontrol ediliyor; eksik olanlar uygulamanın net bir hata mesajı verip istekleri sunmayı reddetmesine neden olacaktır.
| Değişken | Zorunlu mu? | Varsayılan | Amacı | Güvenlik Notu |
|---|---|---|---|---|
| `VELOCMS_MODE` | Evet | `single` | `single` veya `multi` modunu ayarlar. | Yok |
| `POCKETBASE_URL` | Evet | `http://pocketbase:8090` | Next.js uygulamasının PocketBase API'sine nasıl ulaşacağını belirler. | Production'da `https` kullanın. |
| `ENCRYPTION_KEY` | Evet | Yok | Kiracı sırlarını (API anahtarları vb.) şifrelemek için kullanılan 32-byte'lık bir anahtar. | Çok hassas. Güvenli bir yerde saklayın, veritabanıyla birlikte yedeklemeyin. |
| `STRIPE_SECRET_KEY` | Hayır | Yok | Stripe entegrasyonu için platformun ana Stripe anahtarı. | Her zaman kısıtlı izinlere sahip bir anahtar kullanın. |
| `R2_ACCOUNT_ID` | Hayır | Yok | Cloudflare R2 medya depolaması için hesap ID'si. | Yok |
| `R2_ACCESS_KEY_ID` | Hayır | Yok | Cloudflare R2 için erişim anahtarı ID'si. | Yok |
| `R2_SECRET_ACCESS_KEY` | Hayır | Yok | Cloudflare R2 için gizli erişim anahtarı. | Hassas. Güvenli bir şekilde yönetin. |
| `R2_BUCKET_NAME` | Hayır | Yok | Medya dosyalarının yükleneceği R2 bucket'ının adı. | Yok |
Tekil Kurulum ve Çoklu Kiracı Modu Karşılaştırması
Bu modlar arasındaki seçim bir özellik seviyesi değil, tamamen bir kurulum topolojisi kararı. Tekil kurulum; kişisel bir blog, bir ajansın müşteri sitesi veya çoklu kiracı karmaşası olmadan temiz bir kurulum isteyen küçük bir işletme için gerçekten biçilmiş kaftan. Çoklu kiracı modu ise VeloCMS üzerine bir SaaS ürünü inşa ettiğiniz durumlar için var. Müşterileriniz kendi izole PocketBase kurulumlarına, kendi subdomain'lerine ve isteğe bağlı olarak BYOK faturalandırmasıyla kendi Stripe hesaplarına sahip olurlar. velocms.org'daki production ortamı çoklu modda çalışıyor.
| Özellik | `VELOCMS_MODE=single` | `VELOCMS_MODE=multi` |
|---|---|---|
| Veritabanı yapısı | Tek bir `pb_data` dizini | Her kiracı için `pb_data/tenants/{tenantId}` |
| Alan adı yönlendirme | Tek bir alan adı (örn: `blog.sirket.com`) | Wildcard subdomain'ler (örn: `*.platformunuz.com`) |
| Kullanıcı kaydı | Kapalı (sadece davetle) | Açık (herkes yeni bir site oluşturabilir) |
| Faturalandırma | Uygulanamaz | Platform düzeyinde Stripe veya kiracı başına BYOK |
Emin değilseniz, tekil kurulumla başlayın. Daha sonra çoklu kiracı moduna geçiş yapabilirsiniz. Şema aynı, temel fark PocketBase dosyalarının nerede durduğu ve middleware'in istekleri nasıl yönlendirdiği.
İlk Yönetici Kullanıcısını Oluşturma
PocketBase'in kendi yönetici arayüzü var; burası veritabanı için alt seviye kontrol paneli gibi düşünebilirsiniz. Bu arayüze ilk girdiğinizde, sizden bir süper kullanıcı oluşturmanız istenecek. İşte bu süper kullanıcı, VeloCMS'e `/login` adresinden giriş yapacağınız kimlik bilgileri olacak. Bu 'süper kullanıcı oluştur' ekranı sadece temiz bir veritabanında bir kez karşınıza çıkar, o yüzden başka bir şey yapmadan önce bu adımı halledin.
# While Docker Compose is running, open the PocketBase admin UI:
open http://localhost:8090/_/
# Create your superuser email + password when prompted.
# Then log into VeloCMS:
open http://localhost:3000/loginEğer bu ilk kurulumu arayüz olmadan (headless) yapmak isterseniz - ki bu CI veya otomatik provizyon süreçlerinde çok işe yarar - PocketBase ilk başlangıçta kimlik bilgilerini ortam değişkenleri aracılığıyla da kabul ediyor. `.env` dosyanızdaki `POCKETBASE_ADMIN_EMAIL` ve `POCKETBASE_ADMIN_PASSWORD` değişkenleri, şema oluşturulurken PB container'ı tarafından okunur. İlk başlatmadan sonra bu değişkenleri değiştirmenin mevcut bir veritabanı üzerinde hiçbir etkisi olmaz; süper kullanıcı yönetimi artık tamamen PB yönetici arayüzünden yapılır.
`/admin` adresinden VeloCMS yönetici paneline giriş yaptıktan sonra, isterseniz demo içerik yükleyicisini çalıştırarak kurulumunuza örnek yazılar, bir tema ve birkaç medya öğesi ekleyebilirsiniz. Böylece sistemi değerlendirirken arayüz tamamen boş görünmez.
# Optional: seed demo content (posts + default tenant + media placeholders)
# Run this from inside the velocms container or from the repo if you have it locally:
node scripts/seed-multi-tenant.mjsÖzel Alan Adı ve TLS Kurulumu
Tekil bir kurulum için, alan adınızın A kaydını sunucu IP'nize yönlendirin ve 443 portundan gelen trafiği 3000'e yönlendirecek bir reverse proxy (nginx veya Caddy) yapılandırın. Caddy en kolay yoldur, Let's Encrypt işini otomatik olarak halleder.
# Caddyfile — put in /etc/caddy/Caddyfile or your Caddy config path
yourdomain.com {
reverse_proxy localhost:3000
}
# Caddy auto-provisions TLS via Let's Encrypt. No certbot needed.
# Reload after editing: systemctl reload caddyÇoklu kiracı modu için ek olarak bir wildcard DNS kaydına ihtiyacınız var. Bu wildcard kaydı sadece DNS (Cloudflare'de gri bulut) olmalı, proxy'lenmemeli. Cloudflare'in proxy'si ücretsiz planda wildcard sertifika sağlamıyor ve eğer Railway üzerinde kurulum yapıyorsanız, her subdomain için TLS sonlandırmasını Railway kendisi hallediyor.
# Add these two records in the Cloudflare DNS dashboard:
#
# Type Name Content Proxy status
# A yourdomain.com <server-IP> Proxied (orange cloud)
# A *.yourdomain.com <server-IP> DNS only (grey cloud)
#
# The apex domain stays proxied (CDN + DDoS protection).
# The wildcard MUST be grey cloud — Railway or your Caddy handles TLS.Yedekleme Stratejisi
PocketBase tüm veriyi disk üzerindeki SQLite dosyalarında saklar. Yedeklemek oldukça basit: PocketBase durdurulmuşken veya PB yedekleme API'si kullanılırken (ki bu bir 'hot checkpoint' tetikler) `pb_data` dizinini kopyalayın. Tavsiye edilen yöntem, her gün `pocketbase backup` komutunu çalıştıran ve sonucu R2'ye aktaran bir cron görevi oluşturmaktır. Bu sayede yedekleriniz ana depolama alanınızdan ayrı yaşar ve bir sunucu çökmesinden etkilenmez.
#!/usr/bin/env bash
# Daily PocketBase backup -> Cloudflare R2
# Add to crontab: 0 3 * * * /opt/velocms/backup-daily.sh
set -euo pipefail
DATE=$(date +%Y-%m-%d)
BACKUP_FILE="velocms-backup-${DATE}.zip"
PB_URL="${POCKETBASE_URL:-http://localhost:8090}"
R2_BUCKET="${R2_BUCKET_NAME:-velocms-backups}"
# Trigger PocketBase hot backup via API (requires superuser auth)
curl -s -X POST -H "Authorization: ${PB_ADMIN_TOKEN}" "${PB_URL}/api/backups" -d "{"name":"${BACKUP_FILE}"}"
# Wait for backup to appear in PB's local backup folder, then stream to R2
# Assumes rclone is configured with the Cloudflare R2 remote named "r2"
rclone copy "${PB_DATA_DIR}/backups/${BACKUP_FILE}" "r2:${R2_BUCKET}/daily/"
echo "[backup] ${BACKUP_FILE} uploaded to R2 at $(date)"
# Prune local backups older than 7 days
find "${PB_DATA_DIR}/backups/" -name "*.zip" -mtime +7 -deleteGeri yükleme ise bu işlemin tersi: zip dosyasını R2'den indirin, `pb_data/backups/` içine koyun ve PB geri yükleme API'sini çağırın. Ayda en az bir kez geri yükleme tatbikatı yapın; hiç test etmediğiniz bir yedek, aslında sahip olmadığınız bir yedektir.
# Download a backup from R2:
rclone copy "r2:velocms-backups/daily/velocms-backup-2026-04-26.zip" ./restore/
# Restore via PocketBase API (while PB is running):
curl -X PUT -H "Authorization: <admin-token>" "${PB_URL}/api/backups/velocms-backup-2026-04-26.zip/restore"
# PocketBase will restart automatically after restore.VeloCMS'i Güncelleme
Güncellemeler iki adımlı bir 'pull' ve yeniden başlatma işlemidir. VeloCMS, PocketBase migrasyonlarını başlangıçta otomatik olarak uygular. Yani, yıkıcı bir şema değişikliği getiren büyük bir sürüme yükseltme yapmadığınız sürece (ki bunlar sürüm notlarında açıkça belirtilen yükseltme öncesi adımlarla belgelenir) migrasyon betiklerini manuel olarak çalıştırmanıza gerek kalmaz.
# 1. Pull the latest images (do this from your velocms working directory)
docker compose pull
# 2. Take a backup before upgrading (see backup strategy above)
./backup-daily.sh
# 3. Restart with the new images — zero-downtime if using a load balancer
docker compose up -d --remove-orphans
# 4. Verify the app is healthy
docker compose ps
curl -s http://localhost:3000/api/health | jq .`latest` etiketini takip etmek yerine belirli bir sürüme sabitlenmek için `docker-compose.yml` dosyanızdaki imaj etiketini değiştirin. Örneğin, `velocms/velocms:1.2.0` ve `velocms/pocketbase:1.2.0`. Production ortamları için sabitlenmiş etiketler tavsiye edilir; bu size güncelleme zamanlamasını kontrol etme ve bir şeyler ters giderse sorunun yeni bir imaj çekmekten kaynaklanmadığından emin olma imkanı tanır.
Sorun Giderme
Başlangıçtaki hataların çoğu ya eksik bir ortam değişkeninden ya da Next.js container'ı ile PocketBase arasındaki ağ erişim sorunundan kaynaklanır. Bakılacak ilk yer Docker loglarıdır (`docker compose logs -f velocms`). VeloCMS, yapısal JSON hatalarını stdout'a yazar, bu yüzden `| jq .` komutu bunları ayrıştırmanıza yardımcı olur.
| Hata | Olası Neden | Çözüm |
|---|---|---|
| `Error: connect ECONNREFUSED` | VeloCMS container'ı PocketBase'e ulaşamıyor. | `POCKETBASE_URL`'nin doğru olduğundan ve `pocketbase` servisinin çalıştığından emin olun. `docker ps` ile kontrol edin. |
| `Missing required environment variable: ENCRYPTION_KEY` | Zorunlu bir ortam değişkeni eksik. | `.env` dosyanızı `.env.example` ile karşılaştırın ve eksik değişkenleri ekleyin. |
| PocketBase loglarında `database is locked` | İki süreç aynı anda SQLite dosyasına yazmaya çalışıyor. | PocketBase'in sadece bir kopyasının çalıştığından emin olun. `docker compose down` ve `up` ile yeniden başlatmayı deneyin. |
| TLS hataları veya `P-014` (Railway) | Wildcard DNS kaydı Cloudflare'de proxy'lenmiş (turuncu bulut). | Wildcard CNAME kaydını 'Sadece DNS' (gri bulut) olarak değiştirin. |
Referans Ekler
Docker İmajları
| İmaj | Etiket | İçerik |
|---|---|---|
| `velocms/velocms` | `latest`, `1.2.0` | Next.js 16 tabanlı VeloCMS ön uç ve yönetici paneli uygulaması. |
| `velocms/pocketbase` | `latest`, `1.2.0` | VeloCMS şeması ve ayarlarıyla önceden yapılandırılmış PocketBase 0.36. |
Donanım Boyutlandırma Hızlı Referansı
| Sağlayıcı | Sunucu Tipi | RAM | Aylık Maliyet (yaklaşık) | Uygun Olduğu Durumlar |
|---|---|---|---|---|
| DigitalOcean | Basic Droplet | 1 GB | $6 | Tekil kurulum, küçük bloglar |
| Hetzner | CPX11 | 2 GB | €5 | Küçük SaaS, 50 kiracıya kadar |
| Vultr | High Frequency | 4 GB | $24 | Büyüyen SaaS, 50+ kiracı |
Docker Container İçindeki Önemli Dosya Yolları
| Yol | Açıklama |
|---|---|
| `/pb_data` | PocketBase'in tüm veritabanı dosyalarını, migrasyonları ve yedekleri içeren ana veri dizini. Bu dizin bir volume olarak bağlanmalıdır. |
| `/pb_data/tenants/{tenantId}` | Çoklu kiracı modunda, her kiracının izole edilmiş kendi `pb_data` dizini. |
| `/app/.next` | VeloCMS (Next.js) uygulamasının derlenmiş dosyaları. |