Shlink के साथ अपना खुद का URL Shortener कैसे बनाएं
Shlink और Docker Compose का उपयोग करके अपना URL शॉर्टनर सेटअप करें। इस गाइड में DNS कॉन्फ़िगरेशन, Postgres डेटाबेस, API कीज़ और क्लिक ट्रैकिंग की पूरी प्रक्रिया शामिल है।
आप क्या बना रहे हैं
सेल्फ-होस्टेड URL शॉर्टनर एक छोटा सर्वर है जो एक लंबे लिंक को आपके स्वामित्व वाले छोटे लिंक में बदल देता है और उस पर होने वाले हर क्लिक को गिनता है। Shlink इसके लिए सबसे अच्छा विकल्प है: यह ओपन सोर्स है, यह Docker इमेज के रूप में उपलब्ध है, और यह एक कंटेनर और एक डेटाबेस में पूरा काम करता है। यह गाइड इसे एक VPS पर, एक वास्तविक छोटे डोमेन के पीछे, HTTPS, एक API key, QR कोड और क्लिक आँकड़ों के साथ स्थापित करती है।
दो घटक इसे एक कमर्शियल शॉर्टनर जैसा अनुभव देते हैं। API सर्वर रीडायरेक्ट का उत्तर देता है और डेटा को सुरक्षित रखता है। वेब क्लाइंट एक अलग स्टेटिक ऐप है जो आपके ब्राउज़र से उस API के साथ संचार करता है। आप दोनों को चला सकते हैं, या केवल API को चलाकर उसे कमांड लाइन से नियंत्रित कर सकते हैं।
यहाँ दिए गए वर्ज़न नंबर जुलाई 2026 तक के नवीनतम हैं: Shlink 5.1 और shlink-web-client 4.8।
सबसे पहले सर्वर पर एक छोटा डोमेन पॉइंट करें
डोमेन ही उत्पाद है। s.example.com/abc123 वह लिंक है जिसे लोग देखते हैं, इसलिए कुछ छोटा चुनें और किसी भी चीज़ को इंस्टॉल करने से पहले इसे चुन लें। Shlink हर छोटे URL के साथ डोमेन को स्टोर करता है, और बाद में इसे बदलने का मतलब है कि आपके द्वारा पहले से दिए गए सभी लिंक काम करना बंद कर देंगे।
अपने छोटे डोमेन के लिए एक DNS A रिकॉर्ड बनाएं, जो आपके VPS के सार्वजनिक IPv4 पते पर पॉइंट करता हो। यदि सर्वर में IPv6 है, तो एक AAAA रिकॉर्ड भी जोड़ें। फिर आगे बढ़ने से पहले पुष्टि करें कि यह रिज़ॉल्व हो रहा है।
dig +short s.example.com Aआउटपुट आपके सर्वर का पता होना चाहिए। यदि यह खाली है, तो रिकॉर्ड अभी तक प्रोपेगेट नहीं हुआ है, और बाद का हर चरण भ्रमित करने वाले तरीके से विफल हो जाएगा, क्योंकि TLS (transport layer security) प्रमाणपत्र उस नाम के लिए जारी नहीं किया जा सकता जो रिज़ॉल्व नहीं होता है।
The compose file
Shlink को एक डेटाबेस की आवश्यकता होती है। परीक्षण के लिए SQLite काम करता है, लेकिन यदि आप डेटा को सुरक्षित रखना चाहते हैं तो Postgres सही विकल्प है। इसका कारण यह है कि visit पंक्तियाँ जमा होती रहती हैं और 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 लाइन उस सर्वर पर भी ऐप को एक्सपोज़ कर देगी जिसका फायरवॉल बंद दिखता है। लूपबैक एड्रेस से बाइंड करने पर यह समस्या नहीं होती। यही पैटर्न इस तरह चलाए जाने वाले किसी भी ऐप पर लागू होता है, और इसे 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 को केवल तभी पढ़ती है जब वह एक खाली डेटा डायरेक्टरी को इनिशियलाइज़ करती है। बाद में पासवर्ड बदलने का कोई प्रभाव नहीं पड़ता जब तक कि आप वॉल्यूम को हटाकर फिर से शुरू न करें।
HTTPS को इसके आगे समाप्त करें
Shlink पोर्ट 8080 पर सादा HTTP प्रदान करता है। TLS एक रिवर्स प्रॉक्सी में होना चाहिए, और सबसे महत्वपूर्ण सेटिंग मूल होस्ट नाम को आगे भेजना है। 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.comcompose फ़ाइल में IS_HTTPS_ENABLED: "true" वह सेटिंग है जो Shlink को उसके द्वारा लौटाए गए शॉर्ट URL में https:// प्रिंट करने के लिए कहती है। यह अपने आप TLS को सक्षम नहीं करती है। इसे HTTPS प्रॉक्सी के पीछे false छोड़ दें, अन्यथा API द्वारा लौटाया गया प्रत्येक लिंक एक http:// लिंक होगा जो बाद में रीडायरेक्ट करता है। इसमें एक अतिरिक्त राउंड ट्रिप का समय लगता है और यह वेब क्लाइंट में गलत दिखता है।
API key बनाएँ
API key के बिना API से कोई भी संचार संभव नहीं है। कंटेनर के अंदर CLI के माध्यम से एक key जनरेट करें।
sudo docker compose exec shlink shlink api-key:generate --name "web client"यह कमांड key को केवल एक बार प्रिंट करती है। इसे अभी कॉपी कर लें, क्योंकि यह hashed रूप में स्टोर होती है और इसे दोबारा नहीं दिखाया जा सकता। shlink api-key:list प्रत्येक key का नाम और उसकी स्थिति (enabled है या नहीं) दिखाती है, लेकिन 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-urlsshortUrls key वाला एक JSON ऑब्जेक्ट यह दर्शाता है कि key सही ढंग से काम कर रही है। INVALID_API_KEY युक्त 401 यह दर्शाता है कि key गलत है, अक्षम (disabled) है, या उसकी समाप्ति तिथि निकल चुकी है।
कमांड लाइन से शॉर्ट लिंक बनाना
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 आपको जनरेट किए गए कोड के बजाय एक पठनीय लिंक देता है। स्लग प्रत्येक डोमेन के लिए अद्वितीय होते हैं, इसलिए यदि कोई स्लग पहले से लिया गया है, तो उस पर दूसरा प्रयास विफल हो जाएगा, बजाय इसके कि वह चुपचाप पहले लिंक को ओवरराइट कर दे। --tag को दोहराया जा सकता है, और टैग्स का उपयोग उन लिंक्स को समूहित करने के लिए किया जाता है जिनके लिए आप बाद में संयुक्त आँकड़े देखना चाहते हैं।
मौजूदा लिंक्स की सूची देखें, फिर किसी एक लिंक का ट्रैफ़िक देखें।
sudo docker compose exec shlink shlink short-url:list
sudo docker compose exec shlink shlink short-url:visits docsshort-url:visits प्रत्येक क्लिक के लिए दिनांक, रेफ़रर और यूज़र एजेंट के साथ एक पंक्ति प्रिंट करता है। देश और शहर के कॉलम तब तक खाली रहते हैं जब तक आप GEOLITE_LICENSE_KEY एनवायरनमेंट वेरिएबल सेट नहीं करते, जो कि एक निःशुल्क MaxMind की है जिसका उपयोग Shlink, GeoLite2 डेटाबेस डाउनलोड करने के लिए करता है। इसके बिना, विज़िट रिकॉर्ड तो की जाती हैं, लेकिन उनकी लोकेशन का पता नहीं चलता है।
वेब क्लाइंट और QR कोड
वेब क्लाइंट अब 127.0.0.1:8081 पर उपलब्ध है और इसके लिए एक अलग प्रॉक्सी एंट्री की आवश्यकता है, या यदि आप इसे पब्लिश नहीं करना चाहते हैं तो आप SSH टनल का उपयोग कर सकते हैं। पहली बार लोड होने पर यह सर्वर URL और API की (key) मांग करता है। https://s.example.com और आपके द्वारा जनरेट की गई की (key) दर्ज करें। क्लाइंट इन दोनों को ब्राउज़र स्टोरेज में रखता है और सीधे आपके API को कॉल करता है, इसलिए कोई भी डेटा किसी अन्य के माध्यम से नहीं गुजरता है।
QR कोड के लिए किसी कॉन्फ़िगरेशन की आवश्यकता नहीं होती है। किसी भी शॉर्ट URL के अंत में /qr-code जोड़ें और API इमेज रिटर्न कर देगा।
https://s.example.com/docs/qr-code?size=500&format=svg&margin=20size पिक्सल में चौड़ाई है और यह 50 से 1000 तक की वैल्यू स्वीकार करता है, जिसमें 300 डिफ़ॉल्ट है। format का मान png या svg हो सकता है। margin कोड के चारों ओर पिक्सल में खाली जगह (quiet space) है, और तैयार इमेज का माप साइज और मार्जिन के दोगुने के बराबर होता है। ऐसे कोड के लिए errorCorrection=Q जोड़ें जो छोटा प्रिंट होने या आंशिक रूप से ढके होने पर भी स्कैन हो सके।
इसे चालू रखें
एक शॉर्टनर चुपचाप विफल हो जाता है। लिंक रीडायरेक्ट करना बंद कर देते हैं और कोई आपको सूचित नहीं करता है, क्योंकि लिंक पर क्लिक करने वाले व्यक्ति ने मान लिया कि लिंक मृत है। होम पेज के बजाय किसी वास्तविक शॉर्ट URL पर एक अपटाइम चेक सेट करें, और किसी भी ऐसी चीज़ पर अलर्ट करें जो रीडायरेक्ट नहीं है। एक सेल्फ-होस्टेड Uptime Kuma इंस्टेंस यह काम अच्छी तरह से करता है, और यह एक विशिष्ट स्टेटस कोड की निगरानी कर सकता है।
कंटेनर का नहीं, बल्कि डेटाबेस का बैकअप लें। एक कमांड इसे डंप कर देती है।
sudo docker compose exec -T database pg_dump -U shlink shlink | gzip > shlink-$(date +%F).sql.gzवह फ़ाइल और आपकी compose फ़ाइल मिलकर पूरे सर्विस को एक नए सर्वर पर फिर से बना देती है। अपग्रेड के लिए पहले sudo docker compose pull और उसके बाद sudo docker compose up -d का उपयोग करें, और Shlink स्टार्टअप पर किसी भी नए माइग्रेशन को चलाता है। पुल करने से पहले डंप लें, क्योंकि माइग्रेशन को रोल बैक नहीं किया जा सकता है।
FAQ
रिवर्स प्रॉक्सी जोड़ने के बाद मेरे शॉर्ट लिंक 404 क्यों दिखाते हैं?
Shlink Host हेडर में मौजूद डोमेन के आधार पर शॉर्ट कोड का मिलान करता है। यदि प्रॉक्सी अपना नाम या कोई आंतरिक पता भेजती है, तो Shlink उस कोड को ऐसे डोमेन के अंतर्गत खोजता है जिसमें कोई लिंक नहीं है, इसलिए यह 404 त्रुटि देता है। nginx लोकेशन ब्लॉक में proxy_set_header Host $host; सेट करें और प्रॉक्सी को रीलोड करें। लिंक तुरंत काम करना शुरू कर देंगे, इसके लिए कंटेनर को रीस्टार्ट करने की आवश्यकता नहीं है।
क्या मुझे Postgres की आवश्यकता है, या SQLite पर्याप्त है?
SQLite का उपयोग Shlink को आज़माने के लिए ठीक है और इसके लिए किसी दूसरे कंटेनर की आवश्यकता नहीं होती है। यदि आप महत्वपूर्ण लिंक प्रकाशित कर रहे हैं तो Postgres पर स्विच करें, क्योंकि हर क्लिक के साथ विजिट की पंक्तियाँ बढ़ती हैं और SQLite राइट ऑपरेशन्स को सीरियलाइज़ करता है। बाद में स्विच करने का अर्थ है अपने लिंक को एक्सपोर्ट और फिर से इम्पोर्ट करना, इसलिए शुरुआत में ही Postgres चुनना आपको इस माइग्रेशन से बचाता है।
क्या मैं अपना भूला हुआ API key रिकवर कर सकता हूँ?
नहीं। Shlink की का हैश स्टोर करता है, इसलिए api-key:list केवल नाम और स्थिति दिखाता है, लेकिन कभी भी की का मान नहीं दिखाता। shlink api-key:generate के साथ एक नई की जनरेट करें, इसे वेब क्लाइंट में पेस्ट करें, और फिर पुरानी की को shlink api-key:disable के साथ डिसेबल कर दें ताकि वह काम करना बंद कर दे।
मेरे विजिट आँकड़ों में देश वाले कॉलम खाली क्यों हैं?
जियोलोकेशन के लिए GeoLite2 डेटाबेस की आवश्यकता होती है, जिसे Shlink केवल तभी डाउनलोड करता है जब आप इसे GEOLITE_LICENSE_KEY प्रदान करते हैं। यह की MaxMind से मुफ्त मिलती है। इसे एनवायरनमेंट सेक्शन में जोड़ें, कंटेनर को फिर से बनाएँ, और नई विजिट्स का स्थान पता चल जाएगा। इससे पहले रिकॉर्ड की गई विजिट्स तब तक खाली रहेंगी जब तक आप shlink visit:locate नहीं चलाते।
मैं Shlink को दूसरे सर्वर पर कैसे ले जाऊँ?
डोमेन को बनाए रखें और डेटा को स्थानांतरित करें। pg_dump के साथ डेटाबेस का डंप लें, डंप और compose फ़ाइल को नए सर्वर पर कॉपी करें, स्टैक को स्टार्ट करें, और फिर वास्तविक ट्रैफ़िक आने से पहले खाली डेटाबेस में डंप को रिस्टोर करें। DNS रिकॉर्ड को सबसे अंत में बदलें। शॉर्ट कोड और उनका विजिट इतिहास सुरक्षित रहता है, क्योंकि सब कुछ डेटाबेस में ही रहता है।