SSD Nodes Learn Hosting plans →
Rehberler Matt ConnorYazan Matt Connor · Güncellendi 2026-08-27

Shlink ile Kendi URL Kısaltıcınızı Kurun

Shlink ve Docker Compose kullanarak kendi VPS sunucunuzda URL kısaltıcı oluşturun. DNS ayarları, Postgres veritabanı, API anahtarları ve detaylı tıklama istatistikleri.

Ne inşa ediyorsunuz

Kendi kendine barındırılan (self-hosted) bir URL kısaltıcı, uzun bir bağlantıyı size ait kısa bir bağlantıya dönüştüren ve her tıklamayı sayan küçük bir sunucudur. Shlink bu iş için en uygun tercihtir: açık kaynaklıdır, Docker imajı olarak dağıtılır ve tüm işi bir container ile bir veritabanı üzerinde gerçekleştirir. Bu kılavuz, Shlink'i bir VPS üzerinde, gerçek bir kısa alan adı arkasında, HTTPS, API anahtarı, QR kodları ve tıklama istatistikleri ile yapılandırır.

İki bileşen, sistemin ticari bir kısaltıcı gibi hissettirmesini sağlar. API sunucusu yönlendirmeleri yanıtlar ve verileri tutar. Web istemcisi ise tarayıcınızdan bu API ile iletişim kuran ayrı bir statik uygulamadır. Her ikisini de çalıştırabilir veya yalnızca API'yi çalıştırıp komut satırı üzerinden yönetebilirsiniz.

Buradaki sürüm numaraları Temmuz 2026 itibarıyla güncel olanlardır: Shlink 5.1 ve shlink-web-client 4.8.

Kısa alan adını öncelikle sunucuya yönlendirin

Alan adı ürünün kendisidir. s.example.com/abc123 insanların gördüğü bağlantıdır, bu nedenle kısa bir isim seçin ve herhangi bir kurulum yapmadan önce bu seçimi tamamlayın. Shlink, alan adını her kısa URL ile birlikte saklar; daha sonra değiştirmek, dağıttığınız tüm bağlantıların çalışmamasına neden olur.

Kısa alan adınız için VPS genel IPv4 adresinize işaret eden bir adet DNS A kaydı oluşturun. Sunucunuzda IPv6 varsa bir AAAA kaydı da ekleyin. Ardından devam etmeden önce çözümleme yapıldığını doğrulayın.

dig +short s.example.com A

Çıktı, sunucunuzun adresi olmalıdır. Eğer çıktı boşsa, kayıt henüz yayılmamış demektir. Bu durumda sonraki tüm adımlar kafa karıştırıcı bir şekilde başarısız olacaktır; çünkü çözümleme yapmayan bir isim için TLS (transport layer security) sertifikası düzenlenemez.

Compose dosyası

Shlink bir veritabanına ihtiyaç duyar. SQLite test için uygundur ancak kalıcı olması planlanan her şey için Postgres doğru tercihtir; çünkü ziyaret kayıtları birikir ve Postgres, indeksleri ve eşzamanlı yazma işlemlerini daha iyi yönetir. Bunu /opt/shlink/compose.yaml içine yerleştirin.

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ınlanan port da 127.0.0.1 adresine bağlanır, bu nedenle bir sonraki bölümde yer alan reverse proxy kurulana kadar internet üzerinden hiçbir şeye erişilemez. Docker, kendi yönlendirme kurallarını ana makine güvenlik duvarının önüne yazar; bu da basit bir 8080:8080 satırının, güvenlik duvarı kapalı görünen bir sunucuda bile uygulamayı dış dünyaya açacağı anlamına gelir. Loopback adresine bağlamak bu durumu engeller. Aynı yöntem bu şekilde çalıştırdığınız tüm uygulamalar için geçerlidir ve VPS üzerinde Docker Compose rehberi içinde daha ayrıntılı olarak ele alınmıştır.

Veritabanı parolası, compose dosyasının yanındaki bir .env dosyasından gelir, böylece YAML içinde asla yer almaz.

sudo mkdir -p /opt/shlink
printf 'DB_PASSWORD=%s\n' "$(openssl rand -base64 24)" | sudo tee /opt/shlink/.env
sudo chmod 600 /opt/shlink/.env

Başlatın ve API'nin ayağa kalkışını izleyin.

cd /opt/shlink
sudo docker compose up -d
sudo docker compose logs -f shlink

İlk başlatma veritabanı migrasyonlarını çalıştırır, bu nedenle sonraki başlatmalardan daha uzun sürer. İşlem tamamlandığında servisin yerel olarak yanıt verip vermediğini kontrol edin.

curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080/rest/health

Bir 200, API'nin canlı olduğunu ve veritabanı bağlantısının çalıştığını gösterir. Buradaki bir 500 neredeyse her zaman veritabanı kaynaklıdır: .env içindeki DB_PASSWORD, Postgres'in oluşturulduğu değerle eşleşmiyordur; çünkü Postgres imajı POSTGRES_PASSWORD dosyasını yalnızca boş bir veri dizinini başlatırken okur. Parolayı daha sonra düzenlemek, volume silinip yeniden başlatılana kadar hiçbir etki yaratmaz.

HTTPS sonlandırmasını ön tarafta yapın

Shlink, 8080 numaralı port üzerinden düz HTTP sunar. TLS işlemi bir reverse proxy üzerinde yapılmalıdır; burada önemli olan tek ayar, orijinal ana makine adının (host name) iletilmesidir. Shlink, bir kısa kodun hangi alan adına ait olduğuna Host başlığını okuyarak karar verir. Bu başlığı yeniden yazan bir proxy, mevcut bağlantılar için 404 hataları üretilmesine ve ziyaret istatistiklerinin yanlış alan adına kaydedilmesine neden olur.

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 izlenecek yol, Ubuntu 24.04 üzerinde nginx için Certbot kılavuzu içerisinde yer almaktadır.

sudo certbot --nginx -d s.example.com

Compose dosyası içindeki IS_HTTPS_ENABLED: "true", Shlink'in döndürdüğü kısa URL'lerde https:// yazmasını sağlayan ayardır. Bu ayar tek başına TLS'i etkinleştirmez. Eğer bu ayarı bir HTTPS proxy'sinin arkasında false olarak bırakırsanız, API'nin döndürdüğü her bağlantı bir http:// bağlantısı olur. Bu durum, bir gidiş-dönüş süresi maliyeti yaratır ve web istemcisinde hatalı görünür.

API anahtarı oluşturma

Bir anahtar olmadan API ile iletişim kurulamaz. Anahtarı container içerisindeki CLI aracılığıyla oluşturun.

sudo docker compose exec shlink shlink api-key:generate --name "web client"

Komut, anahtarı yalnızca bir kez ekrana yazdırır. Anahtar hash'lenmiş olarak saklandığı ve tekrar görüntülenemeyeceği için hemen kopyalayın. shlink api-key:list, anahtarların isimlerini ve etkin olup olmadıklarını gösterir ancak anahtarın kendisini göstermez. Bir anahtarı iptal etmek için shlink api-key:disable komutunu ve anahtar ismini kullanın.

Her REST çağrısı, anahtarı bir X-Api-Key başlığında taşır.

curl -H "X-Api-Key: YOUR_KEY" https://s.example.com/rest/v3/short-urls

shortUrls anahtarına sahip bir JSON nesnesi, anahtarın çalıştığı anlamına gelir. INVALID_API_KEY içeren bir 401, anahtarın hatalı, devre dışı veya son kullanma tarihinin geçmiş 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 (script) uyumlu çalışır.

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. Slug'lar her alan adı için benzersizdir; bu nedenle halihazırda alınmış bir slug üzerinde ikinci bir deneme yapıldığında, ilk bağlantının üzerine sessizce yazmak yerine işlem başarısız olur. --tag tekrarlanabilir ve etiketler (tags), daha sonra toplu istatistiklerini görmek isteyeceğiniz bağlantıları gruplandırmanızı sağlar.

Mevcut olanları 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 docs

short-url:visits, her tıklama için tarih, yönlendiren (referrer) ve kullanıcı aracısı (user agent) bilgilerini içeren bir satır yazdırır. Ülke ve şehir sütunları, bir GEOLITE_LICENSE_KEY ortam değişkeni tanımlamadığınız sürece 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 kaydedilmeye devam eder, ancak konum bilgisi alınamaz.

Web istemcisi ve QR kodları

Web istemcisi artık 127.0.0.1:8081 adresindedir ve kendi proxy girişine ihtiyaç duyar; eğer dış dünyaya açmak istemiyorsanız bir SSH tüneli kullanabilirsiniz. İlk yüklemede bir sunucu URL'si ve API anahtarı ister. https://s.example.com adresini ve oluşturduğunuz anahtarı girin. İstemci her iki bilgiyi de tarayıcı depolama alanında tutar ve API'nizi doğrudan çağırır; bu sayede veriler başka bir taraftan geçmez. Arayüzü API'den ayırmak dikkat çekici bir yöntemdir; çünkü bu, Halcyon'un bir Jellyfin kütüphanesini 1990'ların video kiralama dükkanı gibi göstermesini sağlayan ve medya sunucusunda herhangi bir değişiklik yapmayı gerektirmeyen yapıyla aynıdır.

QR kodları herhangi bir yapılandırma gerektirmez. Herhangi bir kısa URL'nin sonuna /qr-code eklediğinizde API ilgili görseli döndürür.

https://s.example.com/docs/qr-code?size=500&format=svg&margin=20

size piksel cinsinden genişliği temsil eder ve 50 ile 1000 arasında değer kabul eder; varsayılan değer 300'dür. format değeri png veya svg olabilir. margin kodun etrafındaki boşluk alanını piksel cinsinden belirler; nihai görselin boyutu, kod boyutu ile kenar boşluğunun iki katının toplamına eşittir. Küçük boyutlarda basıldığında veya kısmen kapandığında dahi taranabilir bir kod elde etmek için errorCorrection=Q parametresini ekleyin.

Sistemi çalışır durumda tutma

Bir kısaltıcı sessizce başarısız olabilir. Bağlantılar yönlendirmeyi durdurur ve kimse size haber vermez; çünkü bağlantıya tıklayan kişi bağlantının ölü olduğunu varsayar. Uptime kontrolünü ana sayfaya değil, gerçek bir kısa URL'ye yönlendirin ve yönlendirme dışındaki her türlü durumda uyarı alın. Kendi kendine barındırılan bir Uptime Kuma örneği bu işi iyi yapar ve belirli bir durum kodunu izleyebilir.

Container'ı değil, veritabanını yedekleyin. Tek bir komut ile yedeği alınabilir.

sudo docker compose exec -T database pg_dump -U shlink shlink | gzip > shlink-$(date +%F).sql.gz

Bu dosya ve compose dosyanız, tüm servisi yeni bir sunucuda yeniden oluşturmanızı sağlar. Sunucudaki her uygulamanın bu ikilinin kendi sürümüne ihtiyacı vardır. Fotoğraf kütüphaneleri ise zorlu bir durumdur; çünkü PhotoPrism ve Immich hem orijinalleri diskte tutar hem de veritabanında satırlar barındırır; bu nedenle sadece bir dump dosyası hiçbir şeyi geri yüklemez. Yükseltmeler sudo docker compose pull komutunu takiben sudo docker compose up -d komutu ile yapılır ve Shlink, başlangıçta yeni migrasyonları çalıştırır. Dump dosyasını pull işleminden önce alın, çünkü bir migrasyon geri alınamaz.

FAQ

Ters vekil sunucu ekledikten sonra kısa bağlantılarım neden 404 hatası veriyor?

Shlink, kısa kodu Host başlığındaki alan adıyla eşleştirir. Kendi adını veya dahili bir adresi gönderen bir vekil sunucu, Shlink'in o kodu bağlantısı olmayan bir alan adı altında aramasına neden olur ve bu yüzden 404 yanıtı döner. Nginx location bloğunda proxy_set_header Host $host; ayarını yapın ve vekil sunucuyu yeniden yükleyin. Bağlantılar, container yeniden başlatılmasına gerek kalmadan hemen çalışmaya başlar.

Postgres kullanmam gerekiyor mu, yoksa SQLite yeterli mi?

SQLite, Shlink'i denemek için uygundur ve ikinci bir container gerektirmez. Önemli bağlantılar yayınlamadan önce Postgres'e geçin; çünkü ziyaret satırları her tıklamada artar ve SQLite yazma işlemlerini sıraya alır. Daha sonra geçiş yapmak, bağlantılarınızı dışa ve içe aktarmanız anlamına gelir; bu nedenle başlangıçta Postgres seçmek sizi bu göç işleminden kurtarır.

Kopyalamayı unuttuğum bir API anahtarını kurtarabilir miyim?

Hayır. Shlink anahtarın bir özetini (hash) saklar, bu yüzden api-key:list yalnızca isimleri ve durumu gösterir, değeri asla göstermez. shlink api-key:generate ile yeni bir tane oluşturun, web istemcisine yapıştırın ve ardından eskisini shlink api-key:disable ile devre dışı bırakarak çalışmasını durdurun.

Ziyaret istatistiklerimdeki ülke sütunları neden boş?

Coğrafi konum belirleme, Shlink'in yalnızca GEOLITE_LICENSE_KEY verdiğinizde indirdiği GeoLite2 veritabanına ihtiyaç duyar. Bu anahtar MaxMind üzerinden ücretsiz alınabilir. Anahtarı environment bölümüne ekleyin, container'ı yeniden oluşturun; yeni ziyaretler konumlandırılacaktır. Bundan önce kaydedilen ziyaretler, shlink visit:locate komutunu çalıştırana kadar boş kalmaya devam eder.

Alan adını koruyun ve verileri taşıyın. Veritabanını pg_dump ile dışa aktarın (dump), dump dosyasını ve compose dosyasını yeni sunucuya kopyalayın, stack'i başlatın ve ardından gerçek trafik gelmeden önce dump dosyasını boş veritabanına geri yükleyin. DNS kaydını en son değiştirin. Kısa kodlar ve ziyaret geçmişleri korunur, çünkü her şey veritabanında saklanır.

#shlink#url-shortener#self-hosting#docker#postgres