Shlink के साथ अपना URL shortener कैसे बनाएं
Docker Compose का उपयोग करके अपने VPS पर Shlink को होस्ट करना सीखें। इस गाइड में Postgres सेटअप, API keys, HTTPS कॉन्फ़िगरेशन और क्लिक एनालिटिक्स को मैनेज करने का पूरा तरीका शामिल है।
आप क्या बना रहे हैं
एक self-hosted URL shortener एक छोटा सर्वर है जो एक लंबे लिंक को आपके स्वामित्व वाले छोटे लिंक में बदल देता है और हर क्लिक की गिनती करता है। Shlink इसके लिए सबसे अच्छा विकल्प है: यह open source है, एक Docker image के रूप में उपलब्ध है, और यह एक container और एक database के साथ पूरा काम करता है। यह गाइड इसे एक VPS पर, एक वास्तविक short domain के पीछे, HTTPS, एक API key, QR codes और click stats के साथ स्थापित करती है।
दो घटक इसे एक commercial shortener जैसा अनुभव देते हैं। API server redirects का उत्तर देता है और डेटा को सुरक्षित रखता है। Web client एक अलग static app है जो आपके browser से उस API के साथ संवाद करती है। आप दोनों को चला सकते हैं, या केवल API को चलाकर उसे command line से नियंत्रित कर सकते हैं।
यहाँ दिए गए version numbers अक्टूबर 2026 तक के नवीनतम संस्करण हैं: Shlink 5.1 और shlink-web-client 4.8।
सबसे पहले सर्वर पर एक छोटा डोमेन पॉइंट करें
डोमेन ही आपका प्रोडक्ट है। s.example.com/abc123 वह लिंक है जिसे लोग देखते हैं, इसलिए कुछ छोटा चुनें और किसी भी चीज़ को इंस्टॉल करने से पहले इसे तय कर लें। Shlink हर short URL के साथ डोमेन को स्टोर करता है, और बाद में इसे बदलने का मतलब है कि आपके द्वारा पहले से दिए गए सभी लिंक काम करना बंद कर देंगे।
अपने छोटे डोमेन के लिए एक DNS A record बनाएँ, जो आपके VPS के public IPv4 address की ओर पॉइंट करता हो। यदि सर्वर में IPv6 है, तो एक AAAA record भी जोड़ें। आगे बढ़ने से पहले पुष्टि करें कि यह resolve हो रहा है।
dig +short s.example.com Aआउटपुट आपके सर्वर का address होना चाहिए। यदि यह खाली है, तो record अभी तक propagate नहीं हुआ है, और बाद का हर कदम भ्रमित करने वाले तरीके से विफल हो जाएगा, क्योंकि जिस नाम का DNS resolve नहीं होता, उसके लिए TLS (transport layer security) certificate जारी नहीं किया जा सकता है।
Compose file
Shlink को एक database की आवश्यकता होती है। परीक्षण के लिए SQLite काम करता है, लेकिन यदि आप डेटा को सुरक्षित रखना चाहते हैं तो Postgres सही विकल्प है। इसका कारण यह है कि visit rows की संख्या बढ़ती रहती है और Postgres indexes तथा 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:दोनों published ports 127.0.0.1 पर bind होते हैं, इसलिए जब तक अगले section में reverse proxy सेट नहीं हो जाता, तब तक इंटरनेट से कुछ भी एक्सेस नहीं किया जा सकेगा। Docker host firewall से पहले अपने स्वयं के forwarding rules लिखता है, जिसका अर्थ है कि एक साधारण 8080:8080 line उस app को भी expose कर देगी जिसका firewall बंद दिखता है। Loopback address पर bind करने से यह समस्या नहीं होती। यही pattern उस हर app पर लागू होता है जिसे आप इस तरह चलाते हैं, और इसका अधिक विवरण Docker Compose on a VPS के लिए गाइड में दिया गया है।
Database password compose file के बगल में स्थित एक .env file से आता है, इसलिए यह कभी भी 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इसे start करें और API के चालू होने की प्रतीक्षा करें।
cd /opt/shlink
sudo docker compose up -d
sudo docker compose logs -f shlinkपहली बार start करने पर database migrations चलती हैं, इसलिए इसमें बाद की बार की तुलना में अधिक समय लगता है। जब यह स्थिर हो जाए, तो जाँचें कि service स्थानीय रूप से उत्तर दे रही है या नहीं।
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080/rest/health200 का अर्थ है कि API सक्रिय है और database connection काम कर रहा है। 503 का अर्थ है कि Shlink चल रहा है लेकिन उसका database check विफल हो गया है। Health endpoint किसी भी database error के लिए 503 उत्तर देता है, कभी भी 500 नहीं। यदि curl इसके बजाय 000 प्रिंट करता है, तो port पर कोई उत्तर नहीं मिल रहा है: container अपने start-up checks के दौरान रुक गया है और Docker उसे restart कर रहा है, इसलिए ऊपर दिए गए logs को पढ़ें। किसी भी स्थिति में, इसका सामान्य कारण यह होता है कि .env में मौजूद DB_PASSWORD उस password से मेल नहीं खाता जिसके साथ Postgres बनाया गया था, क्योंकि Postgres image केवल तभी POSTGRES_PASSWORD को पढ़ती है जब वह एक खाली data directory को initialize करती है। बाद में password बदलने का तब तक कोई प्रभाव नहीं पड़ता जब तक आप volume को हटाकर फिर से शुरू नहीं करते।
इसके सामने HTTPS terminate करें
Shlink पोर्ट 8080 पर plain HTTP सर्व करता है। TLS का स्थान reverse proxy में होता है, और सबसे महत्वपूर्ण सेटिंग मूल host name को आगे पास करना है। Shlink यह तय करता है कि कोई short code किस domain का है, इसके लिए वह Host header को पढ़ता है। इसलिए, यदि कोई proxy इसे rewrite करता है, तो मौजूद links पर भी 404 response मिलता है और visit stats गलत domain से जुड़ जाते हैं।
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;
}
}इसके बाद certificate जारी करें। renewal timer सहित पूरी प्रक्रिया Ubuntu 24.04 पर nginx के लिए Certbot गाइड में दी गई है।
sudo certbot --nginx -d s.example.comcompose file में IS_HTTPS_ENABLED: "true" वह सेटिंग है जो Shlink को उसके द्वारा return किए गए short URLs में https:// प्रिंट करने के लिए कहती है। यह अपने आप TLS enable नहीं करती। इसे HTTPS proxy के पीछे false छोड़ दें, अन्यथा API द्वारा दी गई हर link एक http:// link होगी जो बाद में redirect होती है। इससे एक अतिरिक्त round trip लगता है और web client में यह गलत दिखता है।
API key बनाएँ
API key के बिना कोई भी API से संवाद नहीं कर सकता। container के अंदर CLI के माध्यम से एक key generate करें।
sudo docker compose exec shlink shlink api-key:generate --name "web client"यह command key को केवल एक बार print करती है। इसे अभी copy कर लें, क्योंकि यह hashed रूप में store होती है और इसे दोबारा नहीं दिखाया जा सकता। shlink api-key:list प्रत्येक key का नाम और उसकी स्थिति (enabled है या नहीं) दिखाता है, न कि स्वयं key। shlink api-key:disable और नाम का उपयोग करके किसी key को revoke करें।
प्रत्येक REST call में key को X-Api-Key header में भेजा जाता है।
curl -H "X-Api-Key: YOUR_KEY" https://s.example.com/rest/v3/short-urlsयदि JSON object में shortUrls key मौजूद है, तो इसका अर्थ है कि key सही ढंग से काम कर रही है। यदि 401 का type मान https://shlink.io/api/error/invalid-api-key है, और उसका title Invalid API key है, तो इसका अर्थ है कि key गलत है, disabled है, या उसकी expiry date निकल चुकी है।
कमांड लाइन से शॉर्ट लिंक बनाना
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) प्रत्येक डोमेन के लिए अद्वितीय होते हैं, इसलिए पहले से उपयोग किए गए स्लग पर दूसरा प्रयास विफल हो जाता है, न कि चुपचाप पहले लिंक को ओवरराइट करता है। --tag को दोहराया जा सकता है, और टैग्स (tags) का उपयोग उन लिंक्स को समूहित करने के लिए किया जाता है जिनके संयुक्त आँकड़े आप बाद में देखना चाहते हैं।
मौजूदा लिंक्स की सूची देखें, फिर किसी एक लिंक का ट्रैफिक देखें।
sudo docker compose exec shlink shlink short-url:list
sudo docker compose exec shlink shlink short-url:visits docsshort-url:visits प्रति क्लिक एक पंक्ति प्रिंट करता है जिसमें तारीख, रेफरर (referrer) और यूजर एजेंट शामिल होते हैं। देश और शहर के कॉलम तब तक खाली रहते हैं जब तक आप 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 कोड वेब क्लाइंट से आते हैं, API से नहीं। Shlink 5 ने शॉर्ट URL में /qr-code जोड़ने वाली पुरानी ट्रिक को हटा दिया है, इसलिए वह एड्रेस अब कोई इमेज रिटर्न नहीं करता है। इसके बजाय, वेब क्लाइंट आपके ब्राउज़र में कोड ड्रा करता है, बिना Shlink को कोई रिक्वेस्ट भेजे। शॉर्ट URL लिस्ट में किसी भी लिंक पर QR कोड विकल्प खोलें, साइज, फॉर्मेट और मार्जिन सेट करें, और परिणाम डाउनलोड करें। यदि कोड छोटा प्रिंट होने या आंशिक रूप से ढके होने पर भी स्कैन हो, तो इसके लिए एरर करेक्शन लेवल बढ़ाएं। उसी डायलॉग में रंग और लोगो भी सेट किए जा सकते हैं।
इसे चालू रखें
एक shortener चुपचाप विफल हो जाता है। लिंक redirect करना बंद कर देते हैं और कोई आपको सूचित नहीं करता, क्योंकि लिंक पर क्लिक करने वाले व्यक्ति को लगता है कि लिंक मृत है। होम पेज के बजाय किसी वास्तविक short URL पर uptime check सेट करें, और किसी भी ऐसी चीज़ पर alert भेजें जो redirect न हो। एक self-hosted Uptime Kuma instance यह काम अच्छी तरह से करता है, और यह एक विशिष्ट status code की निगरानी कर सकता है।
कंटेनर का नहीं, बल्कि database का बैकअप लें। एक कमांड इसे dump कर देती है।
sudo docker compose exec -T database pg_dump -U shlink shlink | gzip > shlink-$(date +%F).sql.gzवह फ़ाइल और आपकी compose फ़ाइल मिलकर पूरे service को एक नए सर्वर पर फिर से बना देती है। बॉक्स पर मौजूद हर app को उस जोड़ी के अपने संस्करण की आवश्यकता होती है, और photo library एक कठिन मामला है, क्योंकि PhotoPrism और Immich दोनों ही originals को डिस्क पर और database में rows के रूप में रखते हैं, इसलिए केवल dump लेने से accounts और settings तो वापस आ जाते हैं लेकिन एक भी फोटो नहीं। अपग्रेड sudo docker compose pull के बाद sudo docker compose up -d करने से होते हैं, और Shlink शुरू होने पर कोई भी नया migration चलाता है। pull करने से पहले dump ले लें, क्योंकि migration को वापस (roll back) नहीं किया जा सकता है।
FAQ
Reverse proxy जोड़ने के बाद मेरे short links 404 error क्यों दिखा रहे हैं?
Shlink short code का मिलान Host header में मौजूद domain से करता है। यदि proxy अपना नाम या internal address भेजता है, तो Shlink उस domain पर code ढूँढता है जहाँ कोई links नहीं हैं, इसलिए वह 404 error देता है। nginx location block में proxy_set_header Host $host; सेट करें और proxy को reload करें। container को restart किए बिना ही links तुरंत काम करने लगेंगे।
क्या मुझे Postgres की आवश्यकता है, या SQLite पर्याप्त है?
Shlink को आज़माने के लिए SQLite ठीक है और इसके लिए किसी दूसरे container की आवश्यकता नहीं है। महत्वपूर्ण links प्रकाशित करने से पहले Postgres पर आ जाएँ, क्योंकि हर click के साथ visit rows बढ़ती हैं और SQLite writes को serialize करता है। बाद में switch करने का अर्थ है अपने links को export और re-import करना, इसलिए शुरुआत में ही Postgres चुनना आपको उस migration से बचा लेता है।
क्या मैं वह API key रिकवर कर सकता हूँ जिसे मैं copy करना भूल गया था?
नहीं। Shlink key का hash store करता है, इसलिए api-key:list केवल नाम और status दिखाता है, value कभी नहीं। shlink api-key:generate के साथ एक नई key generate करें, उसे web client में paste करें, और फिर पुरानी key को shlink api-key:disable के साथ disable कर दें ताकि वह काम करना बंद कर दे।
मेरे visit stats में country columns खाली क्यों हैं?
Geolocation के लिए GeoLite2 database की आवश्यकता होती है, जिसे Shlink केवल तभी download करता है जब आप उसे GEOLITE_LICENSE_KEY प्रदान करते हैं। यह key MaxMind से मुफ्त मिलती है। इसे environment section में जोड़ें, container को recreate करें, और नई visits की location दिखने लगेगी। ऐसा करने से पहले दर्ज की गई visits तब तक खाली रहेंगी जब तक आप shlink visit:locate नहीं चलाते।
मैं Shlink को दूसरे server पर कैसे ले जाऊँ?
Domain को वही रखें और data को move करें। pg_dump के साथ database का dump लें, dump और compose file को नए server पर copy करें, stack को start करें, और फिर वास्तविक traffic आने से पहले खाली database में dump को restore करें। DNS record को सबसे अंत में बदलें। Short codes और उनका visit history सुरक्षित रहता है, क्योंकि सब कुछ database में ही होता है।