Jinsi ya kusakinisha Shlink URL shortener kwa Docker
Jifunze kuendesha Shlink kwenye VPS yako kwa kutumia Docker Compose. Mwongozo huu unashughulikia usanidi wa DNS, database ya Postgres, API keys, na uchanganuzi wa mibofyo ya viungo.
Unachojenga
URL shortener unayojiendeshea mwenyewe ni seva ndogo inayobadilisha kiungo kirefu kuwa kifupi unachokimiliki, na kuhesabu kila bofyo kwenye kiungo hicho. Shlink ndiyo chaguo bora: ni open source, inasambazwa kama Docker image, na inafanya kazi yote katika container moja pamoja na database. Mwongozo huu unaiweka kwenye VPS nyuma ya domain fupi halisi, ikiwa na HTTPS, API key, QR codes na takwimu za mibofyo.
Vipengele viwili hufanya iwe kama huduma ya kibiashara ya kufupisha viungo. Seva ya API hujibu maombi ya kuelekeza (redirects) na kuhifadhi data. Web client ni programu tuli (static app) tofauti inayowasiliana na API hiyo kutoka kwenye kivinjari chako. Unaweza kuendesha vyote viwili, au kuendesha API pekee na kuitumia kupitia command line.
Namba za matoleo hapa ni zile zilizokuwa za sasa kufikia Julai 2026: Shlink 5.1 na shlink-web-client 4.8.
Elekeza domain fupi kwenye seva kwanza
Domain ndiyo bidhaa yenyewe. s.example.com/abc123 ndiyo kiungo ambacho watu hukiona, kwa hivyo chagua jina fupi na uliamue kabla ya kusakinisha chochote. Shlink huhifadhi domain hiyo pamoja na kila short URL, na kuibadilisha baadaye kutafanya kila kiungo ulichokwishatoa kishindwe kufanya kazi.
Tengeneza DNS A record moja kwa ajili ya domain hiyo fupi, ikielekeza kwenye anwani ya IPv4 ya umma ya VPS yako. Ongeza pia AAAA record ikiwa seva ina IPv6. Kisha thibitisha kuwa inatatuliwa (resolves) kabla ya kuendelea.
dig +short s.example.com AMatokeo yanayopaswa kuonekana ni anwani ya seva yako. Ikiwa pato ni tupu, basi record hiyo haijasambaa bado, na kila hatua inayofuata itafeli kwa njia inayochanganya, kwa sababu cheti cha TLS (transport layer security) hakiwezi kutolewa kwa jina ambalo halitatuliwi.
Faili la compose
Shlink inahitaji database. SQLite inafaa kwa majaribio, lakini Postgres ndiyo chaguo sahihi kwa kitu chochote unachopanga kukihifadhi, kwa sababu safu za ziara (visit rows) hujilimbikiza na Postgres hushughulikia indexes na uandishi wa wakati mmoja (concurrent writes) vizuri zaidi. Weka hili kwenye /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:Ports zote zilizochapishwa hufungwa kwenye 127.0.0.1, kwa hivyo hakuna kinachoweza kufikiwa kutoka kwenye Internet hadi pale reverse proxy katika sehemu inayofuata itakapowekwa. Docker huandika sheria zake za usambazaji (forwarding rules) mbele ya firewall ya host, jambo linalomaanisha kuwa mstari wa 8080:8080 pekee ungeifanya app ionekane hata kwenye mashine ambayo firewall yake inaonekana imefungwa. Kufunga kwenye loopback address huepuka hilo. Mfumo huo huo hutumika kwa app yoyote unayoendesha kwa njia hii, na umefafanuliwa kwa kina zaidi katika mwongozo wa Docker Compose kwenye VPS.
Nenosiri la database linatoka kwenye faili la .env lililo karibu na faili la compose, kwa hivyo haliingii kamwe kwenye 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/.envIanzishe na ufuatilie API ikianza kufanya kazi.
cd /opt/shlink
sudo docker compose up -d
sudo docker compose logs -f shlinkUanzishaji wa kwanza huendesha migrations za database, kwa hivyo huchukua muda mrefu kuliko uanzishaji wa baadaye. Inapotulia, hakikisha huduma inajibu ndani ya mfumo (locally).
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080/rest/health200 inamaanisha API iko hai na muunganisho wa database unafanya kazi. 500 hapa karibu kila mara inahusu database: DB_PASSWORD katika .env hailingani na ile ambayo Postgres iliundwa nayo, kwa sababu image ya Postgres husoma POSTGRES_PASSWORD tu wakati inapoanzisha saraka ya data tupu (empty data directory). Kubadilisha nenosiri baadaye hakuna athari yoyote hadi utakapofuta volume na kuanza tena.
Sitisha HTTPS mbele yake
Shlink hutoa HTTP ya kawaida kwenye port 8080. TLS inapaswa kushughulikiwa na reverse proxy, na mpangilio mmoja muhimu ni kupitisha jina la host asilia. Shlink huamua domain ambayo short code inamilikiwa nayo kwa kusoma header ya Host, kwa hivyo proxy inayobadilisha header hiyo husababisha majibu ya 404 kwenye viungo vilivyopo, na takwimu za ziara kuunganishwa kwenye domain isiyo sahihi.
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;
}
}Kisha toa cheti. Mwongozo kamili, ikijumuisha kipima muda cha kusasisha (renewal timer), unapatikana katika mwongozo wa Certbot kwa ajili ya nginx kwenye Ubuntu 24.04.
sudo certbot --nginx -d s.example.comIS_HTTPS_ENABLED: "true" katika faili ya compose ndiyo inayofanya Shlink ichapishe https:// katika short URL inazorejesha. Hii haiwashi TLS yenyewe. Iache ikiwa false nyuma ya proxy ya HTTPS na kila kiungo ambacho API inarejesha kitakuwa kiungo cha http:// ambacho kitalazimika kuelekezwa upya (redirect), jambo linaloongeza muda wa mawasiliano na kuonekana vibaya kwenye web client.
Tengeneza API key
Hakuna kinachoweza kuwasiliana na API bila key. Tengeneza moja kupitia CLI ndani ya container.
sudo docker compose exec shlink shlink api-key:generate --name "web client"Amri hii huchapisha key mara moja tu. Nakili sasa, kwa sababu inahifadhiwa ikiwa imefanyiwa hashing na haiwezi kuonyeshwa tena. shlink api-key:list huonyesha majina na kama kila key imewezeshwa, lakini kamwe haionyeshi key yenyewe. Batilisha key moja kwa kutumia shlink api-key:disable na jina lake.
Kila ombi la REST hubeba key hiyo ndani ya header ya X-Api-Key.
curl -H "X-Api-Key: YOUR_KEY" https://s.example.com/rest/v3/short-urlsObject ya JSON yenye key ya shortUrls inamaanisha kuwa key inafanya kazi. 401 inayobeba INVALID_API_KEY inamaanisha kuwa key si sahihi, imezimwa, au imepita tarehe yake ya mwisho ya matumizi.
Tengeneza viungo vifupi kutoka kwa mstari wa amri
CLI ndiyo njia ya haraka zaidi ya kutengeneza viungo, na ndiyo inayofaa zaidi kwa hati (scripts).
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 hukupa kiungo kinachosomeka badala ya msimbo uliotengenezwa kiotomatiki. Slugs ni za kipekee kwa kila domain, kwa hivyo jaribio la pili la kutumia slug ambayo imeshatumika litafeli badala ya kufuta kiungo cha kwanza kimyakimya. --tag inaweza kurudiwa, na tags ndizo njia unayotumia kupanga viungo ambavyo utataka kuona takwimu zake kwa pamoja baadaye.
Orodhesha vilivyopo, kisha angalia trafiki ya kiungo kimoja.
sudo docker compose exec shlink shlink short-url:list
sudo docker compose exec shlink shlink short-url:visits docsshort-url:visits huchapisha safu moja kwa kila bofyo ikionyesha tarehe, referrer na user agent. Safu wima za nchi na mji hubaki tupu isipokuwa ukiweka GEOLITE_LICENSE_KEY environment variable, ambayo ni ufunguo wa bure wa MaxMind ambao Shlink hutumia kupakua database ya GeoLite2. Bila ufunguo huo, ziara bado hurekodiwa, hazijapewa tu eneo la kijiografia.
Mteja wa wavuti na QR codes
Mteja wa wavuti sasa yuko kwenye 127.0.0.1:8081 na anahitaji ingizo lake la proxy, au SSH tunnel ikiwa hutaki kuichapisha hadharani. Huomba URL ya seva na API key wakati wa kwanza kupakiwa. Ingiza https://s.example.com na ufunguo uliotengeneza. Mteja huhifadhi vyote viwili kwenye hifadhi ya kivinjari na huita API yako moja kwa moja, kwa hivyo hakuna data inayopita kwa mtu mwingine yeyote. Kutenganisha kiolesura na API ni muundo unaostahili kuzingatiwa, kwa sababu ndio uleule unaoruhusu Halcyon kuifanya maktaba ya Jellyfin ionekane kama duka la kukodisha la miaka ya 1990 bila kubadilisha seva ya media iliyo nyuma yake.
QR codes hazihitaji usanidi wowote. Ambatisha /qr-code kwenye URL yoyote fupi na API itarejesha picha hiyo.
https://s.example.com/docs/qr-code?size=500&format=svg&margin=20size ni upana katika pixels na hukubali kuanzia 50 hadi 1000, huku 300 ikiwa ni chaguo-msingi. format ni png au svg. margin ni nafasi tulivu inayozunguka code hiyo katika pixels, na picha iliyokamilika hupima ukubwa huo pamoja na mara mbili ya margin. Ongeza errorCorrection=Q kwa ajili ya code inayoweza kusomeka hata inapochapishwa kwa ukubwa mdogo au kufunikwa kwa sehemu.
Kuhakikisha huduma inaendelea kufanya kazi
Shortener inaweza kufeli kimyakimya. Viungo huacha kuelekeza watumiaji na hakuna anayekupa taarifa, kwa sababu mtumiaji anayebofya anadhani kiungo hicho kimekufa. Elekeza ukaguzi wa uptime kwenye URL fupi halisi badala ya ukurasa wa nyumbani, na uweke tahadhari kwa chochote ambacho si redirect. Instance ya Uptime Kuma unayojiendeshea mwenyewe hufanya hivi vizuri, na inaweza kufuatilia status code mahususi.
Hifadhi nakala ya database, siyo container. Amri moja inatosha kutoa dump hiyo.
sudo docker compose exec -T database pg_dump -U shlink shlink | gzip > shlink-$(date +%F).sql.gzFaili hilo pamoja na compose file yako hurejesha huduma nzima kwenye seva mpya. Kila app kwenye seva inahitaji toleo lake la jozi hiyo, na maktaba ya picha ni kesi ngumu, kwa sababu PhotoPrism na Immich zote huhifadhi picha asilia kwenye diski pamoja na safu kwenye database, kwa hivyo dump pekee hairejeshi chochote. Uboreshaji hufanyika kwa sudo docker compose pull ikifuatiwa na sudo docker compose up -d, na Shlink huendesha migrations yoyote mapya wakati wa kuanza. Chukua dump kabla ya kufanya pull, kwa sababu migration haiwezi kutenduliwa.
FAQ
Kwa nini viungo vyangu vifupi vinarudisha 404 baada ya kuongeza reverse proxy?
Shlink inalinganisha msimbo mfupi (short code) na kikoa kilichopo kwenye header ya Host. Proxy inayotuma jina lake yenyewe, au anwani ya ndani, huifanya Shlink kutafuta msimbo huo chini ya kikoa kisicho na viungo, hivyo inajibu 404. Weka proxy_set_header Host $host; kwenye block ya location ya nginx na uwashe upya proxy. Viungo huanza kufanya kazi mara moja, bila kuhitaji kuanzisha upya container.
Je, ninahitaji Postgres, au SQLite inatosha?
SQLite inafaa kwa kujaribia Shlink na haihitaji container ya pili. Hamia kwenye Postgres kabla ya kuchapisha viungo muhimu, kwa sababu safu za ziara (visit rows) huongezeka kwa kila bofyo na SQLite hufanya uandishi kwa mtiririko (serialises writes). Kubadili baadaye kunamaanisha kusafirisha na kuingiza tena viungo vyako, hivyo kuchagua Postgres mwanzoni hukuokoa na uhamiaji huo.
Je, ninaweza kupata tena API key niliyosahau kunakili?
Hapana. Shlink huhifadhi hash ya ufunguo, kwa hivyo api-key:list inaonyesha majina na hali lakini kamwe haionyeshi thamani yake. Tengeneza ufunguo mbadala kwa kutumia shlink api-key:generate, ubandike kwenye web client, kisha uzime ule wa zamani kwa kutumia shlink api-key:disable ili uache kufanya kazi.
Kwa nini safu za nchi hazina kitu kwenye takwimu zangu za ziara?
Geolocation inahitaji database ya GeoLite2, ambayo Shlink huipakua tu unapoiwekea GEOLITE_LICENSE_KEY. Ufunguo huo ni wa bure kutoka MaxMind. Uongeze kwenye sehemu ya environment, tengeneza upya container, na ziara mpya zitapatikana kijiografia. Ziara zilizorekodiwa kabla ya hapo zitabaki tupu hadi utakapokimbiza shlink visit:locate.
Ninawezaje kuhamisha Shlink kwenye seva nyingine?
Tunza kikoa na uhamishe data. Toa nakala ya database (dump) kwa kutumia pg_dump, nakili dump hiyo na faili la compose kwenye seva mpya, anzisha stack, kisha rudisha dump hiyo kwenye database tupu kabla ya trafiki halisi kufika. Badilisha rekodi ya DNS mwishoni. Misimbo mifupi na historia ya ziara zake hubaki salama, kwa sababu kila kitu kimo ndani ya database.