SSD Nodes Learn Hosting plans →
تعلیمی Matt Connorتحریر: Matt Connor · اپ ڈیٹ شدہ 2026-08-29

Shlink کے ذریعے اپنا URL shortener کیسے بنائیں

Docker Compose اور Shlink کا استعمال کرتے ہوئے اپنا URL shortener سیٹ اپ کریں۔ اس گائیڈ میں VPS پر Postgres، API keys، QR codes اور کلک ٹریکنگ کے ساتھ مکمل کنفیگریشن شامل ہے۔

آپ کیا بنا رہے ہیں

ایک self-hosted URL shortener ایک چھوٹا سرور ہے جو ایک طویل لنک کو آپ کی ملکیت والے مختصر لنک میں تبدیل کرتا ہے اور ہر کلک کو شمار کرتا ہے۔ Shlink اس مقصد کے لیے بہترین انتخاب ہے: یہ open source ہے، Docker image کے طور پر دستیاب ہے، اور ایک container اور database کے ساتھ مکمل کام انجام دیتا ہے۔ یہ گائیڈ اسے ایک VPS پر، ایک حقیقی مختصر ڈومین کے پیچھے، HTTPS، API key، QR codes اور کلک کے اعداد و شمار کے ساتھ ترتیب دیتی ہے۔

دو اجزاء اسے ایک کمرشل shortener جیسا بناتے ہیں۔ API سرور redirects کا جواب دیتا ہے اور ڈیٹا کو محفوظ رکھتا ہے۔ Web client ایک الگ static ایپ ہے جو آپ کے براؤزر سے اس API کے ساتھ رابطہ کرتی ہے۔ آپ دونوں کو چلا سکتے ہیں، یا صرف API کو چلا کر اسے command line سے کنٹرول کر سکتے ہیں۔

یہاں دیے گئے ورژن نمبر جولائی 2026 تک کے تازہ ترین ہیں: Shlink 5.1 اور shlink-web-client 4.8۔

سب سے پہلے سرور پر ایک مختصر ڈومین پوائنٹ کریں

ڈومین ہی اصل پروڈکٹ ہے۔ s.example.com/abc123 وہ لنک ہے جو لوگ دیکھتے ہیں، لہذا کوئی مختصر نام منتخب کریں اور کسی بھی چیز کو انسٹال کرنے سے پہلے اسے فائنل کر لیں۔ Shlink ہر مختصر URL کے ساتھ ڈومین کو محفوظ کرتا ہے، اور اسے بعد میں تبدیل کرنے کا مطلب یہ ہوگا کہ آپ کے پہلے سے دیے گئے تمام لنکس کام کرنا چھوڑ دیں گے۔

اپنے مختصر ڈومین کے لیے ایک DNS A ریکارڈ بنائیں، جو آپ کے VPS کے پبلک IPv4 ایڈریس کی طرف اشارہ کرے۔ اگر سرور میں IPv6 موجود ہے تو ایک AAAA ریکارڈ بھی شامل کریں۔ پھر آگے بڑھنے سے پہلے تصدیق کریں کہ یہ ریزولو (resolve) ہو رہا ہے۔

dig +short s.example.com A

آؤٹ پٹ آپ کے سرور کا ایڈریس ہونا چاہیے۔ اگر یہ خالی ہے، تو اس کا مطلب ہے کہ ریکارڈ ابھی تک پروپیگیٹ (propagate) نہیں ہوا ہے، اور بعد کے تمام مراحل الجھا دینے والے انداز میں ناکام ہو جائیں گے، کیونکہ TLS (ٹرانسپورٹ لیئر سیکیورٹی) سرٹیفکیٹ ایسے نام کے لیے جاری نہیں کیا جا سکتا جو ریزولو نہ ہوتا ہو۔

Compose فائل

Shlink کو ایک ڈیٹا بیس کی ضرورت ہوتی ہے۔ ٹیسٹ کے لیے SQLite کام کرتا ہے، لیکن اگر آپ اسے مستقل استعمال کرنا چاہتے ہیں تو Postgres بہترین انتخاب ہے، کیونکہ وزٹ کی قطاریں (visit rows) جمع ہوتی رہتی ہیں اور Postgres انڈیکسز اور بیک وقت ہونے والی تحریروں (concurrent writes) کو بہتر طریقے سے سنبھالتا ہے۔ اسے /opt/shlink/compose.yaml میں رکھیں۔

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:

دونوں شائع شدہ پورٹس 127.0.0.1 پر بائنڈ ہوتی ہیں، لہذا جب تک اگلی سیکشن میں ریورس پراکسی موجود نہ ہو، انٹرنیٹ سے کچھ بھی قابل رسائی نہیں ہوتا۔ Docker ہوسٹ فائر وال سے پہلے اپنے فارورڈنگ رولز لکھتا ہے، جس کا مطلب ہے کہ ایک سادہ 8080:8080 لائن اس ایپ کو ایسے باکس پر بھی ظاہر کر دے گی جس کی فائر وال بند نظر آتی ہے۔ لوپ بیک ایڈریس (loopback address) پر بائنڈ کرنے سے یہ مسئلہ نہیں ہوتا۔ یہی پیٹرن ہر اس ایپ پر لاگو ہوتا ہے جسے آپ اس طرح چلاتے ہیں، اور اس کی مزید تفصیل VPS پر Docker Compose کے گائیڈ میں موجود ہے۔

ڈیٹا بیس کا پاس ورڈ compose فائل کے ساتھ موجود .env فائل سے آتا ہے، لہذا یہ کبھی بھی YAML میں نہیں جاتا۔

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

اسے شروع کریں اور API کے فعال ہونے کا مشاہدہ کریں۔

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

پہلی بار شروع کرنے پر ڈیٹا بیس مائیگریشنز چلتی ہیں، اس لیے یہ بعد کی بار کی نسبت زیادہ وقت لیتا ہے۔ جب یہ مستحکم ہو جائے، تو چیک کریں کہ سروس مقامی طور پر جواب دے رہی ہے۔

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

200 کا مطلب ہے کہ API زندہ ہے اور ڈیٹا بیس کنکشن کام کر رہا ہے۔ یہاں 500 کا مطلب تقریباً ہمیشہ ڈیٹا بیس ہوتا ہے: .env میں موجود DB_PASSWORD اس پاس ورڈ سے میل نہیں کھاتا جس کے ساتھ Postgres بنایا گیا تھا، کیونکہ Postgres امیج POSTGRES_PASSWORD کو صرف تب پڑھتا ہے جب وہ خالی ڈیٹا ڈائریکٹری کو شروع (initialise) کر رہا ہو۔ پاس ورڈ کو بعد میں تبدیل کرنے کا کوئی اثر نہیں ہوتا جب تک کہ آپ والیوم کو ہٹا کر دوبارہ شروع نہ کریں۔

اس کے سامنے HTTPS کو ٹرمینیٹ کریں

Shlink پورٹ 8080 پر سادہ HTTP فراہم کرتا ہے۔ TLS کا کام reverse proxy میں ہوتا ہے، اور سب سے اہم سیٹنگ اصل host name کو آگے بھیجنا ہے۔ Shlink یہ فیصلہ کرنے کے لیے کہ کوئی شارٹ کوڈ کس ڈومین سے تعلق رکھتا ہے، Host ہیڈر کو پڑھتا ہے، لہذا اگر کوئی پراکسی اسے تبدیل کر دے تو موجودہ لنکس پر 404 رسپانس ملیں گے، اور وزٹ کے اعدادوشمار غلط ڈومین کے ساتھ منسلک ہو جائیں گے۔

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;
    }
}

اس کے بعد سرٹیفکیٹ جاری کریں۔ رینیول ٹائمر سمیت مکمل طریقہ کار Ubuntu 24.04 پر nginx کے لیے Certbot گائیڈ میں موجود ہے۔

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

compose فائل میں IS_HTTPS_ENABLED: "true" وہ سیٹنگ ہے جو Shlink کو اس کے واپس کیے گئے شارٹ یو آر ایل میں https:// پرنٹ کرنے پر مجبور کرتی ہے۔ یہ خود بخود TLS کو فعال نہیں کرتی۔ اگر آپ اسے HTTPS پراکسی کے پیچھے false چھوڑ دیں گے تو API کی طرف سے دیا گیا ہر لنک ایک http:// لنک ہوگا جو بعد میں ری ڈائریکٹ ہوتا ہے، جس سے ایک اضافی راؤنڈ ٹرپ ضائع ہوتا ہے اور ویب کلائنٹ میں یہ غلط دکھائی دیتا ہے۔

API key بنائیں

کوئی بھی چیز key کے بغیر API سے رابطہ نہیں کر سکتی۔ container کے اندر CLI کے ذریعے ایک key تیار کریں۔

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

یہ کمانڈ key کو صرف ایک بار پرنٹ کرتی ہے۔ اسے ابھی کاپی کر لیں، کیونکہ یہ hashed حالت میں محفوظ ہوتی ہے اور دوبارہ نہیں دکھائی جا سکتی۔ shlink api-key:list نام دکھاتا ہے اور یہ بتاتا ہے کہ آیا ہر key فعال ہے یا نہیں، لیکن یہ کبھی بھی اصل key نہیں دکھاتا۔ shlink api-key:disable اور نام کے ساتھ کسی key کو منسوخ (revoke) کریں۔

ہر REST کال میں key کو X-Api-Key ہیڈر میں شامل کیا جاتا ہے۔

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

ایک JSON آبجیکٹ جس میں shortUrls key ہو، اس کا مطلب ہے کہ key کام کر رہی ہے۔ INVALID_API_KEY پر مشتمل 401 کا مطلب ہے کہ key غلط ہے، غیر فعال ہے، یا اس کی میعاد ختم ہو چکی ہے۔

کمانڈ لائن سے مختصر لنکس بنانا

CLI لنکس بنانے کا تیز ترین طریقہ ہے، اور یہ اسکرپٹس کے لیے بہترین ہے۔

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 آپ کو تیار کردہ کوڈ کے بجائے ایک پڑھنے کے قابل لنک دیتا ہے۔ Slugs ہر ڈومین کے لیے منفرد ہوتے ہیں، لہذا اگر کوئی slug پہلے سے استعمال میں ہو تو دوسری کوشش ناکام ہو جاتی ہے، بجائے اس کے کہ وہ خاموشی سے پہلے لنک کو اوور رائٹ کر دے۔ --tag کو دہرایا جا سکتا ہے، اور ٹیگز کے ذریعے آپ ان لنکس کو گروپ کر سکتے ہیں جن کے مشترکہ اعدادوشمار آپ بعد میں دیکھنا چاہتے ہیں۔

موجودہ لنکس کی فہرست دیکھیں، پھر کسی ایک لنک کی ٹریفک کا جائزہ لیں۔

sudo docker compose exec shlink shlink short-url:list
sudo docker compose exec shlink shlink short-url:visits docs

short-url:visits ہر کلک کے لیے ایک قطار پرنٹ کرتا ہے جس میں تاریخ، ریفرر اور یوزر ایجنٹ شامل ہوتے ہیں۔ ملک اور شہر کے کالم اس وقت تک خالی رہتے ہیں جب تک آپ GEOLITE_LICENSE_KEY انوائرمنٹ ویری ایبل سیٹ نہ کریں۔ یہ ایک مفت MaxMind کی (key) ہے جسے Shlink، GeoLite2 ڈیٹا بیس ڈاؤن لوڈ کرنے کے لیے استعمال کرتا ہے۔ اس کے بغیر، وزٹس ریکارڈ تو ہوتے ہیں، لیکن ان کا جغرافیائی محل وقوع معلوم نہیں کیا جا سکتا۔

ویب کلائنٹ اور QR کوڈز

ویب کلائنٹ اب 127.0.0.1:8081 پر موجود ہے اور اسے اپنی ایک الگ پراکسی انٹری درکار ہے، یا اگر آپ اسے پبلک نہیں کرنا چاہتے تو آپ SSH ٹنل استعمال کر سکتے ہیں۔ پہلی بار لوڈ ہونے پر یہ سرور کا URL اور API کی (key) مانگتا ہے۔ https://s.example.com اور وہ کی (key) درج کریں جو آپ نے بنائی تھی۔ کلائنٹ ان دونوں کو براؤزر اسٹوریج میں محفوظ رکھتا ہے اور براہ راست آپ کی API کو کال کرتا ہے، لہذا کوئی بھی ڈیٹا کسی تیسرے فریق کے پاس نہیں جاتا۔ انٹرفیس کو API سے الگ کرنا ایک قابلِ غور پیٹرن ہے، کیونکہ یہی وہ طریقہ ہے جس کی بدولت Halcyon ایک Jellyfin لائبریری کو 1990 کی دہائی کے رینٹل اسٹور جیسا دکھا سکتا ہے، جبکہ اس کے پیچھے موجود میڈیا سرور میں کوئی تبدیلی نہیں کرنی پڑتی۔

QR کوڈز کے لیے کسی کنفیگریشن کی ضرورت نہیں ہے۔ کسی بھی شارٹ URL کے آخر میں /qr-code کا اضافہ کریں تو API تصویر واپس بھیج دے گی۔

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

size پکسلز میں چوڑائی ہے اور یہ 50 سے 1000 تک کی ویلیو قبول کرتا ہے، جس میں 300 ڈیفالٹ ہے۔ format کی ویلیو png یا svg ہو سکتی ہے۔ margin کوڈ کے ارد گرد خالی جگہ (quiet space) پکسلز میں ہے، اور حتمی تصویر کا سائز کوڈ کے سائز اور مارجن کے دوگنا کے برابر ہوتا ہے۔ errorCorrection=Q کا اضافہ کریں تاکہ ایسا کوڈ حاصل ہو سکے جو چھوٹا پرنٹ ہونے یا جزوی طور پر ڈھکے ہونے کے باوجود اسکین ہو سکے۔

اسے چلتا رکھیں

ایک shortener خاموشی سے ناکام ہو جاتا ہے۔ لنکس redirect کرنا بند کر دیتے ہیں اور کوئی آپ کو مطلع نہیں کرتا، کیونکہ لنک پر کلک کرنے والا یہ سمجھتا ہے کہ لنک ڈیڈ ہے۔ uptime چیک کو ہوم پیج کے بجائے کسی حقیقی short URL پر پوائنٹ کریں، اور کسی بھی ایسی چیز پر الرٹ سیٹ کریں جو redirect نہ ہو۔ ایک self-hosted Uptime Kuma instance یہ کام بخوبی کرتا ہے، اور یہ مخصوص status code کی نگرانی بھی کر سکتا ہے۔

کنٹینر کا نہیں، ڈیٹا بیس کا بیک اپ لیں۔ ایک کمانڈ اسے ڈمپ (dump) کر دیتی ہے۔

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

وہ فائل اور آپ کی compose فائل مل کر پورے سروس کو نئے سرور پر دوبارہ تعمیر کر دیتی ہیں۔ باکس پر موجود ہر ایپ کو اس جوڑی کے اپنے ورژن کی ضرورت ہوتی ہے، اور فوٹو لائبریری ایک مشکل کیس ہے، کیونکہ PhotoPrism اور Immich دونوں اصل فائلیں ڈسک پر اور ڈیٹا بیس میں قطاریں (rows) رکھتی ہیں، لہذا صرف ایک ڈمپ کچھ بھی بحال نہیں کرتا۔ اپ گریڈز sudo docker compose pull کے بعد sudo docker compose up -d کے ذریعے ہوتے ہیں، اور Shlink شروع ہونے پر کوئی بھی نئی مائیگریشن خود چلا لیتا ہے۔ پل (pull) کرنے سے پہلے ڈمپ لے لیں، کیونکہ مائیگریشن کو رول بیک (roll back) نہیں کیا جا سکتا۔

FAQ

ریورس پراکسی شامل کرنے کے بعد میرے شارٹ لنکس 404 کیوں دکھا رہے ہیں؟

Shlink شارٹ کوڈ کا موازنہ Host ہیڈر میں موجود ڈومین سے کرتا ہے۔ اگر پراکسی اپنا نام یا کوئی اندرونی ایڈریس بھیجتی ہے، تو Shlink اس کوڈ کو ایسی ڈومین کے تحت تلاش کرتا ہے جس میں کوئی لنکس موجود نہیں ہوتے، اس لیے وہ 404 کا جواب دیتا ہے۔ nginx لوکیشن بلاک میں proxy_set_header Host $host; سیٹ کریں اور پراکسی کو ری لوڈ کریں۔ لنکس فوراً کام کرنا شروع کر دیں گے، کنٹینر کو ری اسٹارٹ کرنے کی ضرورت نہیں ہے۔

کیا مجھے Postgres کی ضرورت ہے، یا SQLite کافی ہے؟

SQLite Shlink کو آزمانے کے لیے ٹھیک ہے اور اس کے لیے کسی دوسرے کنٹینر کی ضرورت نہیں ہوتی۔ اہم لنکس شائع کرنے سے پہلے Postgres پر منتقل ہو جائیں، کیونکہ ہر کلک کے ساتھ وزٹ کی قطاریں بڑھتی ہیں اور SQLite رائٹس (writes) کو سیریلائز کرتا ہے۔ بعد میں سوئچ کرنے کا مطلب ہے اپنے لنکس کو ایکسپورٹ اور دوبارہ امپورٹ کرنا، اس لیے شروع میں ہی Postgres کا انتخاب آپ کو اس مائیگریشن سے بچا لیتا ہے۔

کیا میں وہ API کی (key) دوبارہ حاصل کر سکتا ہوں جسے میں کاپی کرنا بھول گیا تھا؟

نہیں۔ Shlink کی (key) کا ہیش اسٹور کرتا ہے، اس لیے api-key:list نام اور اسٹیٹس تو دکھاتا ہے لیکن کبھی بھی ویلیو نہیں دکھاتا۔ shlink api-key:generate کے ساتھ ایک متبادل جنریٹ کریں، اسے ویب کلائنٹ میں پیسٹ کریں، اور پھر پرانی والی کو shlink api-key:disable کے ساتھ ڈس ایبل کر دیں تاکہ وہ کام کرنا بند کر دے۔

میرے وزٹ اسٹیٹس میں ملک کے کالم خالی کیوں ہیں؟

جیو لوکیشن کے لیے GeoLite2 ڈیٹا بیس کی ضرورت ہوتی ہے، جسے Shlink صرف تب ڈاؤن لوڈ کرتا ہے جب آپ اسے GEOLITE_LICENSE_KEY فراہم کرتے ہیں۔ یہ کی (key) MaxMind سے مفت ملتی ہے۔ اسے انوائرمنٹ سیکشن میں شامل کریں، کنٹینر کو دوبارہ بنائیں، اور نئے وزٹس کی لوکیشن معلوم ہو جائے گی۔ اس سے پہلے ریکارڈ کیے گئے وزٹس تب تک خالی رہیں گے جب تک آپ shlink visit:locate رن نہیں کرتے۔

ڈومین کو برقرار رکھیں اور ڈیٹا منتقل کریں۔ ڈیٹا بیس کو pg_dump کے ساتھ ڈمپ کریں، ڈمپ اور compose فائل کو نئے سرور پر کاپی کریں، اسٹیک شروع کریں، اور پھر اصلی ٹریفک آنے سے پہلے خالی ڈیٹا بیس میں ڈمپ کو ریسٹور کریں۔ DNS ریکارڈ سب سے آخر میں تبدیل کریں۔ شارٹ کوڈز اور ان کی وزٹ ہسٹری محفوظ رہتی ہے، کیونکہ سب کچھ ڈیٹا بیس میں موجود ہوتا ہے۔

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