Shlink ile VPS Üzerinde URL Kısaltıcı Kurulumu
Shlink 5.1 ve Docker Compose ile VPS üzerinde kendi URL kısaltıcınızı kurun. Kısa alan adı DNS ayarları, Postgres, API key, web client, QR kodları ve tıklama istatistikleri.
Oluşturulacak sistem
Kendi sunucunuzda barındırılan bir URL kısaltıcı, uzun bir bağlantıyı size ait kısa bir bağlantıya dönüştüren ve bağlantının her tıklanmasını sayan küçük bir sunucudur. Tercih edilmesi gereken ürün Shlink'tir. Shlink açık kaynaklıdır, Docker image olarak sunulur ve tüm işi bir container ile bir veritabanında gerçekleştirir. Bu kılavuzda Shlink, gerçek bir kısa alan adının arkasında, HTTPS, API key, QR kodları ve tıklama istatistikleriyle birlikte bir VPS üzerine kurulmaktadır.
Ticari bir kısaltıcıdaki kullanım deneyimini iki bileşen sağlar. API server yönlendirmelere yanıt verir ve verileri tutar. Web client, tarayıcıdan bu API ile iletişim kuran ayrı bir statik uygulamadır. Her ikisi de çalıştırılabilir veya yalnızca API çalıştırılarak komut satırından kullanılabilir.
Buradaki sürüm numaraları Temmuz 2026 itibarıyla günceldir: Shlink 5.1 ve shlink-web-client 4.8.
Önce kısa alan adını sunucuya yönlendirin
Alan adı ürünün kendisidir. s.example.com/abc123 kullanıcıların gördüğü bağlantıdır; bu nedenle kısa bir ad seçin ve herhangi bir kurulum yapmadan önce bu adı belirleyin. Shlink, alan adını her kısa URL ile birlikte kaydeder. Daha sonra değiştirirseniz daha önce dağıttığınız tüm bağlantılar çalışmaz.
Kısa alan adı için sunucunuzun genel IPv4 adresine işaret eden bir DNS A kaydı oluşturun. Sunucuda IPv6 varsa bir AAAA kaydı da ekleyin. Ardından devam etmeden önce alan adının çözümlendiğini doğrulayın.
dig +short s.example.com AÇıktı sunucunuzun adresi olmalıdır. Çıktı boşsa kayıt henüz yayılmamıştır. Bu durumda sonraki tüm adımlar anlaşılması zor şekilde başarısız olur; çünkü çözümlenmeyen bir ad için TLS (transport layer security) sertifikası verilemez.
Compose dosyası
Shlink için bir veritabanı gerekir. SQLite test için kullanılabilir, ancak kalıcı olarak kullanılması planlanan kurulumlarda Postgres doğru tercihtir. Bunun nedeni, ziyaret kayıtlarının birikmesi ve Postgres'in dizinleri ve eşzamanlı yazma işlemlerini daha iyi yönetmesidir. Aşağıdakileri /opt/shlink/compose.yaml içine ekleyin.
services:
shlink:
image: shlinkio/shlink:stable
restart: unless-stopped
ports:
- "127.0.0.1:8080:8080"
environment:
DEFAULT_DOMAIN: s.example.com
IS_HTTPS_ENABLED: "true"
DB_DRIVER: postgres
DB_HOST: database
DB_NAME: shlink
DB_USER: shlink
DB_PASSWORD: ${DB_PASSWORD}
depends_on:
- database
database:
image: postgres:17-alpine
restart: unless-stopped
environment:
POSTGRES_DB: shlink
POSTGRES_USER: shlink
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- shlink_db:/var/lib/postgresql/data
web-client:
image: shlinkio/shlink-web-client:stable
restart: unless-stopped
ports:
- "127.0.0.1:8081:8080"
volumes:
shlink_db:Her iki yayımlanan port da 127.0.0.1 adresine bağlanır. Bu nedenle, sonraki bölümde ters proxy kurulana kadar internetten erişim mümkün değildir. Docker, kendi yönlendirme kurallarını ana makinenin güvenlik duvarından önce uygular. Bu nedenle, yalnızca 8080:8080 kullanılması, güvenlik duvarı kapalı görünse bile uygulamayı dışarıya açar. Döngüsel geri besleme adresine bağlanmak bu sorunu önler. Aynı yöntem bu şekilde çalıştırılan tüm uygulamalar için geçerlidir ve VPS üzerinde Docker Compose kılavuzunda daha ayrıntılı olarak açıklanır.
Veritabanı parolası, compose dosyasının yanındaki bir .env dosyasından alınır. Böylece parola YAML dosyasına yazılmaz.
sudo mkdir -p /opt/shlink
printf 'DB_PASSWORD=%s\n' "$(openssl rand -base64 24)" | sudo tee /opt/shlink/.env
sudo chmod 600 /opt/shlink/.envBaşlatın ve API'nin kullanıma hazır olmasını izleyin.
cd /opt/shlink
sudo docker compose up -d
sudo docker compose logs -f shlinkİlk başlatmada veritabanı geçişleri çalıştırılır. Bu nedenle işlem sonraki başlatmalardan daha uzun sürer. İşlem tamamlandığında hizmetin yerel olarak yanıt verdiğini denetleyin.
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080/rest/healthBir 200, API'nin çalıştığını ve veritabanı bağlantısının başarılı olduğunu gösterir. Buradaki 500 neredeyse her zaman veritabanı kaynaklıdır. Bunun nedeni, .env içindeki DB_PASSWORD değerinin Postgres oluşturulurken kullanılan değerle eşleşmemesidir. Postgres imajı POSTGRES_PASSWORD değerini yalnızca boş bir veri dizinini ilk kez başlatırken okur. Parolayı daha sonra düzenlemek, birimi kaldırıp yeniden başlatana kadar etkili olmaz.
HTTPS'i önünde sonlandırma
Shlink, 8080 bağlantı noktasında düz HTTP sunar. TLS işlemi bir ters proxy'de yapılmalıdır. Önemli olan tek ayar, özgün ana bilgisayar adının iletilmesidir. Shlink, kısa kodun hangi etki alanına ait olduğunu Host üst bilgisini okuyarak belirler. Proxy bu üst bilgiyi yeniden yazarsa mevcut bağlantılar için 404 yanıtları döner ve ziyaret istatistikleri yanlış etki alanına bağlanır.
server {
server_name s.example.com;
listen 80;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}Ardından sertifikayı oluşturun. Yenileme zamanlayıcısı da dahil olmak üzere tüm adımlar Ubuntu 24.04 üzerinde nginx için Certbot kılavuzunda açıklanmıştır.
sudo certbot --nginx -d s.example.comCompose dosyasındaki IS_HTTPS_ENABLED: "true", Shlink'in döndürdüğü kısa URL'lerde https:// yazdırmasını sağlar. Tek başına TLS'yi etkinleştirmez. HTTPS proxy'sinin arkasında false olarak bırakılırsa API'nin döndürdüğü her bağlantı, ardından yönlendirilen bir http:// bağlantısı olur. Bu durum ek bir gidiş-dönüşe neden olur ve web istemcisinde hatalı görünür.
API anahtarı oluşturma
Anahtar olmadan hiçbir şey API ile iletişim kuramaz. Container içindeki CLI aracılığıyla bir anahtar oluşturun.
sudo docker compose exec shlink shlink api-key:generate --name "web client"Komut anahtarı yalnızca bir kez yazdırır. Anahtar hash'lenmiş olarak saklandığından ve tekrar görüntülenemeyeceğinden hemen kopyalayın. shlink api-key:list anahtarların adlarını ve her birinin etkin olup olmadığını gösterir; anahtarın kendisini göstermez. Bir anahtarı shlink api-key:disable ve adını kullanarak iptal edin.
Her REST çağrısında anahtar, X-Api-Key başlığında taşınır.
curl -H "X-Api-Key: YOUR_KEY" https://s.example.com/rest/v3/short-urlsshortUrls anahtarını içeren bir JSON nesnesi, anahtarın çalıştığını gösterir. INVALID_API_KEY içeren bir 401, anahtarın hatalı, devre dışı veya geçerlilik süresinin dolmuş olduğunu gösterir.
Komut satırından kısa bağlantılar oluşturma
CLI, bağlantı oluşturmanın en hızlı yoludur ve betiklerle kullanıma uygundur.
sudo docker compose exec shlink shlink short-url:create https://example.com/a/very/long/path
sudo docker compose exec shlink shlink short-url:create https://example.com/docs --custom-slug docs --tag reference--custom-slug, oluşturulan bir kod yerine okunabilir bir bağlantı sağlar. Kısa adlar etki alanı başına benzersizdir. Bu nedenle, kullanılan bir kısa adla yapılan ikinci deneme ilk bağlantının üzerine sessizce yazmak yerine başarısız olur. --tag tekrarlanabilir. Etiketler, daha sonra birleşik istatistiklerini almak isteyeceğiniz bağlantıları gruplandırmak için kullanılır.
Mevcut öğeleri listeleyin, ardından bir bağlantının trafiğini inceleyin.
sudo docker compose exec shlink shlink short-url:list
sudo docker compose exec shlink shlink short-url:visits docsshort-url:visits, her tıklama için tarih, yönlendiren ve kullanıcı aracısı bilgilerini içeren bir satır yazdırır. GEOLITE_LICENSE_KEY ortam değişkenini ayarlamadığınız sürece ülke ve şehir sütunları boş kalır. Bu değişken, Shlink'in GeoLite2 veritabanını indirmek için kullandığı ücretsiz bir MaxMind anahtarıdır. Bu anahtar olmadan ziyaretler yine kaydedilir, ancak konumları belirlenmez.
Web istemcisi ve QR kodları
Web istemcisi artık 127.0.0.1:8081 üzerinde çalışır ve kendisi için ayrı bir proxy girdisi gerektirir. İstemciyi yayımlamak istemiyorsanız SSH tüneli de kullanılabilir. İlk yüklemede bir sunucu URL'si ve API anahtarı ister. https://s.example.com değerini ve oluşturulan anahtarı girin. İstemci bu iki bilgiyi tarayıcı depolamasında tutar ve API'nizi doğrudan çağırır. Bu nedenle veriler başka bir sistem üzerinden geçmez.
QR kodları için hiçbir yapılandırma gerekmez. Herhangi bir kısa URL'nin sonuna /qr-code eklenir ve API görüntüyü döndürür.
https://s.example.com/docs/qr-code?size=500&format=svg&margin=20size piksel cinsinden genişliktir ve 50 ile 1000 arasındaki değerleri kabul eder. Varsayılan değer 300'dür. format, png veya svg değeridir. margin, kodun çevresindeki piksel cinsinden boş alandır. Oluşan görüntünün boyutu, belirtilen boyuta kenar boşluğunun iki katı eklenerek hesaplanır. Küçük basıldığında veya bir bölümü kapatıldığında da taranabilen bir kod için errorCorrection=Q eklenir.
Çalışır durumda tutma
Bir kısaltma hizmeti sessizce arızalanır. Bağlantılar yönlendirme yapmayı durdurur ve kimse size bildirmez, çünkü bağlantıya tıklayan kişi bağlantının artık çalışmadığını varsayar. Çalışma süresi denetimini ana sayfa yerine gerçek bir kısa URL'ye yönlendirin ve yönlendirme olmayan her durumu uyarı olarak bildirin. Kendi sunucunuzda barındırılan Uptime Kuma örneği bunu iyi şekilde yapar ve belirli bir durum kodunu izleyebilir.
Container'ı değil, veritabanını yedekleyin. Tek bir komut veritabanının dökümünü oluşturur.
sudo docker compose exec -T database pg_dump -U shlink shlink | gzip > shlink-$(date +%F).sql.gzBu dosya ile compose dosyanız, hizmetin tamamını yeni bir sunucuda yeniden oluşturur. Yükseltmelerde önce sudo docker compose pull, ardından sudo docker compose up -d çalıştırılır ve Shlink başlangıçta yeni migration işlemlerini gerçekleştirir. Dökümü pull işleminden önce alın, çünkü bir migration geri alınamaz.
FAQ
Reverse proxy ekledikten sonra kısa bağlantılarım neden 404 döndürüyor?
Shlink, kısa kodu Host üstbilgisindeki etki alanıyla eşleştirir. Proxy kendi adını veya dahili bir adresi gönderirse Shlink bu kodu bağlantı içermeyen bir etki alanında arar ve 404 yanıtı verir. nginx location bloğunda proxy_set_header Host $host; değerini ayarlayın ve proxy'yi yeniden yükleyin. Bağlantılar, container'ı yeniden başlatmaya gerek kalmadan hemen çalışır.
Postgres gerekli mi, yoksa SQLite yeterli mi?
Shlink'i denemek için SQLite yeterlidir ve ikinci bir container gerektirmez. Önemli bağlantıları yayımlamadan önce Postgres'e geçin; çünkü her tıklamayla ziyaret satırları artar ve SQLite yazma işlemlerini serileştirir. Daha sonra geçiş yapmak, bağlantıları dışa aktarıp yeniden içe aktarmayı gerektirir. Bu nedenle başlangıçta Postgres'i seçmek bu geçişi önler.
Kopyalamayı unuttuğum bir API anahtarını kurtarabilir miyim?
Hayır. Shlink, anahtarın hash değerini saklar. Bu nedenle api-key:list adları ve durumu gösterir, ancak anahtar değerini göstermez. shlink api-key:generate ile yeni bir anahtar oluşturun, bunu web istemcisine yapıştırın, ardından çalışmasını durdurmak için eski anahtarı shlink api-key:disable ile devre dışı bırakın.
Ziyaret istatistiklerimde ülke sütunları neden boş?
Coğrafi konum belirleme için GeoLite2 veritabanı gerekir. Shlink bu veritabanını yalnızca bir GEOLITE_LICENSE_KEY verdiğinizde indirir. Anahtar MaxMind'dan ücretsiz olarak alınabilir. Anahtarı ortam bölümüne ekleyin, container'ı yeniden oluşturun ve yeni ziyaretlerin konumu belirlenir. Bundan önce kaydedilmiş ziyaretler, shlink visit:locate komutu çalıştırılana kadar boş kalır.
Shlink'i farklı bir sunucuya nasıl taşıyabilirim?
Etki alanını koruyun ve verileri taşıyın. Veritabanını pg_dump ile dışa aktarın, dışa aktarılan dosyayı ve compose dosyasını yeni sunucuya kopyalayın, stack'i başlatın, ardından gerçek trafik gelmeden önce dışa aktarılan verileri boş veritabanına geri yükleyin. DNS kaydını son olarak değiştirin. Kısa kodlar ve ziyaret geçmişleri korunur; çünkü tüm veriler veritabanında tutulur.